/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.x86.compiler; import java.util.HashMap; import java.util.Map; import org.jnode.annotation.PrivilegedActionPragma; import org.jnode.assembler.Label; import org.jnode.assembler.x86.X86Assembler; import org.jnode.assembler.x86.X86Constants; import org.jnode.assembler.x86.X86Register; import org.jnode.assembler.x86.X86Register.GPR; import org.jnode.assembler.x86.X86Register.GPR64; import org.jnode.vm.JvmType; import org.jnode.vm.classmgr.VmArray; import org.jnode.vm.classmgr.VmInstanceField; import org.jnode.vm.classmgr.VmIsolatedStaticsEntry; import org.jnode.vm.classmgr.VmMethod; import org.jnode.vm.classmgr.VmSharedStaticsEntry; import org.jnode.vm.classmgr.VmStaticField; import org.jnode.vm.classmgr.VmType; import org.jnode.vm.classmgr.VmTypeState; import org.jnode.vm.compiler.EntryPoints; import org.jnode.vm.facade.VmUtils; import org.jnode.vm.facade.VmWriteBarrier; import org.jnode.vm.scheduler.VmProcessor; import org.jnode.vm.x86.X86CpuID; import static org.jnode.vm.x86.compiler.X86CompilerConstants.BITS32; import static org.jnode.vm.x86.compiler.X86CompilerConstants.BITS64; import static org.jnode.vm.x86.compiler.X86CompilerConstants.INTSIZE; import static org.jnode.vm.x86.compiler.X86CompilerConstants.PROCESSOR64; /** * Helpers class used by the X86 compilers. * * @author epr * @author patrik_reali */ public class X86CompilerHelper { /** * Address size ax register (EAX/RAX) */ public final GPR AAX; /** * Address size bx register (EBX/RBX) */ public final GPR ABX; /** * Address size cx register (ECX/RCX) */ public final GPR ACX; /** * Address size dx register (EDX/RDX) */ public final GPR ADX; /** * The stack pointer (ESP/RSP) */ public final GPR SP; /** * The stack frame pointer (EBP/RBP) */ public final GPR BP; /** * The statics table pointer (EDI/RDI) */ public final GPR STATICS; /** * The size of an address (BITS32/BITS64) */ public final int ADDRSIZE; /** * The size of stack slot in bytes (4/8) */ public final int SLOTSIZE; private EntryPoints entryPoints; private VmMethod method; private String labelPrefix; private String instrLabelPrefix; private final boolean haveCMOV; private final Map<Integer, Label> addressLabels = new HashMap<Integer, Label>(); private final boolean debug = VmUtils.getVm().isDebugMode(); private final AbstractX86StackManager stackMgr; private X86Assembler os; private final Map<VmType<?>, Label> classInitLabels = new HashMap<VmType<?>, Label>(); /** * Create a new instance * * @param entryPoints */ @PrivilegedActionPragma public X86CompilerHelper(X86Assembler os, AbstractX86StackManager stackMgr, EntryPoints entryPoints, boolean isBootstrap) { this.os = os; if (os.isCode32()) { this.AAX = X86Register.EAX; this.ABX = X86Register.EBX; this.ACX = X86Register.ECX; this.ADX = X86Register.EDX; this.SP = X86Register.ESP; this.BP = X86Register.EBP; this.STATICS = X86CompilerConstants.STATICS32; this.ADDRSIZE = X86Constants.BITS32; this.SLOTSIZE = 4; } else { this.AAX = X86Register.RAX; this.ABX = X86Register.RBX; this.ACX = X86Register.RCX; this.ADX = X86Register.RDX; this.SP = X86Register.RSP; this.BP = X86Register.RBP; this.STATICS = X86CompilerConstants.STATICS64; this.ADDRSIZE = X86Constants.BITS64; this.SLOTSIZE = 8; } this.entryPoints = entryPoints; this.stackMgr = stackMgr; final X86CpuID cpuId = (X86CpuID) os.getCPUID(); haveCMOV = cpuId.hasFeature(X86CpuID.FEAT_CMOV); } public void reset(X86Assembler x86Assembler, EntryPoints entryPoints) { this.os = x86Assembler; this.entryPoints = entryPoints; } /** * Reset the state of this helper. */ public final void reset() { classInitLabels.clear(); } /** * Gets the method that is currently being compiled. * * @return method */ public final VmMethod getMethod() { return method; } /** * Sets the method that is currently being compiled. * * @param method */ public final void setMethod(VmMethod method) { this.method = method; setLabelPrefix(method.toString() + '_'); } /** * Sets the current label prefix. * * @param prefix */ public final void setLabelPrefix(String prefix) { this.labelPrefix = prefix; this.instrLabelPrefix = labelPrefix + "_bci_"; this.addressLabels.clear(); } public final String getLabelPrefix() { return labelPrefix; } /** */ public void startInlinedMethod(VmMethod inlinedMethod, Label curInstrLabel) { setLabelPrefix(curInstrLabel + "_" + inlinedMethod.getName() + '_'); } /** * Create a method relative label to a given bytecode address. * * @param address * @return The created label */ public final Label getInstrLabel(int address) { Label l = addressLabels.get(address); if (l == null) { l = new Label(instrLabelPrefix + address); addressLabels.put(address, l); } return l; } /** * Create a method relative label * * @param postFix * @return The created label */ public final Label genLabel(String postFix) { return new Label(labelPrefix + postFix); } /** * Write code to call the address found at the given index in the system * jumptable. * * @param index * @see X86JumpTable */ public final void writeJumpTableCALL(int index) { if (os.isCode64()) { index *= 2; } final int offset = (VmArray.DATA_OFFSET * SLOTSIZE) + (index << 2); os.writeCALL(STATICS, offset); } /** * Write code to jump to the address found at the given index in the system * jumptable. * * @param index * @see X86JumpTable */ public final void writeJumpTableJMP(int index) { if (os.isCode64()) { index *= 2; } final int offset = (VmArray.DATA_OFFSET * SLOTSIZE) + (index << 2); os.writeJMP(STATICS, offset); } /** * Emit code to push the returncode of the given method signature. * * @param signature */ public final void pushReturnValue(String signature) { final int returnType = JvmType.getReturnType(signature); assertCondition( signature.endsWith("V") == (returnType == JvmType.VOID), "Return type"); // System.out.println("Return type: " + returnType + "\t" + signature); switch (returnType) { case JvmType.VOID: // No return value break; case JvmType.DOUBLE: case JvmType.LONG: // Wide return value if (os.isCode32()) { stackMgr.writePUSH64(returnType, X86Register.EAX, X86Register.EDX); } else { stackMgr.writePUSH64(returnType, X86Register.RAX); } break; case JvmType.REFERENCE: stackMgr.writePUSH(returnType, AAX); break; default: // int/float return value stackMgr.writePUSH(returnType, X86Register.EAX); } } /** * Emit code to invoke a java method * * @param method */ public final void invokeJavaMethod(VmMethod method) { final int offset = getSharedStaticsOffset(method); os.writeCALL(STATICS, offset); pushReturnValue(method.getSignature()); } /** * Insert a yieldpoint into the code */ public final void writeYieldPoint(Object curInstrLabel) { if (!method.isUninterruptible()) { final Label doneLabel = new Label(curInstrLabel + "noYP"); final Label ypLabel = new Label(curInstrLabel + "$$yp"); final int offset = entryPoints.getVmThreadSwitchIndicatorOffset(); final int flag = VmProcessor.TSI_SWITCH_REQUESTED; if (os.isCode32()) { os.writePrefix(X86Constants.FS_PREFIX); os.writeCMP_MEM(BITS32, offset, flag); } else { os.writeCMP_Const(BITS32, PROCESSOR64, offset, flag); } // Jump to the yieldpoint interrupt, when flags are set // We do NOT predict this to happen (in most cases), // so we optimize for that (wrt. branch prediction) os.writeJCC(ypLabel, X86Constants.JE); // Jump over INT is most cases os.writeJMP(doneLabel); // Trigger yieldpoint os.setObjectRef(ypLabel); os.writeINT(X86CompilerConstants.YIELDPOINT_INTNO); // Done os.setObjectRef(doneLabel); } } /** * Write class initialization code * * @param method the method reference * @return true if code was written, false otherwise */ public final boolean writeClassInitialize(VmMethod method) { // Only for static methods (non <clinit>) if (method.isStatic() && !method.isInitializer()) { // Only when class is not initialize final VmType<?> cls = method.getDeclaringClass(); if (!cls.isAlwaysInitialized()) { final GPR aax = this.AAX; final Label label = genLabel("$$class_init"); // Save eax os.writePUSH(aax); // Get class into aax if (os.isCode32()) { writeGetStaticsEntry(label, aax, cls); } else { writeGetStaticsEntry64(label, (GPR64) aax, (VmSharedStaticsEntry) cls); } // Write code to initialize writeClassInitialize(label, aax, aax, cls); // Restore eax os.writePOP(aax); return true; } } return false; } /** * Emit code to test the initialized state of a class and if required, call * the class initializer. * * @param curInstrLabel * @param classReg * @param tmpReg A temporary reference type register. This may be the same as * classReg, but this register is not preserved. * @param cls */ public final void writeClassInitialize(Label curInstrLabel, GPR classReg, GPR tmpReg, VmType<?> cls) { if (!cls.isAlwaysInitialized()) { // Create jump labels final Label testIsolated = new Label(curInstrLabel + "$$testiso_cinit"); final Label doInit = new Label(curInstrLabel + "$$do_cinit_ex"); final Label done = new Label(curInstrLabel + "$$done_cinit_ex"); // Test declaringClass.modifiers (mostly true) os.writeTEST(BITS32, classReg, entryPoints.getVmTypeState() .getOffset(), VmTypeState.ST_ALWAYS_INITIALIZED); if (!cls.isSharedStatics()) { // Jump when not initialized to isolated state test // Branch predication expects this forward jump NOT // to be taken. os.writeJCC(testIsolated, X86Constants.JZ); // We don't have to initialize, so jump over the init-code. os.writeJMP(done); // Test isolated class state os.setObjectRef(testIsolated); writeLoadIsolatedStatics(curInstrLabel, "$$ld_is_stat", tmpReg); final int offset = getIsolatedStaticsOffset(cls); os.writeTEST(BITS32, tmpReg, offset, VmTypeState.IST_INITIALIZED); } // Jump when not initialized to doInit. // Branch predication expects this forward jump NOT // to be taken. os.writeJCC(doInit, X86Constants.JZ); // We don't have to initialize, so jump over the init-code. os.writeJMP(done); // Start initialize code os.setObjectRef(doInit); // Get label for class initialize code Label initializer = classInitLabels.get(cls); if (initializer == null) { // create one initializer = genLabel("$$init_" + cls.getName()); classInitLabels.put(cls, initializer); } // Setup call to class initializer code os.writeCALL(initializer); os.writeJMP(done); // Set the done label os.setObjectRef(done); } } /** * Write the class initializer code. */ public final void writeClassInitializers() { for (Map.Entry<VmType<?>, Label> entry : classInitLabels.entrySet()) { final Label label = entry.getValue(); // Set label os.setObjectRef(label); // Save registers if (os.isCode32()) { os.writePUSHA(); } else { os.writePUSH(X86Register.RAX); os.writePUSH(X86Register.RBX); os.writePUSH(X86Register.RCX); os.writePUSH(X86Register.RDX); os.writePUSH(X86Register.RSI); os.writePUSH(X86Register.R8); os.writePUSH(X86Register.R9); os.writePUSH(X86Register.R10); os.writePUSH(X86Register.R11); // R12 contains processor and is preserved os.writePUSH(X86Register.R13); os.writePUSH(X86Register.R14); os.writePUSH(X86Register.R15); } // Load cls if (os.isCode32()) { writeGetStaticsEntry(label, AAX, entry.getKey()); } else { writeGetStaticsEntry64(label, (GPR64) AAX, (VmSharedStaticsEntry) entry.getKey()); } // Call cls.initialize os.writePUSH(AAX); // cls invokeJavaMethod(entryPoints.getVmTypeInitialize()); if (os.isCode32()) { os.writePOPA(); } else { os.writePOP(X86Register.R15); os.writePOP(X86Register.R14); os.writePOP(X86Register.R13); // R12 contains processor and is preserved os.writePOP(X86Register.R11); os.writePOP(X86Register.R10); os.writePOP(X86Register.R9); os.writePOP(X86Register.R8); os.writePOP(X86Register.RSI); os.writePOP(X86Register.RDX); os.writePOP(X86Register.RCX); os.writePOP(X86Register.RBX); os.writePOP(X86Register.RAX); } // Return os.writeRET(); } } /** * Write stack overflow test code. * * @param method */ public final void writeStackOverflowTest(VmMethod method) { // cmp esp,STACKEND // jg vm_invoke_testStackOverflowDone // vm_invoke_testStackOverflow: // int 0x31 // vm_invoke_testStackOverflowDone: final int offset = entryPoints.getVmProcessorStackEnd().getOffset(); final Label doneLabel = new Label(labelPrefix + "$$stackof_done"); final Label intLabel = new Label(labelPrefix + "$$stovf"); if (os.isCode32()) { os.writePrefix(X86Constants.FS_PREFIX); os.writeCMP_MEM(X86Register.ESP, offset); } else { os.writeCMP(X86Register.RSP, PROCESSOR64, offset); } // We expect no stack overflow, so optimize jumps for static // branch prediction. os.writeJCC(intLabel, X86Constants.JNG); os.writeJMP(doneLabel); os.setObjectRef(intLabel); os.writeINT(0x31); os.setObjectRef(doneLabel); } /** * Write staticTable load code. After the code (generated by this method) is * executed, the STATICS register contains the reference to the statics * table. */ public final void writeLoadSTATICS(Label curInstrLabel, String labelPrefix, boolean isTestOnly) { final int offset = entryPoints.getVmProcessorSharedStaticsTable() .getOffset(); if (isTestOnly) { if (debug) { final Label ok = new Label(curInstrLabel + labelPrefix + "_" + (os.getLength() % 256) + "$$ediok"); if (os.isCode32()) { os.writePrefix(X86Constants.FS_PREFIX); os.writeCMP_MEM(this.STATICS, offset); } else { os.writeCMP(this.STATICS, PROCESSOR64, offset); } os.writeJCC(ok, X86Constants.JE); os.writeINT(0x88); os.setObjectRef(ok); } } else { if (os.isCode32()) { os.writeXOR(this.STATICS, this.STATICS); os.writePrefix(X86Constants.FS_PREFIX); os.writeMOV(INTSIZE, this.STATICS, this.STATICS, offset); } else { os.writeMOV(BITS64, this.STATICS, PROCESSOR64, offset); } } } /** * Write isolatedStaticTable load code. After the code (generated by this * method) is executed, the given destination register contains the * reference to the isolated statics table of the current isolate. */ public final void writeLoadIsolatedStatics(Label curInstrLabel, String labelPrefix, GPR dst) { final int offset = entryPoints.getVmProcessorIsolatedStaticsTable() .getOffset(); if (os.isCode32()) { VmUtils.getVm().getCounter("### load " + dst.getName()).inc(); // os.writeXOR(dst, dst); os.writePrefix(X86Constants.FS_PREFIX); // os.writeMOV(INTSIZE, dst, dst, offset); os.writeMOV(dst, offset); } else { os.writeMOV(BITS64, dst, PROCESSOR64, offset); } } /** * Is class initialization code needed for the given method. * * @param method * @return true if class init code is needed, false otherwise. */ public static boolean isClassInitializeNeeded(VmMethod method) { // Only for static methods (non <clinit>) if (method.isStatic() && !method.isInitializer()) { // Only when class is not initialize final VmType<?> cls = method.getDeclaringClass(); if (!cls.isAlwaysInitialized()) { return true; } } return false; } /** * Do we need a write barrier * * @return True/false */ public final boolean needsWriteBarrier() { return (entryPoints.getWriteBarrier() != null); } /** * Write code to call the arrayStoreWriteBarrier. * * @param refReg * @param indexReg * @param valueReg */ public final void writeArrayStoreWriteBarrier(GPR refReg, GPR indexReg, GPR valueReg, GPR scratchReg) { final VmWriteBarrier wb = entryPoints.getWriteBarrier(); if (wb != null) { os.writeMOV_Const(scratchReg, wb); os.writePUSH(scratchReg); os.writePUSH(refReg); os.writePUSH(indexReg); os.writePUSH(valueReg); invokeJavaMethod(entryPoints.getArrayStoreWriteBarrier()); } } /** * Write code to call the putfieldWriteBarrier. * * @param field * @param refReg * @param valueReg */ public final void writePutfieldWriteBarrier(VmInstanceField field, GPR refReg, GPR valueReg, GPR scratchReg) { if (field.isObjectRef()) { final VmWriteBarrier wb = entryPoints.getWriteBarrier(); if (wb != null) { os.writeMOV_Const(scratchReg, wb); os.writePUSH(scratchReg); os.writePUSH(refReg); os.writePUSH(field.getOffset()); os.writePUSH(valueReg); invokeJavaMethod(entryPoints.getPutfieldWriteBarrier()); } } } /** * Write code to call the putstaticWriteBarrier. * * @param field * @param valueReg */ public final void writePutstaticWriteBarrier(VmStaticField field, GPR valueReg, GPR scratchReg) { if (VmUtils.verifyAssertions()) { VmUtils._assert(scratchReg.getSize() == this.ADDRSIZE, "scratchReg wrong size"); VmUtils._assert(valueReg.getSize() == this.ADDRSIZE, "valueReg wrong size"); } if (field.isObjectRef()) { final VmWriteBarrier wb = entryPoints.getWriteBarrier(); if (wb != null) { os.writeMOV_Const(scratchReg, wb); os.writePUSH(scratchReg); if (field.isShared()) { os.writePUSH(1); // shared = true os.writePUSH(field.getSharedStaticsIndex()); } else { os.writePUSH(0); // shared = false os.writePUSH(field.getIsolatedStaticsIndex()); } os.writePUSH(valueReg); invokeJavaMethod(entryPoints.getPutstaticWriteBarrier()); } } } /** * Is CMOVxx support bu the current cpu. * * @return Returns the haveCMOV. */ public final boolean haveCMOV() { return this.haveCMOV; } /** * Write code to load the given 32-bit shared statics table entry into the * given register. * * @param curInstrLabel * @param dst * @param entry */ public final void writeGetStaticsEntry(Label curInstrLabel, GPR dst, VmSharedStaticsEntry entry) { if (VmUtils.verifyAssertions()) { VmUtils._assert(dst.getSize() == BITS32, "dst wrong size"); } writeLoadSTATICS(curInstrLabel, "gs", true); os.writeMOV(INTSIZE, dst, this.STATICS, getSharedStaticsOffset(entry)); } /** * Write code to load the given 32-bit isolated statics table entry into the * given register. * * @param curInstrLabel * @param dst * @param entry * @param tmp A temporary REFERENCE register */ public final void writeGetStaticsEntry(Label curInstrLabel, GPR dst, VmIsolatedStaticsEntry entry, GPR tmp) { if (VmUtils.verifyAssertions()) { VmUtils._assert(dst.getSize() == BITS32, "dst wrong size"); } writeLoadIsolatedStatics(curInstrLabel, "gs", tmp); os.writeMOV(INTSIZE, dst, tmp, getIsolatedStaticsOffset(entry)); } /** * Write code to load the given statics table entry onto the FPU stack. * * @param curInstrLabel * @param entry * @param is32bit If true, a 32-bit load is performed, otherwise a 64-bit load. */ public final void writeGetStaticsEntryToFPU(Label curInstrLabel, VmSharedStaticsEntry entry, boolean is32bit) { writeLoadSTATICS(curInstrLabel, "gs", true); final int staticsIdx = getSharedStaticsOffset(entry); if (is32bit) { os.writeFLD32(this.STATICS, staticsIdx); } else { os.writeFLD64(this.STATICS, staticsIdx); } } /** * Write code to load the given statics table entry onto the FPU stack. * * @param curInstrLabel * @param entry * @param is32bit If true, a 32-bit load is performed, otherwise a 64-bit load. * @param tmp A temporary register of the REFERENCE kind */ public final void writeGetStaticsEntryToFPU(Label curInstrLabel, VmIsolatedStaticsEntry entry, boolean is32bit, GPR tmp) { writeLoadIsolatedStatics(curInstrLabel, "gs", tmp); final int staticsIdx = getIsolatedStaticsOffset(entry); if (is32bit) { os.writeFLD32(tmp, staticsIdx); } else { os.writeFLD64(tmp, staticsIdx); } } /** * Write code to push the given statics table entry to the stack * * @param curInstrLabel * @param entry */ /* Patrik, added to push without requiring allocation of a register */ public final void writePushStaticsEntry(Label curInstrLabel, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "gs", true); os.writePUSH(this.STATICS, getSharedStaticsOffset(entry)); } /** * Write code to load the given 64-bit shared statics table entry into the * given 32-bit registers. * * @param curInstrLabel * @param lsbDst * @param msbReg * @param entry */ public final void writeGetStaticsEntry64(Label curInstrLabel, GPR lsbDst, GPR msbReg, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "gs64", true); final int staticsOfs = getSharedStaticsOffset(entry); os.writeMOV(INTSIZE, msbReg, this.STATICS, staticsOfs + 4); // MSB os.writeMOV(INTSIZE, lsbDst, this.STATICS, staticsOfs + 0); // LSB } /** * Write code to load the given 64-bit isolated statics table entry into the * given 32-bit registers. * * @param curInstrLabel * @param lsbDst * @param msbReg * @param entry */ public final void writeGetStaticsEntry64(Label curInstrLabel, GPR lsbDst, GPR msbReg, VmIsolatedStaticsEntry entry) { writeLoadIsolatedStatics(curInstrLabel, "gs64", lsbDst); final int staticsOfs = getIsolatedStaticsOffset(entry); os.writeMOV(INTSIZE, msbReg, lsbDst, staticsOfs + 4); // MSB os.writeMOV(INTSIZE, lsbDst, lsbDst, staticsOfs + 0); // LSB } /** * Write code to load the given 64-bit shared statics table entry into the * given 64-bit register. * * @param curInstrLabel * @param dstReg * @param entry */ public final void writeGetStaticsEntry64(Label curInstrLabel, GPR64 dstReg, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "gs64", true); os .writeMOV(BITS64, dstReg, this.STATICS, getSharedStaticsOffset(entry)); } /** * Write code to load the given 64-bit shared statics table entry into the * given 64-bit register. * * @param curInstrLabel * @param dstReg * @param entry */ public final void writeGetStaticsEntry64(Label curInstrLabel, GPR64 dstReg, VmIsolatedStaticsEntry entry) { writeLoadIsolatedStatics(curInstrLabel, "gs64", dstReg); os.writeMOV(BITS64, dstReg, dstReg, getIsolatedStaticsOffset(entry)); } /** * Write code to store the given statics table entry into the given * register. * * @param curInstrLabel * @param src * @param entry */ public final void writePutStaticsEntry(Label curInstrLabel, GPR src, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "ps", true); os.writeMOV(INTSIZE, this.STATICS, getSharedStaticsOffset(entry), src); } /** * Write code to store the given isolated statics table entry into the given * register. * * @param curInstrLabel * @param src * @param entry */ public final void writePutStaticsEntry(Label curInstrLabel, GPR src, VmIsolatedStaticsEntry entry, GPR tmp) { writeLoadIsolatedStatics(curInstrLabel, "ps", tmp); os.writeMOV(INTSIZE, tmp, getIsolatedStaticsOffset(entry), src); } /** * Write code to store the given 64-bit shared statics table entry into the * given 32-bit registers. * * @param curInstrLabel * @param lsbSrc * @param msbSrc * @param entry */ public final void writePutStaticsEntry64(Label curInstrLabel, GPR lsbSrc, GPR msbSrc, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "ps64", true); final int staticsOfs = getSharedStaticsOffset(entry); os.writeMOV(BITS32, this.STATICS, staticsOfs + 4, msbSrc); // MSB os.writeMOV(BITS32, this.STATICS, staticsOfs + 0, lsbSrc); // LSB } /** * Write code to store the given 64-bit shared statics table entry into the * given 32-bit registers. * * @param curInstrLabel * @param lsbSrc * @param msbSrc * @param entry */ public final void writePutStaticsEntry64(Label curInstrLabel, GPR lsbSrc, GPR msbSrc, VmIsolatedStaticsEntry entry, GPR tmp) { writeLoadIsolatedStatics(curInstrLabel, "ps64", tmp); final int staticsOfs = getIsolatedStaticsOffset(entry); os.writeMOV(BITS32, tmp, staticsOfs + 4, msbSrc); // MSB os.writeMOV(BITS32, tmp, staticsOfs + 0, lsbSrc); // LSB } /** * Write code to store the given 64-bit shared statics table entry into the * given 64-bit register. * * @param curInstrLabel * @param srcReg * @param entry */ public final void writePutStaticsEntry64(Label curInstrLabel, GPR64 srcReg, VmSharedStaticsEntry entry) { writeLoadSTATICS(curInstrLabel, "ps64", true); os .writeMOV(BITS64, this.STATICS, getSharedStaticsOffset(entry), srcReg); } /** * Write code to store the given 64-bit isolated statics table entry into * the given 64-bit register. * * @param curInstrLabel * @param srcReg * @param entry */ public final void writePutStaticsEntry64(Label curInstrLabel, GPR64 srcReg, VmIsolatedStaticsEntry entry, GPR tmp) { writeLoadIsolatedStatics(curInstrLabel, "ps64", tmp); os.writeMOV(BITS64, tmp, getIsolatedStaticsOffset(entry), srcReg); } /** * Gets the offset from the beginning of the shared statics table * (this.STATICS) to the given entry. * * @param entry * @return The byte offset from this.STATICS to the entry. */ public final int getSharedStaticsOffset(VmSharedStaticsEntry entry) { if (os.isCode32()) { return (VmArray.DATA_OFFSET * 4) + (entry.getSharedStaticsIndex() << 2); } else { return (VmArray.DATA_OFFSET * 8) + (entry.getSharedStaticsIndex() << 2); } } /** * Gets the offset from the beginning of the isolated statics table to the * given entry. * * @param entry * @return The byte offset from the isolated statics table to the entry. */ public final int getIsolatedStaticsOffset(VmIsolatedStaticsEntry entry) { if (os.isCode32()) { return (VmArray.DATA_OFFSET * 4) + (entry.getIsolatedStaticsIndex() << 2); } else { return (VmArray.DATA_OFFSET * 8) + (entry.getIsolatedStaticsIndex() << 2); } } public static void assertCondition(boolean condition, String msg) { if (!condition) { throw new InternalError("Assertion failed: " + msg); } } }