Path: blob/master/runtime/compiler/ilgen/J9IlGeneratorMethodDetails.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "env/FrontEnd.hpp"23#include "env/KnownObjectTable.hpp"24#include "compile/Compilation.hpp"25#include "compile/InlineBlock.hpp"26#include "compile/Method.hpp"27#include "compile/ResolvedMethod.hpp"28#include "env/CompilerEnv.hpp"29#include "env/IO.hpp"30#include "env/jittypes.h"31#include "env/VMAccessCriticalSection.hpp"32#include "il/TreeTop.hpp"33#include "il/TreeTop_inlines.hpp"34#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"35#include "ilgen/J9ByteCodeIlGenerator.hpp"36#include "env/VMJ9.h"37383940namespace J941{4243TR::IlGeneratorMethodDetails *44IlGeneratorMethodDetails::clone(TR::IlGeneratorMethodDetails &storage, const TR::IlGeneratorMethodDetails & other)45{46// The if nest below covers every concrete subclass of IlGeneratorMethodDetails.47// If other is not one of these classes, then it will assert.4849if (other.isOrdinaryMethod())50return new (&storage) TR::IlGeneratorMethodDetails(static_cast<const TR::IlGeneratorMethodDetails &>(other));51else if (other.isJitDumpMethod())52return new (&storage) JitDumpMethodDetails(static_cast<const JitDumpMethodDetails &>(other));53else if (other.isNewInstanceThunk())54return new (&storage) NewInstanceThunkDetails(static_cast<const NewInstanceThunkDetails &>(other));55else if (other.isMethodInProgress())56return new (&storage) MethodInProgressDetails(static_cast<const MethodInProgressDetails &>(other));57else if (other.isMethodHandleThunk())58{59if (static_cast<const MethodHandleThunkDetails &>(other).isShareable())60return new (&storage) ShareableInvokeExactThunkDetails(static_cast<const ShareableInvokeExactThunkDetails &>(other));61else if (static_cast<const MethodHandleThunkDetails &>(other).isCustom())62return new (&storage) CustomInvokeExactThunkDetails(static_cast<const CustomInvokeExactThunkDetails &>(other));63}6465TR_ASSERT(0, "Unexpected IlGeneratorMethodDetails object\n");66return NULL; // error case67}686970#if defined(J9VM_OPT_JITSERVER)71TR::IlGeneratorMethodDetails *72IlGeneratorMethodDetails::clone(TR::IlGeneratorMethodDetails &storage, const TR::IlGeneratorMethodDetails & other, const IlGeneratorMethodDetailsType type)73{74// The if nest below covers every concrete subclass of IlGeneratorMethodDetails.75// If other is not one of these classes, then it will assert.7677if (type & ORDINARY_METHOD)78return new (&storage) TR::IlGeneratorMethodDetails(static_cast<const TR::IlGeneratorMethodDetails &>(other));79else if (type & DUMP_METHOD)80return new (&storage) JitDumpMethodDetails(static_cast<const JitDumpMethodDetails &>(other));81else if (type & NEW_INSTANCE_THUNK)82return new (&storage) NewInstanceThunkDetails(static_cast<const NewInstanceThunkDetails &>(other));83else if (type & METHOD_IN_PROGRESS)84return new (&storage) MethodInProgressDetails(static_cast<const MethodInProgressDetails &>(other));85else if (type & METHOD_HANDLE_THUNK)86{87if (type & SHAREABLE_THUNK)88return new (&storage) ShareableInvokeExactThunkDetails(static_cast<const ShareableInvokeExactThunkDetails &>(other));89else if (type & CUSTOM_THUNK)90return new (&storage) CustomInvokeExactThunkDetails(static_cast<const CustomInvokeExactThunkDetails &>(other));91}9293TR_ASSERT(0, "Unexpected IlGeneratorMethodDetails object\n");94return NULL; // error case95}96#endif /* defined(J9VM_OPT_JITSERVER) */979899IlGeneratorMethodDetails::IlGeneratorMethodDetails(const TR::IlGeneratorMethodDetails & other) :100_method(other.getMethod())101{102}103104105IlGeneratorMethodDetails::IlGeneratorMethodDetails(TR_ResolvedMethod *method)106{107_method = (J9Method *)(method->getPersistentIdentifier());108}109110const J9ROMClass *111IlGeneratorMethodDetails::getRomClass() const112{113return J9_CLASS_FROM_METHOD(self()->getMethod())->romClass;114}115116const J9ROMMethod *117IlGeneratorMethodDetails::getRomMethod(TR_J9VMBase *fe)118{119return fe->getROMMethodFromRAMMethod(self()->getMethod());120}121122#if defined(J9VM_OPT_JITSERVER)123IlGeneratorMethodDetailsType124IlGeneratorMethodDetails::getType() const125{126int type = EMPTY;127if (self()->isOrdinaryMethod()) type |= ORDINARY_METHOD;128if (self()->isJitDumpMethod()) type |= DUMP_METHOD;129if (self()->isNewInstanceThunk()) type |= NEW_INSTANCE_THUNK;130if (self()->isMethodInProgress()) type |= METHOD_IN_PROGRESS;131if (self()->isArchetypeSpecimen()) type |= ARCHETYPE_SPECIMEN;132if (self()->isMethodHandleThunk())133{134type |= METHOD_HANDLE_THUNK;135if (static_cast<const MethodHandleThunkDetails *>(self())->isShareable())136type |= SHAREABLE_THUNK;137else if (static_cast<const MethodHandleThunkDetails *>(self())->isCustom())138type |= CUSTOM_THUNK;139}140return (IlGeneratorMethodDetailsType) type;141}142#endif /* defined(J9VM_OPT_JITSERVER) */143144145bool146IlGeneratorMethodDetails::sameAs(TR::IlGeneratorMethodDetails & other, TR_FrontEnd *fe)147{148return other.isOrdinaryMethod() && self()->sameMethod(other);149}150151152bool153IlGeneratorMethodDetails::sameMethod(TR::IlGeneratorMethodDetails & other)154{155return (other.getMethod() == self()->getMethod());156}157158159TR::IlGeneratorMethodDetails & IlGeneratorMethodDetails::create(160TR::IlGeneratorMethodDetails & target,161TR_ResolvedMethod *method)162{163164TR_ResolvedJ9Method * j9method = static_cast<TR_ResolvedJ9Method *>(method);165166if (j9method->isNewInstanceImplThunk())167return * new (&target) NewInstanceThunkDetails((J9Method *)j9method->getNonPersistentIdentifier(), (J9Class *)j9method->classOfMethod());168169else if (j9method->convertToMethod()->isArchetypeSpecimen())170{171if (j9method->getMethodHandleLocation())172return * new (&target) CustomInvokeExactThunkDetails((J9Method *)j9method->getNonPersistentIdentifier(), j9method->getMethodHandleLocation(), NULL);173else174return * new (&target) ArchetypeSpecimenDetails((J9Method *)j9method->getNonPersistentIdentifier());175}176177return * new (&target) TR::IlGeneratorMethodDetails((J9Method *)j9method->getNonPersistentIdentifier());178179}180181182TR_IlGenerator *183IlGeneratorMethodDetails::getIlGenerator(TR::ResolvedMethodSymbol *methodSymbol,184TR_FrontEnd * fe,185TR::Compilation *comp,186TR::SymbolReferenceTable *symRefTab,187bool forceClassLookahead,188TR_InlineBlocks *blocksToInline)189{190TR_ASSERT((J9Method *)methodSymbol->getResolvedMethod()->getNonPersistentIdentifier() == self()->getMethod(),191"getIlGenerator methodSymbol must match _method");192193return new (comp->trHeapMemory()) TR_J9ByteCodeIlGenerator(*(self()),194methodSymbol,195static_cast<TR_J9VMBase *>(fe),196comp,197symRefTab,198forceClassLookahead,199blocksToInline,200-1);201}202203204void205IlGeneratorMethodDetails::print(TR_FrontEnd *fe, TR::FILE *file)206{207if (file == NULL)208return;209210trfprintf(file, "%s(", self()->name());211self()->printDetails(fe, file);212trfprintf(file, ")");213}214215216void217IlGeneratorMethodDetails::printDetails(TR_FrontEnd *fe, TR::FILE *file)218{219trfprintf(file, "%s", fe->sampleSignature((TR_OpaqueMethodBlock *)(self()->getMethod())));220}221222J9Class *223IlGeneratorMethodDetails::getClass() const224{225return J9_CLASS_FROM_METHOD(self()->getMethod());226}227228229void230IlGeneratorMethodDetailsOverrideForReplay::changeMethod(231TR::IlGeneratorMethodDetails & details,232J9Method *newMethod)233{234details._method = newMethod;235}236237238void239NewInstanceThunkDetails::printDetails(TR_FrontEnd *fe, TR::FILE *file)240{241int32_t len;242TR_J9VMBase *fej9 = (TR_J9VMBase *)fe;243char *className = fej9->getClassNameChars((TR_OpaqueClassBlock *)getClass(), len);244trfprintf(file, "%.*s.newInstancePrototype(Ljava/lang/Class;)Ljava/lang/Object;", len, className);245}246247248void249MethodInProgressDetails::printDetails(TR_FrontEnd *fe, TR::FILE *file)250{251trfprintf(file, "DLT %d,%s", getByteCodeIndex(), fe->sampleSignature((TR_OpaqueMethodBlock *)getMethod()));252}253254255TR_IlGenerator *256ArchetypeSpecimenDetails::getIlGenerator(TR::ResolvedMethodSymbol *methodSymbol,257TR_FrontEnd * fe,258TR::Compilation *comp,259TR::SymbolReferenceTable *symRefTab,260bool forceClassLookahead,261TR_InlineBlocks *blocksToInline)262{263TR_ASSERT((J9Method *)methodSymbol->getResolvedMethod()->getNonPersistentIdentifier() == getMethod(),264"getIlGenerator methodSymbol must match _method");265266// Figure out the argPlaceholderSlot, which is the slot number of the last argument.267// Note that this creates and discards a TR_ResolvedMethod. TODO: A query268// on J9MethodBase could avoid this.269//270TR_ResolvedMethod *method = fe->createResolvedMethod(comp->trMemory(), (TR_OpaqueMethodBlock *)getMethod());271int32_t argPlaceholderSlot = method->numberOfParameterSlots()-1; // Assumes the arg placeholder is a 1-slot type272273return new (comp->trHeapMemory()) TR_J9ByteCodeIlGenerator(*this,274methodSymbol,275static_cast<TR_J9VMBase *>(fe),276comp,277symRefTab,278forceClassLookahead,279blocksToInline,280argPlaceholderSlot);281}282283284void285MethodHandleThunkDetails::printDetails(TR_FrontEnd *fe, TR::FILE *file)286{287#if 0288// annoying: knot can only be accessed from the compilation object which isn't always handy: wait for thread locals289TR::KnownObjectTable *knot = fe->getKnownObjectTable();290if (knot)291trfprintf(file, "obj%d,%s", knot->getOrCreateIndexAt(getHandleRef()), fe->sampleSignature((TR_OpaqueMethodBlock *)getMethod()));292else293#endif294trfprintf(file, "%p,%s", getHandleRef(), fe->sampleSignature((TR_OpaqueMethodBlock *)getMethod()));295}296297298bool299MethodHandleThunkDetails::isSameThunk(MethodHandleThunkDetails &other, TR_J9VMBase *fe)300{301TR_ASSERT(0, "MethodHandleThunk must be either shareable or custom");302return false;303}304305306bool307ShareableInvokeExactThunkDetails::isSameThunk(MethodHandleThunkDetails & other, TR_J9VMBase *fe)308{309if (!other.isShareable())310return false;311312uintptr_t thisThunkTuple, otherThunkTuple;313314// Consider: there is a race condition here. If there are two shareable thunks requested,315// and then we change the thunktuple of one of the handles, then this code will not detect316// the dup and we'll end up compiling two identical thunks.317//318{319TR::VMAccessCriticalSection isSameThunk(fe);320thisThunkTuple = fe->getReferenceField(*this->getHandleRef(), "thunks", "Ljava/lang/invoke/ThunkTuple;");321otherThunkTuple = fe->getReferenceField(*other.getHandleRef(), "thunks", "Ljava/lang/invoke/ThunkTuple;");322}323324// Same MethodHandle thunk request iff the two requests point to the same ThunkTuple325return thisThunkTuple == otherThunkTuple;326}327328329bool330CustomInvokeExactThunkDetails::isSameThunk(MethodHandleThunkDetails & other, TR_J9VMBase *fe)331{332if (!other.isCustom())333return false;334335bool bothHaveNullArg = false;336if (this->getArgRef() == NULL)337{338if (other.getArgRef() == NULL)339bothHaveNullArg = true;340else341return false;342}343else if (other.getArgRef() == NULL)344return false;345346bool sameHandle, sameArg;347348{349TR::VMAccessCriticalSection isSameThunk(fe);350sameHandle = (*this->getHandleRef()) == (*other.getHandleRef());351sameArg = bothHaveNullArg || ((*this->getArgRef()) == (*other.getArgRef()));352}353354// Same thunk request iff it's for the same handle with the same arg355return sameHandle && sameArg;356}357358}359360361