Path: blob/master/runtime/compiler/x/codegen/CheckFailureSnippet.cpp
6004 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 "x/codegen/CheckFailureSnippet.hpp"2324#include "codegen/CodeGenerator.hpp"25#include "codegen/Instruction.hpp"26#include "codegen/Relocation.hpp"27#include "codegen/SnippetGCMap.hpp"28#include "env/IO.hpp"29#include "env/jittypes.h"30#include "env/VMJ9.h"31#include "il/LabelSymbol.hpp"32#include "il/MethodSymbol.hpp"33#include "il/Node.hpp"34#include "il/Node_inlines.hpp"35#include "il/RegisterMappedSymbol.hpp"36#include "il/ResolvedMethodSymbol.hpp"37#include "il/StaticSymbol.hpp"38#include "il/Symbol.hpp"39#include "infra/SimpleRegex.hpp"40#include "runtime/CodeCacheManager.hpp"4142uint32_t TR::X86CheckFailureSnippet::getLength(int32_t estimatedSnippetStart)43{44uint32_t breakSize = 0;45if(_breakOnThrowType)46{47switch (getDestination()->getReferenceNumber())48{49case TR_nullCheck:50{51if (_breakOnThrowType&TR_BREAKONTHROW_NPE)52{53breakSize=1;54}55break;56}57case TR_arrayBoundsCheck:58{59if (_breakOnThrowType&TR_BREAKONTHROW_AIOB)60{61breakSize=1;62}63break;64}65}6667}68return (_requiresFPstackPop ? 11 : 9) + breakSize;69}7071uint8_t *TR::X86CheckFailureSnippet::emitSnippetBody()72{73uint8_t *buffer = cg()->getBinaryBufferCursor();74getSnippetLabel()->setCodeLocation(buffer);75buffer = emitCheckFailureSnippetBody(buffer);76return buffer;77}787980void81TR_Debug::print(TR::FILE *pOutFile, TR::X86CheckFailureSnippet * snippet)82{83if (pOutFile == NULL)84return;8586TR::SymbolReference *symRef = snippet->getDestination();87TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();88uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();89printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));9091if (snippet->getRequiredFPstackPop())92{93printPrefix(pOutFile, NULL, bufferPos, 2);94trfprintf(pOutFile, "fstp\tst(0)\t\t%s Discard top of FP stack",95commentString());96bufferPos += 2;97}9899printPrefix(pOutFile, NULL, bufferPos, 5);100trfprintf(pOutFile, "call\t%s \t\t%s Helper Address = " POINTER_PRINTF_FORMAT,101getName(symRef),102commentString(),103sym->getMethodAddress());104bufferPos += 5;105106printPrefix(pOutFile, NULL, bufferPos, 4);107trfprintf(pOutFile,108"%s \t%s%08x%s",109ddString(),110hexPrefixString(),111bufferPos - snippet->getCheckInstruction()->getBinaryEncoding(),112hexSuffixString());113}114115116uint8_t *TR::X86CheckFailureSnippet::emitCheckFailureSnippetBody(uint8_t *buffer)117{118TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());119120// add int3 instruction if breakOnThrow is set on NPE or AIOB121if(_breakOnThrowType)122{123switch (getDestination()->getReferenceNumber())124{125case TR_nullCheck:126{127if (_breakOnThrowType&TR_BREAKONTHROW_NPE)128{129*buffer++ = 0xcc;130}131break;132}133case TR_arrayBoundsCheck:134{135if (_breakOnThrowType&TR_BREAKONTHROW_AIOB)136{137*buffer++ = 0xcc;138}139break;140}141}142}143// Discard the top of the FP stack144//145if (_requiresFPstackPop)146{147*buffer++ = 0xdd; // FSTP st0,st0148*buffer++ = 0xd8;149}150151*buffer++ = 0xe8; // CallImm4152intptr_t destinationAddress = (intptr_t)getDestination()->getMethodAddress();153154if (NEEDS_TRAMPOLINE(destinationAddress, buffer+4, cg()))155{156destinationAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(getDestination()->getReferenceNumber(), (void *)buffer);157TR_ASSERT(IS_32BIT_RIP(destinationAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");158}159160*(int32_t *)buffer = (int32_t)(destinationAddress - (intptr_t)(buffer+4));161cg()->addExternalRelocation(new (cg()->trHeapMemory())162TR::ExternalRelocation(163buffer,164(uint8_t *)getDestination(),165TR_HelperAddress,166cg()),167__FILE__, __LINE__, getCheckInstruction()->getNode());168169buffer += 4;170uint8_t *checkSite = getCheckInstruction()->getBinaryEncoding();171*(uint32_t *)buffer = (uint32_t)(buffer - checkSite);172buffer += 4;173174// Up until this point we haven't marked the jump instruction getCheckInstruction() as being a gc safe175// point and we've marked the snippet as being a gc point. This call to registerStackMap is going add176// the gc map to the atlas and associate it with the jump instruction. The flags on the instruction177// and snippet are set back to reflect this.178//179// The real fix is to change the helper and snippet to not do the return code adjust, have the return180// address be the snippet and associate the gc map with the snippet.181//182gcMap().registerStackMap(checkSite, cg());183if (gcMap().getStackMap())184{185getCheckInstruction()->setNeedsGCMap();186gcMap().resetGCSafePoint();187resetNeedsExceptionTableEntry();188}189190return buffer;191}192193194void TR::X86CheckFailureSnippet::checkBreakOnThrowOption()195{196TR::SimpleRegex *r = cg()->comp()->getOptions()->getBreakOnThrow();197if (r && (TR::SimpleRegex::matchIgnoringLocale(r, "java/lang/NullPointerException")198|| TR::SimpleRegex::matchIgnoringLocale(r, "NPE", false)))199{200_breakOnThrowType|=TR_BREAKONTHROW_NPE;201}202if (r && (TR::SimpleRegex::matchIgnoringLocale(r, "java/lang/ArrayIndexOutOfBoundsException")203|| TR::SimpleRegex::matchIgnoringLocale(r, "AIOB", false)))204{205_breakOnThrowType|=TR_BREAKONTHROW_AIOB;206}207}208209210uint32_t TR::X86BoundCheckWithSpineCheckSnippet::getLength(int32_t estimatedSnippetStart)211{212return 0;213}214215uint8_t *TR::X86BoundCheckWithSpineCheckSnippet::emitSnippetBody()216{217uint8_t *buffer = cg()->getBinaryBufferCursor();218getSnippetLabel()->setCodeLocation(buffer);219return buffer;220}221222void223TR_Debug::print(TR::FILE *pOutFile, TR::X86BoundCheckWithSpineCheckSnippet *snippet)224{225if (pOutFile == NULL)226return;227228TR::SymbolReference *symRef = snippet->getDestination();229TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();230uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();231printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));232233trfprintf(pOutFile, "\t\t\t\t\t\t\t\t\t%s bound check with spine check snippet", commentString());234235}236237uint32_t TR::X86SpineCheckSnippet::getLength(int32_t estimatedSnippetStart)238{239return 0;240}241242uint8_t *TR::X86SpineCheckSnippet::emitSnippetBody()243{244uint8_t *buffer = cg()->getBinaryBufferCursor();245getSnippetLabel()->setCodeLocation(buffer);246return buffer;247}248249void250TR_Debug::print(TR::FILE *pOutFile, TR::X86SpineCheckSnippet *snippet)251{252if (pOutFile == NULL)253return;254255TR::SymbolReference *symRef = snippet->getDestination();256TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();257uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();258printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));259260trfprintf(pOutFile, "\t\t\t\t\t\t\t\t\t%s spine check snippet", commentString());261262}263264265uint32_t TR::X86CheckFailureSnippetWithResolve::getLength(int32_t estimatedSnippetStart)266{267268return getRequiredFPstackPop() ? 32 : 30;269}270271enum272{273resolveHasLiveXMMRs = 0x10000000,274longPushTag = 0x00800000,275dontPatchTag = 0x00400000276};277278uint8_t *TR::X86CheckFailureSnippetWithResolve::emitSnippetBody()279{280TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg()->fe());281uint8_t *buffer = cg()->getBinaryBufferCursor();282getSnippetLabel()->setCodeLocation(buffer);283284*buffer++ = 0x68; // push imm4 (return address is the throw of the nullpointer)285*(int32_t *)buffer = (int32_t) (intptr_t) (buffer + 24);286buffer += 4;287288int32_t cpIndexValue = getDataSymbolReference()->getCPIndex();289290*buffer++ = 0x68; // push imm4291292// Tag the value so that we can recognise the long case293//294if (getHasLiveXMMRs())295cpIndexValue |= resolveHasLiveXMMRs;296297*(int32_t *)buffer = (getNumLiveX87Registers() << 24) | dontPatchTag | longPushTag | cpIndexValue;298buffer += 4;299300301// Push address of literal pool302//303*buffer++ = 0x68; // push imm4304*(int32_t *)buffer = (int32_t) (intptr_t) getDataSymbolReference()->getOwningMethod(cg()->comp())->constantPool();305cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,306*(uint8_t **)buffer,307getCheckInstruction()->getNode() ? (uint8_t *)(uintptr_t)getCheckInstruction()->getNode()->getInlinedSiteIndex() : (uint8_t *)-1,308TR_ConstantPool, cg()),309__FILE__, __LINE__,310getCheckInstruction()->getNode());311buffer += 4;312313// Call the glue routine314//315*buffer++ = 0xe8; // call Imm4 glue routine316317TR::SymbolReference * glueSymRef = cg()->symRefTab()->findOrCreateRuntimeHelper(getHelper());318intptr_t glueAddress = (intptr_t)glueSymRef->getMethodAddress();319if (NEEDS_TRAMPOLINE(glueAddress, buffer+4, cg()))320{321glueAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(glueSymRef->getReferenceNumber(), (void *)buffer);322TR_ASSERT(IS_32BIT_RIP(glueAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");323}324*(int32_t *)buffer = (int32_t)(glueAddress - (intptr_t)(buffer+4));325cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,326(uint8_t *)glueSymRef,327TR_HelperAddress, cg()),328__FILE__,329__LINE__,330getCheckInstruction()->getNode());331332buffer += 4;333334// Discard the top of the FP stack335//336if (getRequiredFPstackPop())337{338*buffer++ = 0xdd; // FSTP st0,st0339*buffer++ = 0xd8;340}341342*buffer++ = 0xe8; // CallImm4343344intptr_t destinationAddress = (intptr_t)getDestination()->getMethodAddress();345if (NEEDS_TRAMPOLINE(destinationAddress, buffer+4, cg()))346{347destinationAddress = TR::CodeCacheManager::instance()->findHelperTrampoline(getDestination()->getReferenceNumber(), (void *)buffer);348TR_ASSERT(IS_32BIT_RIP(destinationAddress, buffer+4), "Local helper trampoline should be reachable directly.\n");349}350*(int32_t *)buffer = (int32_t)(destinationAddress - (intptr_t)(buffer+4));351cg()->addExternalRelocation(new (cg()->trHeapMemory()) TR::ExternalRelocation(buffer,352(uint8_t *)getDestination(),353TR_HelperAddress,354cg()),355__FILE__,356__LINE__,357getCheckInstruction()->getNode());358buffer += 4;359uint8_t *checkSite = getCheckInstruction()->getBinaryEncoding();360*(uint32_t *)buffer = (uint32_t)(buffer - checkSite);361buffer += 4;362363// Up until this point we haven't marked the jump instruction getCheckInstruction() as being a gc safe point and364// we've marked the snippet as being a gc point. This call to registerStackMap is going add the gc map to the atlas365// and associate it with the jump instruction. The flags on the instruction and snippet are set back to reflect this.366// The real fix is to change the helper and snippet to not do the return code adjust, have the return address be the367// snippet and associate the gc map with the snippet.368//369gcMap().registerStackMap(checkSite, cg());370if (gcMap().getStackMap())371{372getCheckInstruction()->setNeedsGCMap();373gcMap().resetGCSafePoint();374resetNeedsExceptionTableEntry();375}376377return buffer;378}379380381void382TR_Debug::print(TR::FILE *pOutFile, TR::X86CheckFailureSnippetWithResolve * snippet)383{384385enum386{387longPushTag = 0x00800000,388dontPatchTag = 0x00400000389};390391if (pOutFile == NULL)392return;393TR::SymbolReference *symRef = snippet->getDestination();394TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();395uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();396printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), getName(symRef));397398TR::SymbolReference *methodSymRef = snippet->getNode()->getSymbolReference();399TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();400int32_t cpIndexValue = ((TR::X86CheckFailureSnippetWithResolve *)snippet)->getDataSymbolReference()->getCPIndex();401int32_t size = 5;402403printPrefix(pOutFile, NULL, bufferPos, size);404trfprintf(pOutFile, "push\t" POINTER_PRINTF_FORMAT "\t\t%s push return address which is the throw bellow", bufferPos+24,405commentString());406bufferPos += 5;407408cpIndexValue |= dontPatchTag;409cpIndexValue |= longPushTag;410printPrefix(pOutFile, NULL, bufferPos, size);411trfprintf(pOutFile, "push\t" POINTER_PRINTF_FORMAT "\t\t%s push cpIndex", cpIndexValue,412commentString());413bufferPos += size;414415printPrefix(pOutFile, NULL, bufferPos, 5);416trfprintf(pOutFile,417"push\t" POINTER_PRINTF_FORMAT "\t\t%s push address of constant pool",418getOwningMethod(methodSymRef)->constantPool(),419commentString());420bufferPos += 5;421422printPrefix(pOutFile, NULL, bufferPos, 5);423424trfprintf(pOutFile, "call\tResolve Function For the Child to the NULLChk");425bufferPos += 5;426427if (snippet->getRequiredFPstackPop())428{429printPrefix(pOutFile, NULL, bufferPos, 2);430trfprintf(pOutFile, "fstp\tst(0)\t\t%s Discard top of FP stack",431commentString());432bufferPos += 2;433}434435printPrefix(pOutFile, NULL, bufferPos, 5);436trfprintf(pOutFile, "call\t%s \t\t%s Helper Address = " POINTER_PRINTF_FORMAT,437getName(symRef),438commentString(),439sym->getMethodAddress());440bufferPos += 5;441442printPrefix(pOutFile, NULL, bufferPos, 4);443trfprintf(pOutFile,444"%s \t%s%08x%s",445ddString(),446hexPrefixString(),447bufferPos - snippet->getCheckInstruction()->getBinaryEncoding(),448hexSuffixString());449}450451452