Path: blob/master/runtime/compiler/x/codegen/GuardedDevirtualSnippet.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/GuardedDevirtualSnippet.hpp"2324#include <stddef.h>25#include <stdint.h>26#include "codegen/CodeGenerator.hpp"27#include "env/FrontEnd.hpp"28#include "codegen/MemoryReference.hpp"29#include "codegen/RealRegister.hpp"30#include "codegen/RegisterConstants.hpp"31#include "codegen/Snippet.hpp"32#include "codegen/SnippetGCMap.hpp"33#include "compile/Compilation.hpp"34#include "env/CompilerEnv.hpp"35#include "env/IO.hpp"36#include "env/jittypes.h"37#include "il/LabelSymbol.hpp"38#include "il/Node.hpp"39#include "il/Symbol.hpp"40#include "il/SymbolReference.hpp"41#include "ras/Debug.hpp"42#include "x/codegen/RestartSnippet.hpp"4344namespace TR { class Block; }45namespace TR { class MethodSymbol; }46namespace TR { class Register; }4748TR::X86GuardedDevirtualSnippet::X86GuardedDevirtualSnippet(TR::CodeGenerator * cg,49TR::Node * node,50TR::LabelSymbol *restartlab,51TR::LabelSymbol *snippetlab,52int32_t vftoffset,53TR::Block *currentBlock,54TR::Register *classRegister)55: TR::X86RestartSnippet(cg, node, restartlab, snippetlab, true),56_vtableOffset(vftoffset),57_currentBlock(currentBlock),58_classObjectRegister(classRegister)59{60}616263TR::X86GuardedDevirtualSnippet *TR::X86GuardedDevirtualSnippet::getGuardedDevirtualSnippet()64{65return this;66}6768uint8_t *TR::X86GuardedDevirtualSnippet::emitSnippetBody()69{70uint8_t *buffer = cg()->getBinaryBufferCursor();71getSnippetLabel()->setCodeLocation(buffer);72TR::Compilation *comp = cg()->comp();7374if (_classObjectRegister == NULL)75{76if (comp->target().is64Bit() && !TR::Compiler->om.generateCompressedObjectHeaders())77*buffer++ = 0x48; // Rex prefix for 64-bit mov7879*(uint16_t *)buffer = 0x788b; // prepare for mov edi, [eax + class_offset]80buffer += 2;8182*(uint8_t *)buffer = (uint8_t) TR::Compiler->om.offsetOfObjectVftField(); // mov edi, [eax + class_offset]83buffer += 1;8485uintptr_t vftMask = TR::Compiler->om.maskOfObjectVftField();86if (~vftMask != 0)87{88if (comp->target().is64Bit() && !TR::Compiler->om.generateCompressedObjectHeaders())89*buffer++ = 0x48; // Rex prefix9091// and edi, vftMask92//93*(uint16_t *)buffer = 0xe781;94buffer += 2;95*(uint32_t *)buffer = vftMask;96buffer += 4;97}9899// two opcode bytes for call [edi + Imm] instruction100*(uint16_t *)buffer = 0x97ff;101buffer += 2;102}103else104{105if (comp->target().is64Bit())106{107uint8_t rex = toRealRegister(_classObjectRegister)->rexBits(TR::RealRegister::REX_B, false);108if (rex)109*buffer++ = rex;110}111112// two opcode bytes for call [reg + Imm] instruction, fix the low 3 bits (later)113// depending on what register the class object is in. For now, leave it zero114*(uint16_t *)buffer = 0x90ff;115buffer++;116117// use SIB-byte encoding if necessary118if (toRealRegister(_classObjectRegister)->needsSIB())119{120*buffer++ |= IA32SIBPresent;121*buffer = IA32SIBNoIndex;122}123124// now must get the class register and add its encoding to the low order 3 bits125// of the second opcode byte (0x90);126TR::RealRegister *classObjectRegister = toRealRegister(_classObjectRegister);127classObjectRegister->setRMRegisterFieldInModRM(buffer++);128}129130131// set the immediate offset field to be the vtable index132*(int32_t *)buffer = _vtableOffset; // call [reg + vtable offset]133buffer += 4;134135gcMap().registerStackMap(buffer, cg());136137return genRestartJump(buffer);138}139140141void142TR_Debug::print(TR::FILE *pOutFile, TR::X86GuardedDevirtualSnippet * snippet)143{144if (pOutFile == NULL)145return;146147uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation();148printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet), "out of line full virtual call sequence");149150char regLetter = (_comp->target().is64Bit())? 'r' : 'e';151152#if defined(TR_TARGET_64BIT)153TR::Node *callNode = snippet->getNode();154TR::SymbolReference *methodSymRef = snippet->getRealMethodSymbolReference();155if (!methodSymRef)156methodSymRef = callNode->getSymbolReference();157TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol();158// Show effect of loadArgumentsIfNecessary on devirtualized VMInternalNatives.159if (snippet->isLoadArgumentsNecessary(methodSymbol))160bufferPos = printArgumentFlush(pOutFile, callNode, false, bufferPos);161#endif162163if (!snippet->getClassObjectRegister())164{165int movSize = (_comp->target().is64Bit())? 3 : 2;166167printPrefix(pOutFile, NULL, bufferPos, movSize);168trfprintf(pOutFile, "mov \t%cdi, [%cax]\t\t%s Load Class Object",169regLetter, regLetter,170commentString());171bufferPos += movSize;172173printPrefix(pOutFile, NULL, bufferPos, 6);174trfprintf(pOutFile, "call\t[%cdi %d]\t\t%s call through vtable slot %d", regLetter, snippet->getVTableOffset(),175commentString(), -snippet->getVTableOffset() >> 2);176bufferPos += 6;177}178else179{180TR::RealRegister *classObjectRegister = toRealRegister(snippet->getClassObjectRegister());181#if defined(TR_TARGET_64BIT)182int callSize = 6;183if (toRealRegister(classObjectRegister)->rexBits(TR::RealRegister::REX_B, false))184callSize++;185if (toRealRegister(classObjectRegister)->needsSIB())186callSize++;187TR_RegisterSizes regSize = TR_DoubleWordReg;188#else189int callSize = 6;190TR_RegisterSizes regSize = TR_WordReg;191#endif192193printPrefix(pOutFile, NULL, bufferPos, callSize);194trfprintf(pOutFile,195"call\t[%s %d]\t\t%s call through vtable slot %d",196getName(classObjectRegister, regSize),197snippet->getVTableOffset(),198commentString(),199-snippet->getVTableOffset() >> 2);200bufferPos += callSize;201}202203printRestartJump(pOutFile, snippet, bufferPos);204}205206207uint32_t TR::X86GuardedDevirtualSnippet::getLength(int32_t estimatedSnippetStart)208{209TR::Compilation *comp = cg()->comp();210uint32_t fixedLength;211if (_classObjectRegister)212{213fixedLength = 6 + (toRealRegister(_classObjectRegister)->needsSIB()? 1 : 0);214if (comp->target().is64Bit())215{216uint8_t rex = toRealRegister(_classObjectRegister)->rexBits(TR::RealRegister::REX_B, false);217if (rex)218fixedLength++;219}220}221else222{223int32_t delta = 0;224delta = 1;225uintptr_t vftMask = TR::Compiler->om.maskOfObjectVftField();226if (~vftMask != 0)227delta += 6 + (comp->target().is64Bit()? 1 /* Rex */ : 0);228229fixedLength = 8 + delta + (comp->target().is64Bit()? 1 /* Rex */ : 0);230}231return fixedLength + estimateRestartJumpLength(estimatedSnippetStart + fixedLength);232}233234235236237238239240241242