Author: eliot Date: 2011-02-06 17:59:40 -0800 (Sun, 06 Feb 2011) New Revision: 2360 Modified: branches/Cog/platforms/Mac OS/vm/config.h branches/Cog/src/vm/cogit.c branches/Cog/src/vm/cogit.h Log: OSCogVM StackToRegisterMapping source as per VMMaker-oscog.47. Fix compilation of blocks with parameter initial nils. Fix compileInterpreterPrimitive to preserve caller-saved registers and run ceCheckProfileTick on the C stack. As part of pc mapping fixing add an annotateUse flag to sim stack entries so that the eliminated send in a folded constant still gets a pc map entry. Fix bad bug in frameless block entry; don't use initSimStackForFramelessMethod:! Add a target fixup for a conditional jump even if it is a jump on true or false since the simStack must still be valid for merges. Modified: branches/Cog/platforms/Mac OS/vm/config.h =================================================================== --- branches/Cog/platforms/Mac OS/vm/config.h 2011-02-06 19:53:20 UTC (rev 2359) +++ branches/Cog/platforms/Mac OS/vm/config.h 2011-02-07 01:59:40 UTC (rev 2360) @@ -172,7 +172,6 @@ /* other configured variables */ -#define SQ_VERSION "4.0-2334" #define VM_VERSION "4.0" #define VM_MODULE_PREFIX "" /* #undef VM_DLSYM_PREFIX */ Modified: branches/Cog/src/vm/cogit.c =================================================================== --- branches/Cog/src/vm/cogit.c 2011-02-06 19:53:20 UTC (rev 2359) +++ branches/Cog/src/vm/cogit.c 2011-02-07 01:59:40 UTC (rev 2360) @@ -1,9 +1,9 @@ /* Automatically generated by CCodeGenerator VMMaker-oscog.47 uuid: a4053f20-cb87-415d-aad3-3bb29b03724c from - SimpleStackBasedCogit VMMaker-oscog.47 uuid: a4053f20-cb87-415d-aad3-3bb29b03724c + StackToRegisterMappingCogit VMMaker-oscog.47 uuid: a4053f20-cb87-415d-aad3-3bb29b03724c */ -static char __buildInfo[] = "SimpleStackBasedCogit VMMaker-oscog.47 uuid: a4053f20-cb87-415d-aad3-3bb29b03724c " __DATE__ ; +static char __buildInfo[] = "StackToRegisterMappingCogit VMMaker-oscog.47 uuid: a4053f20-cb87-415d-aad3-3bb29b03724c " __DATE__ ; char *__cogitBuildInfo = __buildInfo; @@ -82,14 +82,6 @@ typedef struct { - AbstractInstruction *targetInstruction; - sqInt instructionIndex; - } BytecodeFixup; - -#define CogBytecodeFixup BytecodeFixup - - -typedef struct { sqInt annotation; AbstractInstruction *instruction; } InstructionAnnotation; @@ -106,7 +98,33 @@ #define CogPrimitiveDescriptor PrimitiveDescriptor +typedef struct { + AbstractInstruction *targetInstruction; + sqInt instructionIndex; + sqInt simStackPtr; + } BytecodeFixup; +#define CogSSBytecodeFixup BytecodeFixup + + +typedef struct { + char type; + char spilled; + char annotateUse; + sqInt registerr; + sqInt offset; + sqInt constant; + sqInt bcptr; + } CogSimStackEntry; + + +typedef struct { + sqInt isReceiverResultRegLive; + CogSimStackEntry *ssEntry; + } CogSSOptStatus; + + + /*** Constants ***/ #define AddCqR 83 #define AddCwR 90 @@ -123,6 +141,7 @@ #define ArithmeticShiftRightRR 70 #define BaseHeaderSize 4 #define BlockCreationBytecodeSize 4 +#define BytesPerOop 4 #define BytesPerWord 4 #define Call 9 #define CDQ 103 @@ -143,6 +162,7 @@ #define CmpCwR 89 #define CmpRdRd 96 #define CmpRR 75 +#define ConstZero 1 #define ConvertRRd 102 #define CPUID 106 #define Debug DEBUGVM @@ -177,6 +197,8 @@ #define FoxMFReceiver -12 #define FoxThisContext -8 #define FPReg -1 +#define GPRegMax -3 +#define GPRegMin -8 #define HasBytecodePC 5 #define HashBitsOffset 17 #define HashMaskUnshifted 0xFFF @@ -269,7 +291,7 @@ #define NegateR 68 #define Nop 8 #define NumSendTrampolines 4 -#define NumTrampolines 38 +#define NumTrampolines 50 #define OrCqR 86 #define OrRR 79 #define PopR 63 @@ -295,6 +317,10 @@ #define SizeMask 0xFC #define SPReg -2 #define SqrtRd 101 +#define SSBaseOffset 1 +#define SSConstant 2 +#define SSRegister 3 +#define SSSpill 4 #define StackPointerIndex 2 #define SubCqR 84 #define SubCwR 91 @@ -349,6 +375,7 @@ static AbstractInstruction * annotateobjRef(AbstractInstruction *abstractInstruction, sqInt anOop); static AbstractInstruction * annotatewith(AbstractInstruction *abstractInstruction, sqInt annotationFlag); static void assertSaneJumpTarget(void *jumpTarget); +static sqInt availableRegisterOrNil(void); static sqInt blockCodeSize(unsigned char byteZero, unsigned char byteOne, unsigned char byteTwo, unsigned char byteThree); static sqInt blockDispatchTargetsForperformarg(CogMethod *cogMethod, usqInt (*binaryFunction)(sqInt mcpc, sqInt arg), sqInt arg); sqInt bytecodePCForstartBcpcin(sqInt mcpc, sqInt startbcpc, CogBlockMethod *cogMethod); @@ -503,8 +530,13 @@ static sqInt doubleExtendedDoAnythingBytecode(void); static sqInt duplicateTopBytecode(void); static BytecodeFixup * ensureFixupAt(sqInt targetIndex); +static BytecodeFixup * ensureNonMergeFixupAt(sqInt targetIndex); +static void ensureReceiverResultRegContainsSelf(void); +static void ensureSpilledAtfrom(CogSimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister); void enterCogCodePopReceiver(void); void enterCogCodePopReceiverAndClassRegs(void); +void enterCogCodePopReceiverArg0Regs(void); +void enterCogCodePopReceiverArg1Arg0Regs(void); static sqInt extendedPushBytecode(void); static sqInt extendedStoreAndPopBytecode(void); static sqInt extendedStoreBytecode(void); @@ -534,8 +566,10 @@ static sqInt genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)); static sqInt genDoubleComparisoninvert(AbstractInstruction *(*jumpOpcodeGenerator)(void *), sqInt invertComparison); static AbstractInstruction * genDoubleFailIfZeroArgRcvrarg(sqInt rcvrReg, sqInt argReg); +static void (*genEnilopmartForandandcalled(sqInt regArg1, sqInt regArg2, sqInt regArg3, char *trampolineName))(void) ; static void (*genEnilopmartForandcalled(sqInt regArg1, sqInt regArg2, char *trampolineName))(void) ; static void (*genEnilopmartForcalled(sqInt regArg, char *trampolineName))(void) ; +static void (*genEnterPICEnilopmartNumArgs(sqInt numArgs))(void) ; static sqInt genExtendedSendBytecode(void); static sqInt genExtendedSuperBytecode(void); static sqInt genExternalizePointersForPrimitiveCall(void); @@ -592,13 +626,16 @@ static sqInt genLongJumpIfTrue(void); static sqInt genLongUnconditionalBackwardJump(void); static sqInt genLongUnconditionalForwardJump(void); -static sqInt genMethodAbortTrampoline(void); +static sqInt genMarshalledSendSupernumArgs(sqInt selector, sqInt numArgs); +static sqInt genMarshalledSendnumArgs(sqInt selector, sqInt numArgs); +static sqInt genMethodAbortTrampolineFor(sqInt numArgs); static void genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest); static sqInt genMustBeBooleanTrampolineForcalled(sqInt boolean, char *trampolineName); static sqInt genNonLocalReturnTrampoline(void); static sqInt genPassConstasArgument(AbstractInstruction * self_in_genPassConstasArgument, sqInt constant, sqInt zeroRelativeArgIndex); static sqInt genPassRegasArgument(AbstractInstruction * self_in_genPassRegasArgument, sqInt abstractRegister, sqInt zeroRelativeArgIndex); -static sqInt genPICAbortTrampoline(void); +static sqInt genPICAbortTrampolineFor(sqInt numArgs); +static sqInt genPICMissTrampolineFor(sqInt numArgs); static sqInt genPopStackBytecode(void); static sqInt genPrimitiveAdd(void); static sqInt genPrimitiveAsFloat(void); @@ -653,6 +690,9 @@ static sqInt genPushReceiverBytecode(void); static sqInt genPushReceiverVariableBytecode(void); static sqInt genPushReceiverVariable(sqInt index); +static void genPushRegisterArgs(void); +static void genPushRegisterArgsForAbortMissNumArgs(sqInt numArgs); +static void genPushRegisterArgsForNumArgs(sqInt numArgs); static sqInt genPushRemoteTempLongBytecode(void); static sqInt genPushTemporaryVariableBytecode(void); static sqInt genPushTemporaryVariable(sqInt index); @@ -678,19 +718,24 @@ static sqInt genSendLiteralSelector1ArgBytecode(void); static sqInt genSendLiteralSelector2ArgsBytecode(void); static sqInt genSendSupernumArgs(sqInt selector, sqInt numArgs); +static sqInt genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3); static sqInt genSendnumArgs(sqInt selector, sqInt numArgs); static sqInt genSetSmallIntegerTagsIn(sqInt scratchReg); static sqInt genShiftAwaySmallIntegerTagsInScratchReg(sqInt scratchReg); static sqInt genShortJumpIfFalse(void); static sqInt genShortUnconditionalJump(void); static sqInt genSmallIntegerComparison(sqInt jumpOpcode); +static sqInt genSpecialSelectorArithmetic(void); static sqInt genSpecialSelectorClass(void); +static sqInt genSpecialSelectorComparison(void); static sqInt genSpecialSelectorEqualsEquals(void); static sqInt genSpecialSelectorSend(void); +static sqInt genSSPushSlotreg(sqInt index, sqInt baseReg); static sqInt genStoreAndPopReceiverVariableBytecode(void); static sqInt genStoreAndPopRemoteTempLongBytecode(void); static sqInt genStoreAndPopTemporaryVariableBytecode(void); static sqInt genStoreCheckTrampoline(void); +static sqInt genStoreImmediateInSourceRegslotIndexdestReg(sqInt sourceReg, sqInt index, sqInt destReg); static sqInt genStorePopLiteralVariable(sqInt popBoolean, sqInt litVarIndex); static sqInt genStorePopMaybeContextReceiverVariable(sqInt popBoolean, sqInt slotIndex); static sqInt genStorePopReceiverVariable(sqInt popBoolean, sqInt slotIndex); @@ -702,8 +747,6 @@ static AbstractInstruction * genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc); static sqInt genTrampolineForcalled(void *aRoutine, char *aString); static sqInt genTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0); -static sqInt genTrampolineForcalledargarg(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1); -static sqInt genTrampolineForcalledargargargarg(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3); static sqInt genTrampolineForcalledargargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt resultReg); static sqInt genTrampolineForcalledargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt resultReg); static sqInt genTrampolineForcalledargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt resultReg); @@ -729,11 +772,15 @@ static BytecodeFixup * initializeFixupAt(sqInt targetIndex); static sqInt initialMethodUsageCount(void); static sqInt initialOpenPICUsageCount(void); +static void initSimStackForFramefulMethod(sqInt startpc); +static void initSimStackForFramelessBlock(sqInt startpc); +static void initSimStackForFramelessMethod(sqInt startpc); static sqInt inlineCacheTagAt(AbstractInstruction * self_in_inlineCacheTagAt, sqInt callSiteReturnAddress); static sqInt inlineCacheTagForInstance(sqInt oop); static sqInt inlineCacheTagIsYoung(sqInt cacheTag); static sqInt instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc); sqInt interpretOffset(void); +static sqInt inverseBranchFor(sqInt opcode); static sqInt isAFixup(AbstractInstruction * self_in_isAFixup, void *fixupOrAddress); static sqInt isAnInstruction(AbstractInstruction * self_in_isAnInstruction, void *addressOrInstruction); static sqInt isBigEndian(AbstractInstruction * self_in_isBigEndian); @@ -744,6 +791,7 @@ static sqInt isPCDependent(AbstractInstruction * self_in_isPCDependent); static sqInt isQuick(AbstractInstruction * self_in_isQuick, unsigned long operand); sqInt isSendReturnPC(sqInt retpc); +static sqInt isSmallIntegerTagNonZero(void); static AbstractInstruction * gJumpAboveOrEqual(void *jumpTarget); static AbstractInstruction * gJumpAbove(void *jumpTarget); static AbstractInstruction * gJumpBelow(void *jumpTarget); @@ -759,6 +807,7 @@ static AbstractInstruction * gJumpLong(void *jumpTarget); static AbstractInstruction * gJumpNegative(void *jumpTarget); static AbstractInstruction * gJumpNonZero(void *jumpTarget); +static AbstractInstruction * gJumpNoOverflow(void *jumpTarget); static AbstractInstruction * gJumpOverflow(void *jumpTarget); static AbstractInstruction * JumpRT(sqInt callTarget); static AbstractInstruction * gJumpR(sqInt reg); @@ -781,6 +830,7 @@ static sqInt leafCallStackPointerDelta(AbstractInstruction * self_in_leafCallStackPointerDelta); void linkSendAtintocheckedreceiver(sqInt callSiteReturnAddress, CogMethod *sendingMethod, CogMethod *targetMethod, sqInt checked, sqInt receiver); static sqInt literalBeforeFollowingAddress(AbstractInstruction * self_in_literalBeforeFollowingAddress, sqInt followingAddress); +static sqInt liveRegisters(void); static sqInt loadLiteralByteSize(AbstractInstruction * self_in_loadLiteralByteSize); static sqInt longBranchDistance(unsigned char byteZero, unsigned char byteOne); static sqInt longForwardBranchDistance(unsigned char byteZero, unsigned char byteOne); @@ -820,11 +870,14 @@ void markMethodAndReferents(CogBlockMethod *aCogMethod); static void markYoungObjectsIn(CogMethod *cogMethod); static sqInt markYoungObjectspcmethod(sqInt annotation, char *mcpc, sqInt cogMethod); +static void marshallSendArguments(sqInt numArgs); usqInt maxCogMethodAddress(void); static sqInt maybeFreeCogMethodDoesntLookKosher(CogMethod *cogMethod); static void maybeGenerateCheckFeatures(void); static void maybeGenerateICacheFlush(void); sqInt mcPCForstartBcpcin(sqInt bcpc, sqInt startbcpc, CogBlockMethod *cogMethod); +static void mergeAtfrom(CogSimStackEntry * self_in_mergeAtfrom, sqInt baseOffset, sqInt baseRegister); +static void mergeafterReturn(BytecodeFixup *fixup, sqInt mergeFollowsReturn); static sqInt methodAbortTrampolineFor(sqInt numArgs); static CogMethod * methodAfter(CogMethod *cogMethod); CogMethod * methodFor(void *address); @@ -832,6 +885,7 @@ sqInt mnuOffset(void); static sqInt modRMRO(AbstractInstruction * self_in_modRMRO, sqInt mod, sqInt regMode, sqInt regOpcode); static AbstractInstruction * gNegateR(sqInt reg); +static AbstractInstruction * gNop(void); static sqInt needsFrameIfInBlock(sqInt isInBlock); static sqInt needsFrameNever(sqInt isInBlock); static sqInt nextBytecodePCForatbyte0in(BytecodeDescriptor *descriptor, sqInt pc, sqInt opcodeByte, sqInt aMethodObj); @@ -857,6 +911,8 @@ sqInt pcisWithinMethod(char *address, CogMethod *cogMethod); static sqInt picAbortTrampolineFor(sqInt numArgs); static void planCompaction(void); +static void popToReg(CogSimStackEntry * self_in_popToReg, sqInt reg); +static sqInt prevInstIsPCAnnotated(void); static PrimitiveDescriptor * primitiveGeneratorOrNil(void); void printCogMethodFor(void *address); void printCogMethods(void); @@ -871,7 +927,12 @@ void recordCallOffsetInof(CogMethod *cogMethod, void *callLabelArg); static void recordGeneratedRunTimeaddress(char *aString, sqInt address); sqInt recordPrimTraceFunc(void); +static sqInt registerMask(CogSimStackEntry * self_in_registerMask); +static sqInt registerMaskFor(sqInt reg); +static sqInt registerMaskForand(sqInt reg1, sqInt reg2); static sqInt registerMaskForandand(sqInt reg1, sqInt reg2, sqInt reg3); +static sqInt registerOrNil(CogSimStackEntry * self_in_registerOrNil); +static void reinitializeFixupsFromthrough(sqInt start, sqInt end); static void relocateAndPruneYoungReferrers(void); static void relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta); static void relocateCallsAndSelfReferencesInMethod(CogMethod *cogMethod); @@ -911,10 +972,32 @@ static sqInt sizePCDependentInstructionAt(AbstractInstruction * self_in_sizePCDependentInstructionAt, sqInt eventualAbsoluteAddress); static sqInt slotOffsetOfInstVarIndex(sqInt index); static sqInt spanForatbyte0in(BytecodeDescriptor *descriptor, sqInt pc, sqInt opcodeByte, sqInt aMethodObj); +static void ssAllocateCallReg(sqInt requiredReg); +static void ssAllocateCallRegand(sqInt requiredReg1, sqInt requiredReg2); +static sqInt ssAllocatePreferredReg(sqInt preferredReg); +static void ssAllocateRequiredRegMaskupThrough(sqInt requiredRegsMask, sqInt stackPtr); +static void ssAllocateRequiredReg(sqInt requiredReg); +static void ssAllocateRequiredRegand(sqInt requiredReg1, sqInt requiredReg2); +static void ssAllocateRequiredRegupThrough(sqInt requiredReg, sqInt stackPtr); +static void ssFlushTo(sqInt index); +static void ssFlushUpThroughReceiverVariable(sqInt slotIndex); +static void ssFlushUpThroughTemporaryVariable(sqInt tempIndex); +static void ssPop(sqInt n); +static sqInt ssPushAnnotatedConstant(sqInt literal); +static sqInt ssPushBaseoffset(sqInt reg, sqInt offset); +static sqInt ssPushConstant(sqInt literal); +static sqInt ssPushDesc(CogSimStackEntry simStackEntry); +static sqInt ssPushRegister(sqInt reg); +static void ssPush(sqInt n); +static sqInt ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg); +static CogSimStackEntry * ssTop(void); +static CogSimStackEntry ssTopDescriptor(void); +static CogSimStackEntry * ssValue(sqInt n); static sqInt stackBytesForNumArgs(AbstractInstruction * self_in_stackBytesForNumArgs, sqInt numArgs); sqInt stackPageHeadroomBytes(void); static sqInt stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes); static void storeLiteralbeforeFollowingAddress(AbstractInstruction * self_in_storeLiteralbeforeFollowingAddress, sqInt literal, sqInt followingAddress); +static void storeToReg(CogSimStackEntry * self_in_storeToReg, sqInt reg); static sqInt sib(AbstractInstruction * self_in_sib, sqInt scale, sqInt indexReg, sqInt baseReg); static sqInt thirtyTwoBitValueAt(AbstractInstruction * self_in_thirtyTwoBitValueAt, sqInt startAddress); sqInt traceLinkedSendOffset(void); @@ -961,6 +1044,7 @@ static sqInt bytecodePointer; void * CFramePointer; void * CStackPointer; +static sqInt callerSavedRegMask; sqInt ceBaseFrameReturnTrampoline; sqInt ceCannotResumeTrampoline; void (*ceCaptureCStackPointers)(void); @@ -969,7 +1053,12 @@ static sqInt ceClosureCopyTrampoline; static sqInt ceCPICMissTrampoline; static sqInt ceCreateNewArrayTrampoline; +void (*ceEnter0ArgsPIC)(void); +void (*ceEnter1ArgsPIC)(void); +void (*ceEnter2ArgsPIC)(void); void (*ceEnterCogCodePopReceiverAndClassRegs)(void); +void (*ceEnterCogCodePopReceiverArg0Regs)(void); +void (*ceEnterCogCodePopReceiverArg1Arg0Regs)(void); void (*ceEnterCogCodePopReceiverReg)(void); static sqInt ceFetchContextInstVarTrampoline; static void (*ceFlushICache)(unsigned long from, unsigned long to); @@ -1002,6 +1091,8 @@ static sqInt cPICCaseSize; static sqInt cPICEndSize; static const int cStackAlignment = STACK_ALIGN_BYTES; +static sqInt deadCode; +static sqInt debugFixupBreaks; unsigned long debugPrimCallStackOffset; static AbstractInstruction * endCPICCase0; static AbstractInstruction * endCPICCase1; @@ -1016,38 +1107,38 @@ static sqInt firstSend; static BytecodeFixup * fixups; static BytecodeDescriptor generatorTable[256] = { - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -1128,7 +1219,7 @@ { genStoreAndPopTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { genPushReceiverBytecode, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { genPushReceiverBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantTrueBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantFalseBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantNilBytecode, (sqInt (*)(unsigned char,...))0, 1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -1192,28 +1283,28 @@ { genLongJumpIfFalse, (sqInt (*)(unsigned char,...))longForwardBranchDistance, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 1, 0 }, { genLongJumpIfFalse, (sqInt (*)(unsigned char,...))longForwardBranchDistance, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 1, 0 }, { genLongJumpIfFalse, (sqInt (*)(unsigned char,...))longForwardBranchDistance, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 1, 0 }, + { genSpecialSelectorArithmetic, (sqInt (*)(unsigned char,...))0, 0, 76, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorArithmetic, (sqInt (*)(unsigned char,...))0, 0, 77, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 24, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 26, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 27, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 25, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorComparison, (sqInt (*)(unsigned char,...))0, 0, 17, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorArithmetic, (sqInt (*)(unsigned char,...))0, 0, 78, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { genSpecialSelectorArithmetic, (sqInt (*)(unsigned char,...))0, 0, 79, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, { genSpecialSelectorEqualsEquals, (sqInt (*)(unsigned char,...))0, -1, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorClass, (sqInt (*)(unsigned char,...))0, 0, 0, 1, needsFrameNever, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, (sqInt (*)(unsigned char,...))0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, @@ -1282,10 +1373,12 @@ static sqInt lastSend; static usqInt limitAddress; static CogBlockMethod * maxMethodBefore; +static sqInt methodAbortTrampolines[4]; static sqInt methodBytesFreedSinceLastCompaction; static AbstractInstruction *methodLabel = &aMethodLabel; static sqInt methodObj; static sqInt methodOrBlockNumArgs; +static sqInt methodOrBlockNumTemps; static sqInt methodZoneBase; static sqInt missOffset; static AbstractInstruction * mnuCall; @@ -1297,6 +1390,9 @@ static sqInt opcodeIndex; static CogMethod *openPICList = 0; static sqInt openPICSize; +static CogSSOptStatus optStatus; +static sqInt picAbortTrampolines[4]; +static sqInt picMissTrampolines[4]; static void (*postCompileHook)(CogMethod *, void *); static AbstractInstruction * primInvokeLabel; static PrimitiveDescriptor primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1] = { @@ -1526,9 +1622,16 @@ }; static sqInt primitiveIndex; void (*realCEEnterCogCodePopReceiverAndClassRegs)(void); +void (*realCEEnterCogCodePopReceiverArg0Regs)(void); +void (*realCEEnterCogCodePopReceiverArg1Arg0Regs)(void); void (*realCEEnterCogCodePopReceiverReg)(void); +static sqInt regArgsHaveBeenPushed; static AbstractInstruction * sendMissCall; static sqInt sendTrampolines[NumSendTrampolines]; +static CogSimStackEntry simSelf; +static sqInt simSpillBase; +static CogSimStackEntry simStack[256]; +static sqInt simStackPtr; static AbstractInstruction * stackCheckLabel; static AbstractInstruction * stackOverflowCall; static sqInt superSendTrampolines[NumSendTrampolines]; @@ -1575,13 +1678,14 @@ #define halt() warning("halt") #define haltmsg(msg) error("halt: " msg) #define limitZony() ((CogMethod *)mzFreeStart) +#define maybeConstant(sse) ((sse)->constant) #define methodBytesFreedSinceLastCompaction() methodBytesFreedSinceLastCompaction #define nextOpenPIC methodObject #define nextOpenPICHack hack hack hack i.e. the getter macro does all the work #define noCheckEntryOffset() cmNoCheckEntryOffset #define noContextSwitchBlockEntryOffset() blockNoContextSwitchOffset #define notYetImplemented() warning("not yet implemented") -#define numRegArgs() 0 +#define numRegArgs() 1 #define printNum(n) printf("%ld", (long) n) #define printOnTrace() (traceLinkedSends & 8) #define print(aString) printf(aString) @@ -1591,7 +1695,12 @@ #define reportError(n) warning("compilation error") #define setCFramePointer(theFP) (CFramePointer = (void *)(theFP)) #define setCStackPointer(theSP) (CStackPointer = (void *)(theSP)) +#define simStackAt(index) (simStack + (index)) +#define traceDescriptor(ign) 0 +#define traceFixup(ign) 0 #define traceMapbyteatfor(ig,no,re,d) 0 +#define traceMerge(ign) 0 +#define traceSimStack() 0 #define tryLockVMOwner() (ceTryLockVMOwner() != 0) #define typeEtAlWord(cm) (((long *)(cm))[1]) #define unlockVMOwner() ceUnlockVMOwner() @@ -1699,9 +1808,18 @@ sqInt j; if (blockCount > 0) { + + /* Transcript ensureCr; nextPutAll: 'addBlockStartAt: '; print: bytecodepc; cr; flush. */ + i = blockCount - 1; while (1) { + + /* check for repeat addition during recompilation due to initialNil miscount. */ + blockStart = (&(blockStarts[i])); + if (((blockStart->startpc)) == bytecodepc) { + return blockStart; + } if (!((((blockStart->startpc)) > bytecodepc) && (i > 0))) break; i -= 1; @@ -1718,6 +1836,7 @@ (blockStart->startpc = bytecodepc); (blockStart->numArgs = numArgs); (blockStart->numCopied = numCopied); + (blockStart->numInitialNils = 0); (blockStart->stackCheckLabel = null); (blockStart->span = span); return blockStart; @@ -1937,6 +2056,30 @@ } static sqInt +availableRegisterOrNil(void) +{ + sqInt liveRegs; + + liveRegs = liveRegisters(); + if (!(liveRegs & (registerMaskFor(Arg1Reg)))) { + return Arg1Reg; + } + if (!(liveRegs & (registerMaskFor(Arg0Reg)))) { + return Arg0Reg; + } + if (!(liveRegs & (registerMaskFor(SendNumArgsReg)))) { + return SendNumArgsReg; + } + if (!(liveRegs & (registerMaskFor(ClassReg)))) { + return ClassReg; + } + if (!(liveRegs & (registerMaskFor(ReceiverResultReg)))) { + return ReceiverResultReg; + } + return null; +} + +static sqInt blockCodeSize(unsigned char byteZero, unsigned char byteOne, unsigned char byteTwo, unsigned char byteThree) { return (byteTwo * 256) + byteThree; @@ -2978,13 +3121,33 @@ static sqInt compileAbstractInstructionsFromthrough(sqInt start, sqInt end) { + sqInt debugBytecodePointers; BytecodeDescriptor *descriptor; BytecodeFixup *fixup; sqInt nextOpcodeIndex; sqInt result; + traceSimStack(); bytecodePointer = start; + descriptor = null; + deadCode = 0; do { + ; + fixup = fixupAt(bytecodePointer - initialPC); + if ((((usqInt)((fixup->targetInstruction)))) > 0) { + deadCode = 0; + if ((((usqInt)((fixup->targetInstruction)))) >= 2) { + mergeafterReturn(fixup, (descriptor != null) + && ((descriptor->isReturn))); + } + } + else { + if ((descriptor != null) + && ((descriptor->isReturn))) { + deadCode = 1; + } + } + ; byte0 = fetchByteofObject(bytecodePointer, methodObj); descriptor = generatorAt(byte0); if (((descriptor->numBytes)) > 1) { @@ -3000,9 +3163,16 @@ } } nextOpcodeIndex = opcodeIndex; - result = ((descriptor->generator))(); - fixup = fixupAt(bytecodePointer - initialPC); - if (((fixup->targetInstruction)) != 0) { + result = (deadCode + ? (((descriptor->isMapped)) + || (inBlock + && ((descriptor->isMappedInBlock))) + ? annotateBytecode(gNop()) + : 0),0 + : ((descriptor->generator))()); + traceDescriptor(descriptor); + traceSimStack(); + if ((((((usqInt)((fixup->targetInstruction)))) >= 1) && ((((usqInt)((fixup->targetInstruction)))) <= 2))) { if (opcodeIndex == nextOpcodeIndex) { gLabel(); } @@ -3019,6 +3189,10 @@ { BlockStart *blockStart; sqInt compiledBlocksCount; + sqInt i; + sqInt initialAnnotationIndex; + sqInt initialOpcodeIndex; + sqInt initialStackPtr; sqInt result; sqInt savedNeedsFrame; sqInt savedNumArgs; @@ -3031,9 +3205,23 @@ while (compiledBlocksCount < blockCount) { blockStart = blockStartAt(compiledBlocksCount); scanBlock(blockStart); - compileBlockEntry(blockStart); - if (((result = compileAbstractInstructionsFromthrough((blockStart->startpc), (((blockStart->startpc)) + ((blockStart->span))) - 1))) < 0) { - return result; + initialOpcodeIndex = opcodeIndex; + initialAnnotationIndex = annotationIndex; + while (1) { + compileBlockEntry(blockStart); + initialStackPtr = simStackPtr; + if (((result = compileAbstractInstructionsFromthrough(((blockStart->startpc)) + ((blockStart->numInitialNils)), (((blockStart->startpc)) + ((blockStart->span))) - 1))) < 0) { + return result; + } + if (initialStackPtr == simStackPtr) break; + assert(initialStackPtr > simStackPtr); + (blockStart->numInitialNils = (((blockStart->numInitialNils)) + simStackPtr) - initialStackPtr); + ((blockStart->fakeHeader)->dependent = null); + reinitializeFixupsFromthrough(((blockStart->startpc)) + ((blockStart->numInitialNils)), (((blockStart->startpc)) + ((blockStart->span))) - 1); + bzero(abstractOpcodes + initialOpcodeIndex, + (opcodeIndex - initialOpcodeIndex) * sizeof(AbstractInstruction)); + opcodeIndex = initialOpcodeIndex; + annotationIndex = initialAnnotationIndex; } compiledBlocksCount += 1; } @@ -3154,12 +3342,18 @@ sp-> Nth temp Avoid use of SendNumArgsReg which is the flag determining whether context switch is allowed on stack-overflow. */ +/* Build a frame for a block activation. See CoInterpreter + class>>initializeFrameIndices. Override to push the register receiver and + register arguments, if any, and to correctly + initialize the explicitly nilled/pushed temp entries (they are /not/ of + type constant nil). */ static void compileBlockFrameBuild(BlockStart *blockStart) { AbstractInstruction * cascade0; sqInt i; + sqInt ign; annotateBytecode(gLabel()); gPushR(FPReg); @@ -3180,6 +3374,20 @@ gCmpRR(TempReg, SPReg); gJumpBelow(stackOverflowCall); (blockStart->stackCheckLabel = annotateBytecode(gLabel())); + methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); + initSimStackForFramefulMethod((blockStart->startpc)); + if (((blockStart->numInitialNils)) > 0) { + if (((blockStart->numInitialNils)) > 1) { + annotateobjRef(gMoveCwR(nilObject(), TempReg), nilObject()); + for (ign = 1; ign <= ((blockStart->numInitialNils)); ign += 1) { + gPushR(TempReg); + } + } + else { + annotateobjRef(gPushCw(nilObject()), nilObject()); + } + methodOrBlockNumTemps = ((blockStart->numArgs)) + ((blockStart->numCopied)); + } } @@ -3187,10 +3395,14 @@ which is what is initially in ReceiverResultReg. We must annotate the first instruction so that findMethodForStartBcpc:inHomeMethod: can function. We need two annotations because the first is a fiducial. */ +/* Make sure ReceiverResultReg holds the receiver, loaded from + the closure, which is what is initially in ReceiverResultReg */ static void compileBlockFramelessEntry(BlockStart *blockStart) { + methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); + initSimStackForFramelessBlock((blockStart->startpc)); annotateBytecode((blockStart->entryLabel)); annotateBytecode((blockStart->entryLabel)); genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, TempReg); @@ -3231,11 +3443,14 @@ static CogMethod * compileCogMethod(sqInt selector) { + sqInt debugStackPointers; sqInt extra; sqInt numBlocks; sqInt numBytecodes; sqInt result; + methodOrBlockNumTemps = tempCountOf(methodObj); + ; hasYoungReferent = (isYoung(methodObj)) || (isYoung(selector)); methodOrBlockNumArgs = argumentCountOf(methodObj); @@ -3326,12 +3541,14 @@ /* Compile the abstract instructions for the entire method, including blocks. */ +/* Compile the abstract instructions for the entire method, including blocks. */ static sqInt compileEntireMethod(void) { sqInt result; + regArgsHaveBeenPushed = 0; compileProlog(); compileEntry(); if (((result = compilePrimitive())) < 0) { @@ -3383,6 +3600,9 @@ Ensure SendNumArgsReg is set early on (incidentally to nilObj) because it is the flag determining whether context switch is allowed on stack-overflow. */ +/* Build a frame for a CogMethod activation. See CoInterpreter + class>>initializeFrameIndices. Override to push the register receiver and + register arguments, if any. */ static void compileFrameBuild(void) @@ -3391,8 +3611,13 @@ AbstractInstruction *jumpSkip; if (!(needsFrame)) { + initSimStackForFramelessMethod(initialPC); return; } + genPushRegisterArgs(); + if (!(needsFrame)) { + return; + } gPushR(FPReg); gMoveRR(SPReg, FPReg); addDependent(methodLabel, annotateMethodRef(gPushCw(((sqInt)methodLabel)))); @@ -3419,6 +3644,7 @@ jmpTarget(jumpSkip, stackCheckLabel = gLabel()); } annotateBytecode(stackCheckLabel); + initSimStackForFramefulMethod(initialPC); } @@ -3588,7 +3814,7 @@ /* Compile the code for an open PIC. Perform a probe of the first-level method lookup cache followed by a call of ceSendFromOpenPIC: if the probe - fails. */ + fails. Override to push the register args when calling ceSendFromOpenPIC: */ static void compileOpenPICnumArgs(sqInt selector, sqInt numArgs) @@ -3650,6 +3876,7 @@ gCmpRR(SendNumArgsReg, TempReg); gJumpZero(itsAHit); jmpTarget(jumpSelectorMiss, gLabel()); + genPushRegisterArgsForNumArgs(numArgs); genSaveStackPointers(); genLoadCStackPointers(); addDependent(methodLabel, annotateMethodRef(gMoveCwR(((sqInt)methodLabel), SendNumArgsReg))); @@ -5961,7 +6188,7 @@ static sqInt cPICMissTrampolineFor(sqInt numArgs) { - return ceCPICMissTrampoline; + return picMissTrampolines[((numArgs < ((numRegArgs()) + 1)) ? numArgs : ((numRegArgs()) + 1))]; } static sqInt @@ -6327,11 +6554,15 @@ } else { genPushReceiverVariable(byte2); + (ssTop()->annotateUse = 1); + return 0; } break; case 3: genPushLiteralIndex(byte2); - break; + (ssTop()->annotateUse = 1); + return 0; + case 4: genPushLiteralVariable(byte2); break; @@ -6347,18 +6578,19 @@ } } - if (needsFrame) { - annotateBytecode(gLabel()); - } + assert(needsFrame); + assert(!(prevInstIsPCAnnotated())); + annotateBytecode(gLabel()); return 0; } static sqInt duplicateTopBytecode(void) { - gMoveMwrR(0, SPReg, TempReg); - gPushR(TempReg); - return 0; + CogSimStackEntry desc; + + desc = ssTopDescriptor(); + return ssPushDesc(desc); } @@ -6373,13 +6605,99 @@ BytecodeFixup *fixup; fixup = fixupAt(targetIndex); + traceFixup(fixup); + ; + if ((((usqInt)((fixup->targetInstruction)))) <= 1) { + (fixup->targetInstruction = ((AbstractInstruction *) 2)); + (fixup->simStackPtr = simStackPtr); + } + else { + if (((fixup->simStackPtr)) <= -2) { + (fixup->simStackPtr = simStackPtr); + } + else { + assert(((fixup->simStackPtr)) == simStackPtr); + } + } + return fixup; +} + + +/* Make sure there's a flagged fixup at the targetIndex (pc relative to first + pc) in fixups. + Initially a fixup's target is just a flag. Later on it is replaced with a + proper instruction. */ + +static BytecodeFixup * +ensureNonMergeFixupAt(sqInt targetIndex) +{ + BytecodeFixup *fixup; + + fixup = fixupAt(targetIndex); if (((fixup->targetInstruction)) == 0) { (fixup->targetInstruction = ((AbstractInstruction *) 1)); } + ; return fixup; } +static void +ensureReceiverResultRegContainsSelf(void) +{ + if (needsFrame) { + if (!(((optStatus.isReceiverResultRegLive)) + && (((optStatus.ssEntry)) == ((&simSelf))))) { + ssAllocateRequiredReg(ReceiverResultReg); + storeToReg((&simSelf), ReceiverResultReg); + } + (optStatus.isReceiverResultRegLive = 1); + (optStatus.ssEntry = (&simSelf)); + } + else { + assert((((simSelf.type)) == SSRegister) + && (((simSelf.registerr)) == ReceiverResultReg)); + assert(((optStatus.isReceiverResultRegLive)) + && (((optStatus.ssEntry)) == ((&simSelf)))); + } +} +static void +ensureSpilledAtfrom(CogSimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister) +{ + AbstractInstruction *inst; + + if ((self_in_ensureSpilledAtfrom->spilled)) { + if (((self_in_ensureSpilledAtfrom->type)) == SSSpill) { + assert((((self_in_ensureSpilledAtfrom->offset)) == baseOffset) + && (((self_in_ensureSpilledAtfrom->registerr)) == baseRegister)); + return; + } + } + assert(((self_in_ensureSpilledAtfrom->type)) != SSSpill); + if (((self_in_ensureSpilledAtfrom->type)) == SSConstant) { + inst = annotateobjRef(gPushCw((self_in_ensureSpilledAtfrom->constant)), (self_in_ensureSpilledAtfrom->constant)); + } + else { + if (((self_in_ensureSpilledAtfrom->type)) == SSBaseOffset) { + gMoveMwrR((self_in_ensureSpilledAtfrom->offset), (self_in_ensureSpilledAtfrom->registerr), TempReg); + inst = gPushR(TempReg); + } + else { + assert(((self_in_ensureSpilledAtfrom->type)) == SSRegister); + inst = gPushR((self_in_ensureSpilledAtfrom->registerr)); + } + (self_in_ensureSpilledAtfrom->type) = SSSpill; + (self_in_ensureSpilledAtfrom->offset) = baseOffset; + (self_in_ensureSpilledAtfrom->registerr) = baseRegister; + } + (self_in_ensureSpilledAtfrom->spilled) = 1; + if ((self_in_ensureSpilledAtfrom->annotateUse)) { + annotateBytecode(inst); + (self_in_ensureSpilledAtfrom->annotateUse) = 0; + } +} + + /* This is a static version of ceEnterCogCodePopReceiverReg for break-pointing when debugging in C. */ /* (and this exists only to reference Debug) */ @@ -6407,6 +6725,34 @@ realCEEnterCogCodePopReceiverAndClassRegs(); } + +/* This is a static version of ceEnterCogCodePopReceiverArg0Regs + for break-pointing when debugging in C. */ +/* (and this exists only to reference Debug) */ + +void +enterCogCodePopReceiverArg0Regs(void) +{ + if (!(Debug)) { + error("what??"); + } + realCEEnterCogCodePopReceiverArg0Regs(); +} + + +/* This is a static version of ceEnterCogCodePopReceiverArg1Arg0Regs + for break-pointing when debugging in C. */ +/* (and this exists only to reference Debug) */ + +void +enterCogCodePopReceiverArg1Arg0Regs(void) +{ + if (!(Debug)) { + error("what??"); + } + realCEEnterCogCodePopReceiverArg1Arg0Regs(); +} + static sqInt extendedPushBytecode(void) { @@ -6957,29 +7303,27 @@ } -/* Stack looks like - receiver (also in ResultReceiverReg) - arg +/* Receiver and arg in registers. + Stack looks like return address */ static sqInt genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)) { AbstractInstruction *doOp; - AbstractInstruction *fail; AbstractInstruction *jumpFailAlloc; AbstractInstruction *jumpFailCheck; AbstractInstruction *jumpFailClass; AbstractInstruction *jumpSmallInt; - gMoveMwrR(BytesPerWord, SPReg, TempReg); + gMoveRR(Arg0Reg, TempReg); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, ClassReg); jumpSmallInt = genJumpSmallIntegerInScratchReg(TempReg); - genGetCompactClassIndexNonIntOfinto(ClassReg, SendNumArgsReg); + genGetCompactClassIndexNonIntOfinto(Arg0Reg, SendNumArgsReg); gCmpCqR(classFloatCompactIndex(), SendNumArgsReg); jumpFailClass = gJumpNonZero(0); - genGetDoubleValueOfinto(ClassReg, DPFPReg1); + genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); doOp = gLabel(); if (preOpCheckOrNil == null) { null; @@ -6990,29 +7334,30 @@ genoperandoperand(arithmeticOperator, DPFPReg1, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); gMoveRR(SendNumArgsReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); + assert(methodOrBlockNumArgs <= (numRegArgs())); + jmpTarget(jumpFailClass, gLabel()); + if (preOpCheckOrNil == null) { + null; + } + else { + jmpTarget(jumpFailCheck, getJmpTarget(jumpFailClass)); + } + genPushRegisterArgsForNumArgs(methodOrBlockNumArgs); + jumpFailClass = gJump(0); jmpTarget(jumpSmallInt, gLabel()); genConvertSmallIntegerToIntegerInScratchReg(ClassReg); gConvertRRd(ClassReg, DPFPReg1); gJump(doOp); jmpTarget(jumpFailAlloc, gLabel()); compileInterpreterPrimitive(functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex)); - fail = gLabel(); jmpTarget(jumpFailClass, gLabel()); - if (preOpCheckOrNil == null) { - null; - } - else { - jmpTarget(jumpFailCheck, fail); - } return 0; } -/* Stack looks like - receiver (also in ResultReceiverReg) - arg +/* Receiver and arg in registers. + Stack looks like return address */ static sqInt @@ -7023,14 +7368,13 @@ AbstractInstruction *jumpFail; AbstractInstruction *jumpSmallInt; - gMoveMwrR(BytesPerWord, SPReg, TempReg); + gMoveRR(Arg0Reg, TempReg); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); - gMoveRR(TempReg, ClassReg); jumpSmallInt = genJumpSmallIntegerInScratchReg(TempReg); - genGetCompactClassIndexNonIntOfinto(ClassReg, SendNumArgsReg); + genGetCompactClassIndexNonIntOfinto(Arg0Reg, SendNumArgsReg); gCmpCqR(classFloatCompactIndex(), SendNumArgsReg); jumpFail = gJumpNonZero(0); - genGetDoubleValueOfinto(ClassReg, DPFPReg1); + genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); if (invertComparison) { /* May need to invert for NaNs */ @@ -7045,13 +7389,12 @@ jumpCond = jumpOpcodeGenerator(0); annotateobjRef(gMoveCwR(falseObject(), ReceiverResultReg), falseObject()); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpCond, annotateobjRef(gMoveCwR(trueObject(), ReceiverResultReg), trueObject())); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpSmallInt, gLabel()); - genConvertSmallIntegerToIntegerInScratchReg(ClassReg); - gConvertRRd(ClassReg, DPFPReg1); + genConvertSmallIntegerToIntegerInScratchReg(Arg0Reg); + gConvertRRd(Arg0Reg, DPFPReg1); gJump(compare); jmpTarget(jumpFail, gLabel()); return 0; @@ -7074,6 +7417,38 @@ then executes a return instruction to pop off the entry-point and jump to it. */ +static void (*genEnilopmartForandandcalled(sqInt regArg1, sqInt regArg2, sqInt regArg3, char *trampolineName))(void) + +{ + sqInt endAddress; + sqInt enilopmart; + sqInt size; + + opcodeIndex = 0; + genLoadStackPointers(); + gPopR(regArg3); + gPopR(regArg2); + gPopR(regArg1); + gRetN(0); + computeMaximumSizes(); + size = generateInstructionsAt(methodZoneBase); + endAddress = outputInstructionsAt(methodZoneBase); + assert((methodZoneBase + size) == endAddress); + enilopmart = methodZoneBase; + methodZoneBase = alignUptoRoutineBoundary(endAddress); + nopsFromto(backEnd, endAddress, methodZoneBase - 1); + recordGeneratedRunTimeaddress(trampolineName, enilopmart); + return ((void (*)(void)) enilopmart); +} + + +/* An enilopmart (the reverse of a trampoline) is a piece of code that makes + the system-call-like transition from the C runtime into generated machine + code. The desired arguments and entry-point are pushed on a stackPage's + stack. The enilopmart pops off the values to be loaded into registers and + then executes a return instruction to pop off the entry-point and jump to + it. */ + static void (*genEnilopmartForandcalled(sqInt regArg1, sqInt regArg2, char *trampolineName))(void) { @@ -7128,6 +7503,44 @@ } +/* Generate special versions of the ceEnterCogCodePopReceiverAndClassRegs + enilopmart that also pop register args from the stack to undo the pushing + of register args in the abort/miss trampolines. */ + +static void (*genEnterPICEnilopmartNumArgs(sqInt numArgs))(void) + +{ + sqInt endAddress; + sqInt enilopmart; + sqInt size; + + opcodeIndex = 0; + genLoadStackPointers(); + gPopR(ClassReg); + gPopR(TempReg); + gPopR(SendNumArgsReg); + if (numArgs > 0) { + if (numArgs > 1) { + gPopR(Arg1Reg); + assert((numRegArgs()) == 2); + } + gPopR(Arg0Reg); + } + gPopR(ReceiverResultReg); + gPushR(SendNumArgsReg); + gJumpR(TempReg); + computeMaximumSizes(); + size = generateInstructionsAt(methodZoneBase); + endAddress = outputInstructionsAt(methodZoneBase); + assert((methodZoneBase + size) == endAddress); + enilopmart = methodZoneBase; + methodZoneBase = alignUptoRoutineBoundary(endAddress); + nopsFromto(backEnd, endAddress, methodZoneBase - 1); + recordGeneratedRunTimeaddress(trampolineNamenumArgs("ceEnterPIC", numArgs), enilopmart); + return ((void (*)(void)) enilopmart); +} + + /* Can use any of the first 32 literals for the selector and pass up to 7 arguments. */ @@ -7144,9 +7557,13 @@ return genSendSupernumArgs(literalofMethod(byte1 & 31, methodObj), ((usqInt) byte1) >> 5); } + +/* Override to push the register receiver and register arguments, if any. */ + static sqInt genExternalizePointersForPrimitiveCall(void) { + genPushRegisterArgs(); gMoveMwrR(0, SPReg, ClassReg); gMoveRAw(FPReg, framePointerAddress()); gLoadEffectiveAddressMwrR(BytesPerWord, SPReg, TempReg); @@ -7293,6 +7710,9 @@ /* Enilopmarts transfer control from C into machine code (backwards trampolines). */ +/* Enilopmarts transfer control from C into machine code (backwards + trampolines). Override to add version for generic and PIC-specific entry + with reg args. */ static void generateEnilopmarts(void) @@ -7318,6 +7738,27 @@ cePrimReturnEnterCogCodeProfiling = methodZoneBase; outputInstructionsForGeneratedRuntimeAt(cePrimReturnEnterCogCodeProfiling); recordGeneratedRunTimeaddress("cePrimReturnEnterCogCodeProfiling", cePrimReturnEnterCogCodeProfiling); + +# if Debug + realCEEnterCogCodePopReceiverArg0Regs = genEnilopmartForandcalled(ReceiverResultReg, Arg0Reg, "realCEEnterCogCodePopReceiverArg0Regs"); + ceEnterCogCodePopReceiverArg0Regs = enterCogCodePopReceiverArg0Regs; + realCEEnterCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, "realCEEnterCogCodePopReceiverArg1Arg0Regs"); + ceEnterCogCodePopReceiverArg1Arg0Regs = enterCogCodePopReceiverArg1Arg0Regs; + +# else /* Debug */ + ceEnterCogCodePopReceiverArg0Regs = genEnilopmartForandcalled(ReceiverResultReg, Arg0Reg, "ceEnterCogCodePopReceiverArg0Regs"); + ceEnterCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, "ceEnterCogCodePopReceiverArg1Arg0Regs"); + +# endif /* Debug */ + + ceEnter0ArgsPIC = genEnterPICEnilopmartNumArgs(0); + if ((numRegArgs()) >= 1) { + ceEnter1ArgsPIC = genEnterPICEnilopmartNumArgs(1); + if ((numRegArgs()) >= 2) { + ceEnter1ArgsPIC = genEnterPICEnilopmartNumArgs(2); + assert((numRegArgs()) == 2); + } + } } @@ -7472,9 +7913,17 @@ static void generateMissAbortTrampolines(void) { - ceMethodAbortTrampoline = genMethodAbortTrampoline(); - cePICAbortTrampoline = genPICAbortTrampoline(); - ceCPICMissTrampoline = genTrampolineForcalledargarg(ceCPICMissreceiver, "ceCPICMissTrampoline", ClassReg, ReceiverResultReg); + sqInt numArgs; + + for (numArgs = 0; numArgs <= ((numRegArgs()) + 1); numArgs += 1) { + methodAbortTrampolines[numArgs] = (genMethodAbortTrampolineFor(numArgs)); + } + for (numArgs = 0; numArgs <= ((numRegArgs()) + 1); numArgs += 1) { + picAbortTrampolines[numArgs] = (genPICAbortTrampolineFor(numArgs)); + } + for (numArgs = 0; numArgs <= ((numRegArgs()) + 1); numArgs += 1) { + picMissTrampolines[numArgs] = (genPICMissTrampolineFor(numArgs)); + } ; } @@ -7534,6 +7983,9 @@ } +/* Override to generate code to push the register arg(s) for <= numRegArg + arity sends. + */ /* Slang needs these apparently superfluous asSymbol sends. */ static void @@ -7542,13 +7994,13 @@ sqInt numArgs; for (numArgs = 0; numArgs <= (NumSendTrampolines - 2); numArgs += 1) { - sendTrampolines[numArgs] = (genTrampolineForcalledargargargarg(ceSendsupertonumArgs, trampolineNamenumArgs("ceSend", numArgs), ClassReg, 0, ReceiverResultReg, numArgs)); + sendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSend", numArgs), ClassReg, 0, ReceiverResultReg, numArgs)); } - sendTrampolines[NumSendTrampolines - 1] = (genTrampolineForcalledargargargarg(ceSendsupertonumArgs, trampolineNamenumArgs("ceSend", -1), ClassReg, 0, ReceiverResultReg, SendNumArgsReg)); + sendTrampolines[NumSendTrampolines - 1] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, (numRegArgs()) + 1, trampolineNamenumArgs("ceSend", -1), ClassReg, 0, ReceiverResultReg, SendNumArgsReg)); for (numArgs = 0; numArgs <= (NumSendTrampolines - 2); numArgs += 1) { - superSendTrampolines[numArgs] = (genTrampolineForcalledargargargarg(ceSendsupertonumArgs, trampolineNamenumArgs("ceSuperSend", numArgs), ClassReg, 1, ReceiverResultReg, numArgs)); + superSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSuperSend", numArgs), ClassReg, 1, ReceiverResultReg, numArgs)); } - superSendTrampolines[NumSendTrampolines - 1] = (genTrampolineForcalledargargargarg(ceSendsupertonumArgs, trampolineNamenumArgs("ceSuperSend", -1), ClassReg, 1, ReceiverResultReg, SendNumArgsReg)); + superSendTrampolines[NumSendTrampolines - 1] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, (numRegArgs()) + 1, trampolineNamenumArgs("ceSuperSend", -1), ClassReg, 1, ReceiverResultReg, SendNumArgsReg)); firstSend = sendTrampolines[0]; lastSend = superSendTrampolines[NumSendTrampolines - 1]; } @@ -7588,7 +8040,7 @@ { ceTraceLinkedSendTrampoline = genSafeTrampolineForcalledarg(ceTraceLinkedSend, "ceTraceLinkedSendTrampoline", ReceiverResultReg); ceTraceBlockActivationTrampoline = genTrampolineForcalled(ceTraceBlockActivation, "ceTraceBlockActivationTrampoline"); - ceTraceStoreTrampoline = genSafeTrampolineForcalledargarg(ceTraceStoreOfinto, "ceTraceStoreTrampoline", ClassReg, ReceiverResultReg); + ceTraceStoreTrampoline = genSafeTrampolineForcalledargarg(ceTraceStoreOfinto, "ceTraceStoreTrampoline", TempReg, ReceiverResultReg); } @@ -8058,6 +8510,7 @@ static sqInt genJumpBackTo(sqInt targetBytecodePC) { + ssFlushTo(simStackPtr); gMoveAwR(stackLimitAddress(), TempReg); gCmpRR(TempReg, SPReg); gJumpAboveOrEqual(fixupAt(targetBytecodePC - initialPC)); @@ -8114,19 +8567,39 @@ return jumpToTarget; } - -/* Cunning trick by LPD. If true and false are contiguous subtract the - smaller. Correct result is either 0 or the distance between them. If - result is not 0 or - their distance send mustBeBoolean. */ - static sqInt genJumpIfto(sqInt boolean, sqInt targetBytecodePC) { + CogSimStackEntry *desc; + BytecodeFixup *fixup; AbstractInstruction *ok; + ssFlushTo(simStackPtr - 1); + desc = ssTop(); + ssPop(1); + if ((((desc->type)) == SSConstant) + && ((((desc->constant)) == (trueObject())) + || (((desc->constant)) == (falseObject())))) { + + /* Must arrange there's a fixup at the target whether it is jumped to or + not so that the simStackPtr can be kept correct. */ + /* Must enter any annotatedConstants into the map */ + + fixup = ensureFixupAt(targetBytecodePC - initialPC); + if ((desc->annotateUse)) { + annotateBytecode((prevInstIsPCAnnotated() + ? gNop() + : gLabel())); + } + annotateBytecode((((desc->constant)) == boolean + ? gJump(fixup) + : (prevInstIsPCAnnotated() + ? gNop() + : gLabel()))); + return 0; + } + popToReg(desc, TempReg); assert((objectAfter(falseObject())) == (trueObject())); - gPopR(TempReg); annotateobjRef(gSubCwR(boolean, TempReg), boolean); gJumpZero(ensureFixupAt(targetBytecodePC - initialPC)); gCmpCqR((boolean == (falseObject()) @@ -8157,6 +8630,7 @@ static sqInt genJumpTo(sqInt targetBytecodePC) { + ssFlushTo(simStackPtr); gJump(ensureFixupAt(targetBytecodePC - initialPC)); return 0; } @@ -8253,7 +8727,39 @@ return genJumpTo(targetpc); } +static sqInt +genMarshalledSendSupernumArgs(sqInt selector, sqInt numArgs) +{ + if (isYoung(selector)) { + hasYoungReferent = 1; + } + assert(needsFrame); + if (numArgs > 2) { + gMoveCqR(numArgs, SendNumArgsReg); + } + gMoveCwR(selector, ClassReg); + CallSend(superSendTrampolines[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]); + (optStatus.isReceiverResultRegLive = 0); + return ssPushRegister(ReceiverResultReg); +} +static sqInt +genMarshalledSendnumArgs(sqInt selector, sqInt numArgs) +{ + if (isYoung(selector)) { + hasYoungReferent = 1; + } + assert(needsFrame); + if (numArgs > 2) { + gMoveCqR(numArgs, SendNumArgsReg); + } + gMoveCwR(selector, ClassReg); + CallSend(sendTrampolines[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]); + (optStatus.isReceiverResultRegLive = 0); + return ssPushRegister(ReceiverResultReg); +} + + /* Generate the abort for a method. This abort performs either a call of ceSICMiss: to handle a single-in-line cache miss or a call of ceStackOverflow: to handle a @@ -8265,7 +8771,7 @@ miss. */ static sqInt -genMethodAbortTrampoline(void) +genMethodAbortTrampolineFor(sqInt numArgs) { AbstractInstruction *jumpSICMiss; @@ -8274,7 +8780,10 @@ jumpSICMiss = gJumpNonZero(0); compileTrampolineForcallJumpBarnumArgsargargargargsaveRegsresultReg(ceStackOverflow, 1, 1, SendNumArgsReg, null, null, null, 0, null); jmpTarget(jumpSICMiss, gLabel()); - return genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(ceSICMiss, "ceMethodAbort", 1, 1, ReceiverResultReg, null, null, null, 0, null, 1); + genPushRegisterArgsForAbortMissNumArgs(numArgs); + return genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(ceSICMiss, trampolineNamenumArgs("ceMethodAbort", (numArgs <= (numRegArgs()) + ? numArgs + : -1)), 1, 1, ReceiverResultReg, null, null, null, 0, null, 1); } static void @@ -8327,62 +8836,71 @@ ClassReg. If the register is zero then this is an MNU. */ static sqInt -genPICAbortTrampoline(void) +genPICAbortTrampolineFor(sqInt numArgs) { opcodeIndex = 0; - return genInnerPICAbortTrampoline("cePICAbort"); + genPushRegisterArgsForAbortMissNumArgs(numArgs); + return genInnerPICAbortTrampoline(trampolineNamenumArgs("cePICAbort", (numArgs <= (numRegArgs()) + ? numArgs + : -1))); } static sqInt +genPICMissTrampolineFor(sqInt numArgs) +{ + sqInt startAddress; + + startAddress = methodZoneBase; + + /* N.B. a closed PIC jumps to the miss routine, not calls it, so there is only one retpc on the stack. */ + + opcodeIndex = 0; + genPushRegisterArgsForNumArgs(numArgs); + genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(ceCPICMissreceiver, trampolineNamenumArgs("cePICMiss", (numArgs <= (numRegArgs()) + ? numArgs + : -1)), 1, 2, ClassReg, ReceiverResultReg, null, null, 0, null, 1); + return startAddress; +} + +static sqInt genPopStackBytecode(void) { - gAddCqR(BytesPerWord, SPReg); + if ((ssTop()->spilled)) { + gAddCqR(BytesPerWord, SPReg); + } + ssPop(1); return 0; } - -/* Stack looks like - receiver (also in ResultReceiverReg) - arg - return address */ - static sqInt genPrimitiveAdd(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); - gMoveRR(ReceiverResultReg, TempReg); - gAddRR(ClassReg, TempReg); + gAddRR(ReceiverResultReg, ClassReg); jumpOvfl = gJumpOverflow(0); - gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gMoveRR(ClassReg, ReceiverResultReg); + gRetN(0); jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, gLabel())); return 0; } - -/* Stack looks like - receiver (also in ResultReceiverReg) - return address */ - static sqInt genPrimitiveAsFloat(void) { AbstractInstruction *jumpFailAlloc; - gMoveRR(ReceiverResultReg, ClassReg); - genConvertSmallIntegerToIntegerInScratchReg(ClassReg); - gConvertRRd(ClassReg, DPFPReg0); + gMoveRR(ReceiverResultReg, TempReg); + genConvertSmallIntegerToIntegerInScratchReg(TempReg); + gConvertRRd(TempReg, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); gMoveRR(SendNumArgsReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord); + gRetN(0); jmpTarget(jumpFailAlloc, gLabel()); compileInterpreterPrimitive(functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex)); return 0; @@ -8391,8 +8909,8 @@ static sqInt genPrimitiveAt(void) { - gMoveMwrR(BytesPerWord, SPReg, Arg0Reg); - return genInnerPrimitiveAt(BytesPerWord * 2); + assert((numRegArgs()) >= 1); + return genInnerPrimitiveAt(0); } static sqInt @@ -8400,15 +8918,13 @@ { AbstractInstruction *jumpNotSI; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); - /* Whether the SmallInteger tags are zero or non-zero, anding them together will preserve them. */ + /* Whether the SmallInteger tags are zero or non-zero, oring them together will preserve them. */ jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); - gAndRR(ClassReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gAndRR(Arg0Reg, ReceiverResultReg); + gRetN(0); jmpTarget(jumpNotSI, gLabel()); return 0; } @@ -8418,26 +8934,23 @@ { AbstractInstruction *jumpNotSI; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); /* Whether the SmallInteger tags are zero or non-zero, oring them together will preserve them. */ jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); - gOrRR(ClassReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gOrRR(Arg0Reg, ReceiverResultReg); + gRetN(0); jmpTarget(jumpNotSI, gLabel()); return 0; } -/* Stack looks like - receiver (also in ResultReceiverReg) - arg +/* Receiver and arg in registers. + Stack looks like return address - rTemp := ArgOffset(SP) + rTemp := rArg0 rClass := tTemp rTemp := rTemp & 1 jz nonInt @@ -8479,8 +8992,9 @@ AbstractInstruction *jumpOvfl; AbstractInstruction *jumpTooBig; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + assert((numRegArgs()) >= 1); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); genConvertSmallIntegerToIntegerInScratchReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpNegative))) { @@ -8497,14 +9011,14 @@ genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); gLogicalShiftLeftRR(ClassReg, ReceiverResultReg); genAddSmallIntegerTagsTo(ReceiverResultReg); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpNegative, gNegateR(ClassReg)); gCmpCqR(numSmallIntegerBits(), ClassReg); jumpInRange = gJumpLessOrEqual(0); gMoveCqR(numSmallIntegerBits(), ClassReg); jmpTarget(jumpInRange, gArithmeticShiftRightRR(ClassReg, ReceiverResultReg)); genSetSmallIntegerTagsIn(ReceiverResultReg); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpNotSI, jmpTarget(jumpTooBig, jmpTarget(jumpOvfl, gLabel()))); return 0; } @@ -8514,16 +9028,14 @@ { AbstractInstruction *jumpNotSI; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); /* Clear one or the other tag so that xoring will preserve them. */ jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); - genRemoveSmallIntegerTagsInScratchReg(ClassReg); - gXorRR(ClassReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); + gXorRR(Arg0Reg, ReceiverResultReg); + gRetN(0); jmpTarget(jumpNotSI, gLabel()); return 0; } @@ -8535,6 +9047,13 @@ block entry or the no-context-switch entry, as appropriate, and we're done. If not, invoke the interpreter primitive. */ +/* Check the argument count. Fail if wrong. + Get the method from the outerContext and see if it is cogged. If so, jump + to the + block entry or the no-context-switch entry, as appropriate, and we're + done. If not, + invoke the interpreter primitive. + Override to push the register args first. */ static sqInt genPrimitiveClosureValue(void) @@ -8544,6 +9063,7 @@ void (*primitiveRoutine)(); sqInt result; + genPushRegisterArgs(); genLoadSlotsourceRegdestReg(ClosureNumArgsIndex, ReceiverResultReg, TempReg); gCmpCqR(((methodOrBlockNumArgs << 1) | 1), TempReg); jumpFail = gJumpNonZero(0); @@ -8577,9 +9097,9 @@ AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); - gMoveRR(TempReg, Arg1Reg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); + gMoveRR(Arg0Reg, Arg1Reg); /* We must shift away the tags, not just subtract them, so that the overflow case doesn't actually overflow the machine instruction. */ @@ -8607,8 +9127,7 @@ jmpTarget(jumpSameSign, convert = gLabel()); genConvertIntegerToSmallIntegerInScratchReg(TempReg); gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpExact, gCmpCqR(1 << ((numSmallIntegerBits()) - 1), TempReg)); gJumpLess(convert); jmpTarget(jumpZero, jmpTarget(jumpNotSI, gLabel())); @@ -8623,8 +9142,8 @@ AbstractInstruction *jumpOverflow; AbstractInstruction *jumpZero; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); /* We must shift away the tags, not just subtract them, so that the overflow case doesn't actually overflow the machine instruction. */ @@ -8644,8 +9163,7 @@ jumpOverflow = gJumpGreaterOrEqual(0); genConvertIntegerToSmallIntegerInScratchReg(TempReg); gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpOverflow, jmpTarget(jumpInexact, jmpTarget(jumpZero, jmpTarget(jumpNotSI, gLabel())))); return 0; } @@ -8657,9 +9175,8 @@ } -/* Stack looks like - receiver (also in ResultReceiverReg) - arg +/* Receiver and arg in registers. + Stack looks like return address */ static sqInt @@ -8667,14 +9184,12 @@ { AbstractInstruction *jumpFalse; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gCmpRR(TempReg, ReceiverResultReg); + gCmpRR(Arg0Reg, ReceiverResultReg); jumpFalse = gJumpNonZero(0); annotateobjRef(gMoveCwR(trueObject(), ReceiverResultReg), trueObject()); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpFalse, annotateobjRef(gMoveCwR(falseObject(), ReceiverResultReg), falseObject())); - gRetN(BytesPerWord * 2); + gRetN(0); return 0; } @@ -8732,11 +9247,6 @@ return genDoubleComparisoninvert(gJumpFPNotEqual, 0); } - -/* Stack looks like - receiver (also in ResultReceiverReg) - return address */ - static sqInt genPrimitiveFloatSquareRoot(void) { @@ -8746,8 +9256,7 @@ gSqrtRd(DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); gMoveRR(SendNumArgsReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord); + gRetN(0); jmpTarget(jumpFailAlloc, gLabel()); compileInterpreterPrimitive(functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex)); return 0; @@ -8780,8 +9289,7 @@ jumpSI = genJumpSmallIntegerInScratchReg(ClassReg); genGetHashFieldNonIntOfasSmallIntegerInto(ReceiverResultReg, TempReg); gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord); + gRetN(0); jmpTarget(jumpSI, gLabel()); return 0; } @@ -8806,8 +9314,8 @@ AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); jumpZero = gJumpZero(0); @@ -8830,8 +9338,7 @@ jmpTarget(jumpSameSign, jmpTarget(jumpExact, gLabel())); genSetSmallIntegerTagsIn(ClassReg); gMoveRR(ClassReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpZero, jmpTarget(jumpNotSI, gLabel())); return 0; } @@ -8842,18 +9349,17 @@ AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); + gMoveRR(ReceiverResultReg, Arg1Reg); jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); - gMoveRR(ReceiverResultReg, TempReg); - genRemoveSmallIntegerTagsInScratchReg(TempReg); - gMulRR(TempReg, ClassReg); + genRemoveSmallIntegerTagsInScratchReg(Arg1Reg); + gMulRR(Arg1Reg, ClassReg); jumpOvfl = gJumpOverflow(0); genSetSmallIntegerTagsIn(ClassReg); gMoveRR(ClassReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, gLabel())); return 0; } @@ -8871,8 +9377,8 @@ AbstractInstruction *jumpOverflow; AbstractInstruction *jumpZero; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); + gMoveRR(Arg0Reg, ClassReg); /* We must shift away the tags, not just subtract them, so that the overflow case doesn't actually overflow the machine instruction. */ @@ -8890,8 +9396,7 @@ jumpOverflow = gJumpGreaterOrEqual(0); genConvertIntegerToSmallIntegerInScratchReg(TempReg); gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpOverflow, jmpTarget(jumpZero, jmpTarget(jumpNotSI, gLabel()))); return 0; } @@ -8899,38 +9404,30 @@ static sqInt genPrimitiveSize(void) { - return genInnerPrimitiveSize(BytesPerWord); + return genInnerPrimitiveSize(0); } static sqInt genPrimitiveStringAt(void) { - gMoveMwrR(BytesPerWord, SPReg, Arg0Reg); - return genInnerPrimitiveStringAt(BytesPerWord * 2); + assert((numRegArgs()) >= 1); + return genInnerPrimitiveStringAt(0); } - -/* Stack looks like - receiver (also in ResultReceiverReg) - arg - return address */ - static sqInt genPrimitiveSubtract(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); jumpNotSI = genJumpNotSmallIntegerInScratchReg(TempReg); gMoveRR(ReceiverResultReg, TempReg); - gSubRR(ClassReg, TempReg); + gSubRR(Arg0Reg, TempReg); jumpOvfl = gJumpOverflow(0); genAddSmallIntegerTagsTo(TempReg); gMoveRR(TempReg, ReceiverResultReg); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, gLabel())); return 0; } @@ -9004,9 +9501,10 @@ genPushActiveContextBytecode(void) { assert(needsFrame); + (optStatus.isReceiverResultRegLive = 0); + ssAllocateCallReg(ReceiverResultReg); CallRT(cePushActiveContextTrampoline); - gPushR(ReceiverResultReg); - return 0; + return ssPushRegister(ReceiverResultReg); } @@ -9040,18 +9538,18 @@ assert(needsFrame); addBlockStartAtnumArgsnumCopiedspan(bytecodePointer + 4, byte1 & 15, numCopied = ((usqInt) byte1) >> 4, (byte2 << 8) + byte3); + if (numCopied > 0) { + ssFlushTo(simStackPtr); + } + (optStatus.isReceiverResultRegLive = 0); + ssAllocateCallRegand(SendNumArgsReg, ReceiverResultReg); gMoveCqR(byte1 | ((bytecodePointer + 5) << 8), SendNumArgsReg); CallRT(ceClosureCopyTrampoline); if (numCopied > 0) { - if (numCopied > 1) { - gAddCqR((numCopied - 1) * BytesPerWord, SPReg); - } - gMoveRMwr(ReceiverResultReg, 0, SPReg); + gAddCqR(numCopied * BytesPerWord, SPReg); + ssPop(numCopied); } - else { - gPushR(ReceiverResultReg); - } - return 0; + return ssPushRegister(ReceiverResultReg); } static sqInt @@ -9100,22 +9598,25 @@ genPushLiteralVariable(sqInt literalIndex) { sqInt association; + sqInt freeReg; + freeReg = ssAllocatePreferredReg(ClassReg); /* N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods. */ + /* So far descriptors are not rich enough to describe the entire dereference so generate the register + load but don't push the result. There is an order-or-evaluation issue if we defer the dereference. */ association = literalofMethod(literalIndex, methodObj); - annotateobjRef(gMoveCwR(association, ClassReg), association); - genLoadSlotsourceRegdestReg(ValueIndex, ClassReg, TempReg); - gPushR(TempReg); + annotateobjRef(gMoveCwR(association, TempReg), association); + genLoadSlotsourceRegdestReg(ValueIndex, TempReg, freeReg); + ssPushRegister(freeReg); return 0; } static sqInt genPushLiteral(sqInt literal) { - annotateobjRef(gPushCw(literal), literal); - return 0; + return ssPushConstant(literal); } static sqInt @@ -9125,14 +9626,16 @@ AbstractInstruction *jmpSingle; assert(needsFrame); + ssAllocateCallRegand(ReceiverResultReg, SendNumArgsReg); + ensureReceiverResultRegContainsSelf(); + if ((registerMaskFor(ReceiverResultReg)) & callerSavedRegMask) { + (optStatus.isReceiverResultRegLive = 0); + } if (slotIndex == InstructionPointerIndex) { - gMoveMwrR(FoxMFReceiver, FPReg, ReceiverResultReg); gMoveCqR(slotIndex, SendNumArgsReg); CallRT(ceFetchContextInstVarTrampoline); - gPushR(SendNumArgsReg); - return 0; + return ssPushRegister(SendNumArgsReg); } - gMoveMwrR(FoxMFReceiver, FPReg, ReceiverResultReg); genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); jmpSingle = genJumpNotSmallIntegerInScratchReg(TempReg); gMoveCqR(slotIndex, SendNumArgsReg); @@ -9140,8 +9643,8 @@ jmpDone = gJump(0); jmpTarget(jmpSingle, gLabel()); genLoadSlotsourceRegdestReg(slotIndex, ReceiverResultReg, SendNumArgsReg); - jmpTarget(jmpDone, gPushR(SendNumArgsReg)); - return 0; + jmpTarget(jmpDone, gLabel()); + return ssPushRegister(SendNumArgsReg); } static sqInt @@ -9152,7 +9655,13 @@ sqInt size; assert(needsFrame); - popValues = byte1 > 127; + (optStatus.isReceiverResultRegLive = 0); + if ((popValues = byte1 > 127)) { + ssFlushTo(simStackPtr); + } + else { + ssAllocateCallRegand(SendNumArgsReg, ReceiverResultReg); + } size = byte1 & 127; gMoveCqR(size, SendNumArgsReg); CallRT(ceCreateNewArrayTrampoline); @@ -9161,9 +9670,9 @@ gPopR(TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(TempReg, i, ReceiverResultReg); } + ssPop(size); } - gPushR(ReceiverResultReg); - return 0; + return ssPushRegister(ReceiverResultReg); } static sqInt @@ -9175,14 +9684,7 @@ static sqInt genPushReceiverBytecode(void) { - if (needsFrame) { - gMoveMwrR(FoxMFReceiver, FPReg, TempReg); - gPushR(TempReg); - } - else { - gPushR(ReceiverResultReg); - } - return 0; + return ssPushDesc(simSelf); } static sqInt @@ -9194,26 +9696,113 @@ static sqInt genPushReceiverVariable(sqInt index) { - sqInt maybeErr; + ensureReceiverResultRegContainsSelf(); + return genSSPushSlotreg(index, ReceiverResultReg); +} - if (needsFrame) { - gMoveMwrR(FoxMFReceiver, FPReg, ReceiverResultReg); + +/* Ensure that the register args are pushed before the retpc for methods with + arity <= self numRegArgs. + */ +/* This won't be as clumsy on a RISC. But putting the receiver and + args above the return address means the CoInterpreter has a + single machine-code frame format which saves us a lot of work. */ + +static void +genPushRegisterArgs(void) +{ + if (!(regArgsHaveBeenPushed + || (methodOrBlockNumArgs > (numRegArgs())))) { + genPushRegisterArgsForNumArgs(methodOrBlockNumArgs); + regArgsHaveBeenPushed = 1; } - maybeErr = genLoadSlotsourceRegdestReg(index, ReceiverResultReg, TempReg); - if (maybeErr < 0) { - return maybeErr; +} + + +/* Ensure that the register args are pushed before the outer and + inner retpcs at an entry miss for arity <= self numRegArgs. The + outer retpc is that of a call at a send site. The inner is the call + from a method or PIC abort/miss to the trampoline. */ +/* This won't be as clumsy on a RISC. But putting the receiver and + args above the return address means the CoInterpreter has a + single machine-code frame format which saves us a lot of work. */ +/* Iff there are register args convert + base -> outerRetpc (send site retpc) + sp -> innerRetpc (PIC abort/miss retpc) + to + base -> receiver + (arg0) + (arg1) + outerRetpc + sp -> innerRetpc (PIC abort/miss retpc) */ + +static void +genPushRegisterArgsForAbortMissNumArgs(sqInt numArgs) +{ + if (numArgs <= (numRegArgs())) { + assert((numRegArgs()) <= 2); + if (numArgs == 0) { + gMoveMwrR(0, SPReg, TempReg); + gPushR(TempReg); + gMoveMwrR(BytesPerWord * 2, SPReg, TempReg); + gMoveRMwr(TempReg, BytesPerWord, SPReg); + gMoveRMwr(ReceiverResultReg, 2 * BytesPerWord, SPReg); + return; + } + if (numArgs == 1) { + gMoveMwrR(BytesPerWord, SPReg, TempReg); + gPushR(TempReg); + gMoveMwrR(BytesPerWord, SPReg, TempReg); + gPushR(TempReg); + gMoveRMwr(ReceiverResultReg, 3 * BytesPerWord, SPReg); + gMoveRMwr(Arg0Reg, 2 * BytesPerWord, SPReg); + return; + } + if (numArgs == 2) { + gPushR(Arg1Reg); + gMoveMwrR(BytesPerWord * 2, SPReg, TempReg); + gPushR(TempReg); + gMoveMwrR(BytesPerWord * 2, SPReg, TempReg); + gPushR(TempReg); + gMoveRMwr(ReceiverResultReg, 4 * BytesPerWord, SPReg); + gMoveRMwr(Arg0Reg, 3 * BytesPerWord, SPReg); + return; + } } - gPushR(TempReg); - return 0; } + +/* Ensure that the register args are pushed before the retpc for arity <= + self numRegArgs. + */ +/* This won't be as clumsy on a RISC. But putting the receiver and + args above the return address means the CoInterpreter has a + single machine-code frame format which saves us a lot of work. */ + +static void +genPushRegisterArgsForNumArgs(sqInt numArgs) +{ + if (numArgs <= (numRegArgs())) { + gMoveMwrR(0, SPReg, TempReg); + gMoveRMwr(ReceiverResultReg, 0, SPReg); + assert((numRegArgs()) <= 2); + if (numArgs > 0) { + gPushR(Arg0Reg); + if (numArgs > 1) { + gPushR(Arg1Reg); + } + } + gPushR(TempReg); + } +} + static sqInt genPushRemoteTempLongBytecode(void) { + ssAllocateRequiredRegand(ClassReg, SendNumArgsReg); gMoveMwrR(frameOffsetOfTemporary(byte2), FPReg, ClassReg); - genLoadSlotsourceRegdestReg(byte1, ClassReg, TempReg); - gPushR(TempReg); - return 0; + genLoadSlotsourceRegdestReg(byte1, ClassReg, SendNumArgsReg); + return ssPushRegister(SendNumArgsReg); } static sqInt @@ -9225,9 +9814,7 @@ static sqInt genPushTemporaryVariable(sqInt index) { - gMoveMwrR(frameOffsetOfTemporary(index), FPReg, TempReg); - gPushR(TempReg); - return 0; + return ssPushDesc(simStack[index]); } @@ -9374,8 +9961,8 @@ genReturnTopFromBlock(void) { assert(inBlock); - flag("currently caller pushes result"); - gPopR(ReceiverResultReg); + popToReg(ssTop(), ReceiverResultReg); + ssPop(1); if (needsFrame) { gMoveRR(FPReg, SPReg); gPopR(FPReg); @@ -9384,16 +9971,11 @@ return 0; } - -/* Return pops receiver and arguments off the stack. Callee pushes the - result. - */ - static sqInt genReturnTopFromMethod(void) { - flag("currently caller pushes result"); - gPopR(ReceiverResultReg); + popToReg(ssTop(), ReceiverResultReg); + ssPop(1); return genUpArrowReturn(); } @@ -9476,37 +10058,32 @@ static sqInt genSendSupernumArgs(sqInt selector, sqInt numArgs) { - assert(needsFrame); - if (isYoung(selector)) { - hasYoungReferent = 1; - } - gMoveMwrR(numArgs * BytesPerWord, SPReg, ReceiverResultReg); - if (numArgs > 2) { - gMoveCqR(numArgs, SendNumArgsReg); - } - gMoveCwR(selector, ClassReg); - CallSend(superSendTrampolines[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]); - flag("currently caller pushes result"); - gPushR(ReceiverResultReg); - return 0; + marshallSendArguments(numArgs); + return genMarshalledSendSupernumArgs(selector, numArgs); } + +/* Generate a trampoline with four arguments. + Hack: a negative value indicates an abstract register, a non-negative + value indicates a constant. */ + static sqInt +genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3) +{ + sqInt startAddress; + + startAddress = methodZoneBase; + opcodeIndex = 0; + genPushRegisterArgsForNumArgs(numArgs); + genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(aRoutine, aString, 1, 4, regOrConst0, regOrConst1, regOrConst2, regOrConst3, 0, null, 1); + return startAddress; +} + +static sqInt genSendnumArgs(sqInt selector, sqInt numArgs) { - if (isYoung(selector)) { - hasYoungReferent = 1; - } - assert(needsFrame); - gMoveMwrR(numArgs * BytesPerWord, SPReg, ReceiverResultReg); - if (numArgs > 2) { - gMoveCqR(numArgs, SendNumArgsReg); - } - gMoveCwR(selector, ClassReg); - CallSend(sendTrampolines[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]); - flag("currently caller pushes result"); - gPushR(ReceiverResultReg); - return 0; + marshallSendArguments(numArgs); + return genMarshalledSendnumArgs(selector, numArgs); } static sqInt @@ -9538,55 +10115,421 @@ return genJumpTo(target); } - -/* Stack looks like - receiver (also in ResultReceiverReg) - arg - return address */ - static sqInt genSmallIntegerComparison(sqInt jumpOpcode) { AbstractInstruction *jumpFail; AbstractInstruction *jumpTrue; - gMoveMwrR(BytesPerWord, SPReg, TempReg); - gMoveRR(TempReg, ClassReg); + gMoveRR(Arg0Reg, TempReg); jumpFail = genJumpNotSmallIntegerInScratchReg(TempReg); - gCmpRR(ClassReg, ReceiverResultReg); + gCmpRR(Arg0Reg, ReceiverResultReg); jumpTrue = gen(jumpOpcode); annotateobjRef(gMoveCwR(falseObject(), ReceiverResultReg), falseObject()); - flag("currently caller pushes result"); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpTrue, annotateobjRef(gMoveCwR(trueObject(), ReceiverResultReg), trueObject())); - gRetN(BytesPerWord * 2); + gRetN(0); jmpTarget(jumpFail, gLabel()); return 0; } static sqInt +genSpecialSelectorArithmetic(void) +{ + sqInt annotateInst; + sqInt argInt; + sqInt argIsConst; + sqInt argIsInt; + AbstractInstruction *instToAnnotate; + AbstractInstruction *jumpContinue; + AbstractInstruction *jumpNotSmallInts; + BytecodeDescriptor *primDescriptor; + sqInt rcvrInt; + sqInt rcvrIsConst; + sqInt rcvrIsInt; + sqInt result; + + primDescriptor = generatorAt(byte0); + argIsInt = ((argIsConst = ((ssTop()->type)) == SSConstant)) + && ((((argInt = (ssTop()->constant))) & 1)); + rcvrIsInt = ((rcvrIsConst = ((ssValue(1)->type)) == SSConstant)) + && ((((rcvrInt = (ssValue(1)->constant))) & 1)); + if (argIsInt + && (rcvrIsInt)) { + rcvrInt = (rcvrInt >> 1); + argInt = (argInt >> 1); + + switch ((primDescriptor->opcode)) { + case AddRR: + result = rcvrInt + argInt; + break; + case SubRR: + result = rcvrInt - argInt; + break; + case AndRR: + result = rcvrInt & argInt; + break; + case OrRR: + result = rcvrInt | argInt; + break; + default: + error("Case not found and no otherwise clause"); + } + if (isIntegerValue(result)) { + if ((ssValue(1)->annotateUse)) { + annotateBytecode((prevInstIsPCAnnotated() + ? gNop() + : gLabel())); + } + if ((ssTop()->annotateUse)) { + annotateBytecode((prevInstIsPCAnnotated() + ? gNop() + : gLabel())); + } + return ssPop(2),ssPushAnnotatedConstant(((result << 1) | 1)); + } + return genSpecialSelectorSend(); + } + if ((rcvrIsConst + && (!rcvrIsInt)) + || (argIsConst + && (!argIsInt))) { + return genSpecialSelectorSend(); + } + if (!(argIsInt + || (rcvrIsInt))) { + return genSpecialSelectorSend(); + } + if (argIsInt) { + ssFlushTo(simStackPtr - 2); + popToReg(ssValue(1), ReceiverResultReg); + annotateInst = (ssTop()->annotateUse); + ssPop(2); + gMoveRR(ReceiverResultReg, TempReg); + } + else { + marshallSendArguments(1); + gMoveRR(Arg0Reg, TempReg); + if (!(rcvrIsInt)) { + if (isSmallIntegerTagNonZero()) { + gAndRR(ReceiverResultReg, TempReg); + } + else { + gOrRR(ReceiverResultReg, TempReg); + } + } + } + jumpNotSmallInts = genJumpNotSmallIntegerInScratchReg(TempReg); + + switch ((primDescriptor->opcode)) { + case AddRR: + if (argIsInt) { + instToAnnotate = gAddCqR(argInt - ConstZero, ReceiverResultReg); + + /* overflow; must undo the damage before continuing */ + + jumpContinue = gJumpNoOverflow(0); + gSubCqR(argInt - ConstZero, ReceiverResultReg); + } + else { + genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); + gAddRR(Arg0Reg, ReceiverResultReg); + + /* overflow; must undo the damage before continuing */ + + jumpContinue = gJumpNoOverflow(0); + if (rcvrIsInt) { + gMoveCqR(rcvrInt, ReceiverResultReg); + } + else { + gSubRR(Arg0Reg, ReceiverResultReg); + genSetSmallIntegerTagsIn(ReceiverResultReg); + } + } + break; + case SubRR: + if (argIsInt) { + instToAnnotate = gSubCqR(argInt - ConstZero, ReceiverResultReg); + + /* overflow; must undo the damage before continuing */ + + jumpContinue = gJumpNoOverflow(0); + gAddCqR(argInt - ConstZero, ReceiverResultReg); + } + else { + genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); + gSubRR(Arg0Reg, ReceiverResultReg); + + /* overflow; must undo the damage before continuing */ + + jumpContinue = gJumpNoOverflow(0); + gAddRR(Arg0Reg, ReceiverResultReg); + genSetSmallIntegerTagsIn(Arg0Reg); + } + break; + case AndRR: + if (argIsInt) { + instToAnnotate = gAndCqR(argInt, ReceiverResultReg); + } + else { + gAndRR(Arg0Reg, ReceiverResultReg); + } + jumpContinue = gJump(0); + break; + case OrRR: + if (argIsInt) { + instToAnnotate = gOrCqR(argInt, ReceiverResultReg); + } + else { + gOrRR(Arg0Reg, ReceiverResultReg); + } + jumpContinue = gJump(0); + break; + default: + error("Case not found and no otherwise clause"); + } + jmpTarget(jumpNotSmallInts, gLabel()); + if (argIsInt) { + if (annotateInst) { + annotateBytecode(instToAnnotate); + } + gMoveCqR(argInt, Arg0Reg); + } + genMarshalledSendnumArgs(specialSelector(byte0 - 176), 1); + jmpTarget(jumpContinue, gLabel()); + return 0; +} + +static sqInt genSpecialSelectorClass(void) { - gMoveMwrR(0, SPReg, SendNumArgsReg); + ssPop(1); + ssAllocateRequiredRegand(SendNumArgsReg, ClassReg); + ssPush(1); + popToReg(ssTop(), SendNumArgsReg); genGetClassObjectOfintoscratchReg(SendNumArgsReg, ClassReg, TempReg); - gMoveRMwr(ClassReg, 0, SPReg); - return 0; + return ssPop(1),ssPushRegister(ClassReg); } static sqInt +genSpecialSelectorComparison(void) +{ + sqInt annotateInst; + sqInt argInt; + sqInt argIsInt; + sqInt branchBytecode; + BytecodeDescriptor *branchDescriptor; + sqInt branchPC; + sqInt inlineCAB; + AbstractInstruction *jumpNotSmallInts; + sqInt postBranchPC; + BytecodeDescriptor *primDescriptor; + sqInt rcvrInt; + sqInt rcvrIsInt; + sqInt result; + sqInt targetBytecodePC; + + ssFlushTo(simStackPtr - 2); + primDescriptor = generatorAt(byte0); + argIsInt = (((ssTop()->type)) == SSConstant) + && ((((argInt = (ssTop()->constant))) & 1)); + rcvrIsInt = (((ssValue(1)->type)) == SSConstant) + && ((((rcvrInt = (ssValue(1)->constant))) & 1)); + if (argIsInt + && (rcvrIsInt)) { + ; + + switch ((primDescriptor->opcode)) { + case JumpLess: + result = rcvrInt < argInt; + break; + case JumpLessOrEqual: + result = rcvrInt <= argInt; + break; + case JumpGreater: + result = rcvrInt > argInt; + break; + case JumpGreaterOrEqual: + result = rcvrInt >= argInt; + break; + case JumpZero: + result = rcvrInt == argInt; + break; + case JumpNonZero: + result = rcvrInt != argInt; + break; + default: + error("Case not found and no otherwise clause"); + } + if ((ssValue(1)->annotateUse)) { + annotateBytecode((prevInstIsPCAnnotated() + ? gNop() + : gLabel())); + } + if ((ssTop()->annotateUse)) { + annotateBytecode((prevInstIsPCAnnotated() + ? gNop() + : gLabel())); + } + ssPop(2); + return ssPushAnnotatedConstant((result + ? trueObject() + : falseObject())); + } + branchPC = bytecodePointer + ((primDescriptor->numBytes)); + branchBytecode = fetchByteofObject(branchPC, methodObj); + + /* Only interested in inlining if followed by a conditional branch. */ + + branchDescriptor = generatorAt(branchBytecode); + + /* Further, only interested in inlining = and ~= if there's a SmallInteger constant involved. + The relational operators successfully staticaly predict SmallIntegers; the equality operators do not. */ + + inlineCAB = ((branchDescriptor->isBranchTrue)) + || ((branchDescriptor->isBranchFalse)); + if (inlineCAB + && ((((primDescriptor->opcode)) == JumpZero) + || (((primDescriptor->opcode)) == JumpNonZero))) { + inlineCAB = argIsInt + || (rcvrIsInt); + } + if (!(inlineCAB)) { + return genSpecialSelectorSend(); + } + targetBytecodePC = (branchPC + ((branchDescriptor->numBytes))) + (spanForatbyte0in(branchDescriptor, branchPC, branchBytecode, methodObj)); + postBranchPC = branchPC + ((branchDescriptor->numBytes)); + if (argIsInt) { + ssFlushTo(simStackPtr - 2); + popToReg(ssValue(1), ReceiverResultReg); + annotateInst = (ssTop()->annotateUse); + ssPop(2); + gMoveRR(ReceiverResultReg, TempReg); + } + else { + marshallSendArguments(1); + gMoveRR(Arg0Reg, TempReg); + if (!(rcvrIsInt)) { + if (isSmallIntegerTagNonZero()) { + gAndRR(ReceiverResultReg, TempReg); + } + else { + gOrRR(ReceiverResultReg, TempReg); + } + } + } + jumpNotSmallInts = genJumpNotSmallIntegerInScratchReg(TempReg); + if (argIsInt) { + if (annotateInst) { + annotateBytecode(gCmpCqR(argInt, ReceiverResultReg)); + } + else { + gCmpCqR(argInt, ReceiverResultReg); + } + } + else { + gCmpRR(Arg0Reg, ReceiverResultReg); + } + genoperand(((branchDescriptor->isBranchTrue) + ? (primDescriptor->opcode) + : inverseBranchFor((primDescriptor->opcode))), ((usqInt)(ensureNonMergeFixupAt(targetBytecodePC - initialPC)))); + gJump(ensureNonMergeFixupAt(postBranchPC - initialPC)); + jmpTarget(jumpNotSmallInts, gLabel()); + if (argIsInt) { + gMoveCqR(argInt, Arg0Reg); + } + return genMarshalledSendnumArgs(specialSelector(byte0 - 176), 1); +} + +static sqInt genSpecialSelectorEqualsEquals(void) { + sqInt argReg; + sqInt branchBytecode; + BytecodeDescriptor *branchDescriptor; + AbstractInstruction *jumpEqual; AbstractInstruction *jumpNotEqual; - AbstractInstruction *jumpPush; + sqInt nextPC; + sqInt postBranchPC; + BytecodeDescriptor *primDescriptor; + sqInt rcvrReg; + sqInt resultReg; + sqInt targetBytecodePC; - gPopR(TempReg); - gMoveMwrR(0, SPReg, ClassReg); - gCmpRR(TempReg, ClassReg); - jumpNotEqual = gJumpNonZero(0); - annotateobjRef(gMoveCwR(trueObject(), TempReg), trueObject()); - jumpPush = gJump(0); - jmpTarget(jumpNotEqual, annotateobjRef(gMoveCwR(falseObject(), TempReg), falseObject())); - jmpTarget(jumpPush, gMoveRMwr(TempReg, 0, SPReg)); + flag("rewrite this crap."); + ssPop(2); + resultReg = availableRegisterOrNil(); + if (!(resultReg)) { + if (((numRegArgs()) > 1) + && ((!needsFrame) + && (methodOrBlockNumArgs == 2))) { + halt(); + } + ssAllocateRequiredReg(resultReg = Arg1Reg); + } + ssPush(2); + if ((((ssTop()->type)) == SSConstant) + && (!((ssTop()->spilled)))) { + if (((ssValue(1)->type)) == SSRegister) { + + /* if spilled we must generate a real pop */ + + rcvrReg = (ssValue(1)->registerr); + } + else { + popToReg(ssValue(1), rcvrReg = resultReg); + } + if (shouldAnnotateObjectReference((ssTop()->constant))) { + annotateobjRef(gCmpCwR((ssTop()->constant), rcvrReg), (ssTop()->constant)); + } + else { + gCmpCqR((ssTop()->constant), rcvrReg); + } + ssPop(1); + } + else { + argReg = ssStorePoptoPreferredReg(1, TempReg); + rcvrReg = (argReg == resultReg + ? TempReg + : resultReg); + popToReg(ssTop(), rcvrReg); + gCmpRR(argReg, rcvrReg); + } + ssPop(1); + ssPushRegister(resultReg); + primDescriptor = generatorAt(byte0); + nextPC = bytecodePointer + ((primDescriptor->numBytes)); + branchBytecode = fetchByteofObject(nextPC, methodObj); + branchDescriptor = generatorAt(branchBytecode); + if (((branchDescriptor->isBranchTrue)) + || ((branchDescriptor->isBranchFalse))) { + ssFlushTo(simStackPtr - 1); + targetBytecodePC = (nextPC + ((branchDescriptor->numBytes))) + (spanForatbyte0in(branchDescriptor, nextPC, branchBytecode, methodObj)); + postBranchPC = nextPC + ((branchDescriptor->numBytes)); + if (((fixupAt(nextPC - initialPC)->targetInstruction)) == 0) { + + /* The next instruction is dead. we can skip it. */ + + deadCode = 1; + ssPop(1); + ensureFixupAt(targetBytecodePC - initialPC); + ensureFixupAt(postBranchPC - initialPC); + } + genoperand(((branchDescriptor->isBranchTrue) + ? JumpZero + : JumpNonZero), ((usqInt)(ensureNonMergeFixupAt(targetBytecodePC - initialPC)))); + gJump(ensureNonMergeFixupAt(postBranchPC - initialPC)); + } + else { + jumpNotEqual = gJumpNonZero(0); + annotateobjRef(gMoveCwR(trueObject(), resultReg), trueObject()); + jumpEqual = gJump(0); + jmpTarget(jumpNotEqual, annotateobjRef(gMoveCwR(falseObject(), resultReg), falseObject())); + jmpTarget(jumpEqual, gLabel()); + } + if (resultReg == ReceiverResultReg) { + (optStatus.isReceiverResultRegLive = 0); + } return 0; } @@ -9604,6 +10547,12 @@ } static sqInt +genSSPushSlotreg(sqInt index, sqInt baseReg) +{ + return ssPushBaseoffset(baseReg, slotOffsetOfInstVarIndex(index)); +} + +static sqInt genStoreAndPopReceiverVariableBytecode(void) { return genStorePopReceiverVariable(1, byte0 & 7); @@ -9631,23 +10580,56 @@ } static sqInt +genStoreImmediateInSourceRegslotIndexdestReg(sqInt sourceReg, sqInt index, sqInt destReg) +{ + gMoveRMwr(sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); + return 0; +} + +static sqInt genStorePopLiteralVariable(sqInt popBoolean, sqInt litVarIndex) { sqInt association; + sqInt constVal; + sqInt topReg; + sqInt valueReg; + flag("with better register allocation this wouldn't need a frame. e.g. use SendNumArgs instead of ReceiverResultReg"); assert(needsFrame); + (optStatus.isReceiverResultRegLive = 0); association = literalofMethod(litVarIndex, methodObj); - annotateobjRef(gMoveCwR(association, ReceiverResultReg), association); - if (popBoolean) { - gPopR(ClassReg); + + /* Avoid store check for immediate values */ + + constVal = maybeConstant(ssTop()); + if ((((ssTop()->type)) == SSConstant) + && (!(shouldAnnotateObjectReference(constVal)))) { + ssAllocateRequiredReg(ReceiverResultReg); + annotateobjRef(gMoveCwR(association, ReceiverResultReg), association); + ssStorePoptoPreferredReg(popBoolean, TempReg); + if (traceStores > 0) { + CallRT(ceTraceStoreTrampoline); + } + return genStoreImmediateInSourceRegslotIndexdestReg(TempReg, ValueIndex, ReceiverResultReg); } - else { - gMoveMwrR(0, SPReg, ClassReg); + if ((((topReg = registerOrNil(ssTop()))) == null) + || (topReg == ReceiverResultReg)) { + topReg = ClassReg; } + ssPop(1); + ssAllocateCallReg(topReg); + ssPush(1); + valueReg = ssStorePoptoPreferredReg(popBoolean, topReg); + if (valueReg == ReceiverResultReg) { + gMoveRR(valueReg, topReg); + } + ssAllocateCallReg(ReceiverResultReg); + annotateobjRef(gMoveCwR(association, ReceiverResultReg), association); if (traceStores > 0) { + gMoveRR(topReg, TempReg); CallRT(ceTraceStoreTrampoline); } - return genStoreSourceRegslotIndexdestRegscratchReg(ClassReg, ValueIndex, ReceiverResultReg, TempReg); + return genStoreSourceRegslotIndexdestRegscratchReg(topReg, ValueIndex, ReceiverResultReg, TempReg); } static sqInt @@ -9655,72 +10637,122 @@ { AbstractInstruction *jmpDone; AbstractInstruction *jmpSingle; + sqInt valueReg; assert(needsFrame); - gMoveMwrR(FoxMFReceiver, FPReg, ReceiverResultReg); + ssFlushUpThroughReceiverVariable(slotIndex); + ensureReceiverResultRegContainsSelf(); + ssPop(1); + ssAllocateCallRegand(ClassReg, SendNumArgsReg); + ssPush(1); genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); - gMoveMwrR(0, SPReg, ClassReg); + valueReg = ssStorePoptoPreferredReg(popBoolean, ClassReg); + if (valueReg != ClassReg) { + gMoveRR(valueReg, ClassReg); + } jmpSingle = genJumpNotSmallIntegerInScratchReg(TempReg); gMoveCqR(slotIndex, SendNumArgsReg); CallRT(ceStoreContextInstVarTrampoline); jmpDone = gJump(0); jmpTarget(jmpSingle, gLabel()); if (traceStores > 0) { + gMoveRR(ClassReg, TempReg); CallRT(ceTraceStoreTrampoline); } genStoreSourceRegslotIndexdestRegscratchReg(ClassReg, slotIndex, ReceiverResultReg, TempReg); jmpTarget(jmpDone, gLabel()); - if (popBoolean) { - gAddCqR(BytesPerWord, SPReg); - } return 0; } static sqInt genStorePopReceiverVariable(sqInt popBoolean, sqInt slotIndex) { - if (needsFrame) { - gMoveMwrR(FoxMFReceiver, FPReg, ReceiverResultReg); + sqInt constVal; + sqInt topReg; + sqInt valueReg; + + ssFlushUpThroughReceiverVariable(slotIndex); + constVal = maybeConstant(ssTop()); + if ((((ssTop()->type)) == SSConstant) + && (!(shouldAnnotateObjectReference(constVal)))) { + ensureReceiverResultRegContainsSelf(); + ssStorePoptoPreferredReg(popBoolean, TempReg); + if (traceStores > 0) { + CallRT(ceTraceStoreTrampoline); + } + return genStoreImmediateInSourceRegslotIndexdestReg(TempReg, slotIndex, ReceiverResultReg); } - if (popBoolean) { - gPopR(ClassReg); + if ((((topReg = registerOrNil(ssTop()))) == null) + || (topReg == ReceiverResultReg)) { + topReg = ClassReg; } - else { - gMoveMwrR(0, SPReg, ClassReg); + ssPop(1); + ssAllocateCallReg(topReg); + ssPush(1); + valueReg = ssStorePoptoPreferredReg(popBoolean, topReg); + if (valueReg == ReceiverResultReg) { + gMoveRR(valueReg, topReg); } + ensureReceiverResultRegContainsSelf(); if (traceStores > 0) { + gMoveRR(topReg, TempReg); CallRT(ceTraceStoreTrampoline); } - return genStoreSourceRegslotIndexdestRegscratchReg(ClassReg, slotIndex, ReceiverResultReg, TempReg); + return genStoreSourceRegslotIndexdestRegscratchReg(topReg, slotIndex, ReceiverResultReg, TempReg); } static sqInt genStorePopRemoteTempAt(sqInt popBoolean, sqInt slotIndex, sqInt remoteTempIndex) { + sqInt constVal; + sqInt topReg; + sqInt valueReg; + assert(needsFrame); - if (popBoolean) { - gPopR(ClassReg); + (optStatus.isReceiverResultRegLive = 0); + constVal = maybeConstant(ssTop()); + if ((((ssTop()->type)) == SSConstant) + && (!(shouldAnnotateObjectReference(constVal)))) { + ssAllocateRequiredReg(ReceiverResultReg); + gMoveMwrR(frameOffsetOfTemporary(remoteTempIndex), FPReg, ReceiverResultReg); + ssStorePoptoPreferredReg(popBoolean, TempReg); + if (traceStores > 0) { + CallRT(ceTraceStoreTrampoline); + } + return genStoreImmediateInSourceRegslotIndexdestReg(TempReg, slotIndex, ReceiverResultReg); } - else { - gMoveMwrR(0, SPReg, ClassReg); + if ((((topReg = registerOrNil(ssTop()))) == null) + || (topReg == ReceiverResultReg)) { + topReg = ClassReg; } + ssPop(1); + ssAllocateCallReg(topReg); + ssPush(1); + valueReg = ssStorePoptoPreferredReg(popBoolean, topReg); + if (valueReg == ReceiverResultReg) { + gMoveRR(valueReg, topReg); + } + if (!(popBoolean)) { + ssPop(1); + ssPushRegister(topReg); + } + ssAllocateCallReg(ReceiverResultReg); gMoveMwrR(frameOffsetOfTemporary(remoteTempIndex), FPReg, ReceiverResultReg); if (traceStores > 0) { + gMoveRR(topReg, TempReg); CallRT(ceTraceStoreTrampoline); } - return genStoreSourceRegslotIndexdestRegscratchReg(ClassReg, slotIndex, ReceiverResultReg, TempReg); + return genStoreSourceRegslotIndexdestRegscratchReg(topReg, slotIndex, ReceiverResultReg, TempReg); } static sqInt genStorePopTemporaryVariable(sqInt popBoolean, sqInt tempIndex) { - if (popBoolean) { - gPopR(TempReg); - } - else { - gMoveMwrR(0, SPReg, TempReg); - } - gMoveRMwr(TempReg, frameOffsetOfTemporary(tempIndex), FPReg); + sqInt reg; + + ssFlushUpThroughTemporaryVariable(tempIndex); + reg = ssStorePoptoPreferredReg(popBoolean, TempReg); + gMoveRMwr(reg, frameOffsetOfTemporary(tempIndex), FPReg); return 0; } @@ -9813,28 +10845,6 @@ } -/* Generate a trampoline with two arguments. - Hack: a negative value indicates an abstract register, a non-negative - value indicates a constant. */ - -static sqInt -genTrampolineForcalledargarg(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1) -{ - return genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(aRoutine, aString, 1, 2, regOrConst0, regOrConst1, null, null, 0, null, 0); -} - - -/* Generate a trampoline with four arguments. - Hack: a negative value indicates an abstract register, a non-negative - value indicates a constant. */ - -static sqInt -genTrampolineForcalledargargargarg(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3) -{ - return genTrampolineForcalledcallJumpBarnumArgsargargargargsaveRegsresultRegappendOpcodes(aRoutine, aString, 1, 4, regOrConst0, regOrConst1, regOrConst2, regOrConst3, 0, null, 0); -} - - /* Generate a trampoline with two arguments that answers a result. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ @@ -9904,7 +10914,6 @@ static sqInt genUpArrowReturn(void) { - flag("currently caller pushes result"); if (inBlock) { assert(needsFrame); annotateBytecode(CallRT(ceNonLocalReturnTrampoline)); @@ -9913,8 +10922,14 @@ if (needsFrame) { gMoveRR(FPReg, SPReg); gPopR(FPReg); + gRetN((methodOrBlockNumArgs + 1) * BytesPerWord); } - gRetN((methodOrBlockNumArgs + 1) * BytesPerWord); + else { + gRetN(((methodOrBlockNumArgs > (numRegArgs())) + || (regArgsHaveBeenPushed) + ? (methodOrBlockNumArgs + 1) * BytesPerWord + : 0)); + } return 0; } @@ -10140,6 +11155,7 @@ (methodLabel->opcode = Label); ((methodLabel->operands))[0] = 0; ((methodLabel->operands))[1] = 0; + callerSavedRegMask = callerSavedRegisterMask(backEnd); } void @@ -10164,6 +11180,9 @@ /* Make sure there's a flagged fixup at the targetIndex (pc relative to first pc) in fixups. + These are the targets of backward branches. A backward branch fixup's + simStackPtr needs to be set when generating the code for the bytecode at + the targetIndex. Initially a fixup's target is just a flag. Later on it is replaced with a proper instruction. */ @@ -10173,7 +11192,8 @@ BytecodeFixup *fixup; fixup = fixupAt(targetIndex); - (fixup->targetInstruction = ((AbstractInstruction *) 1)); + (fixup->targetInstruction = ((AbstractInstruction *) 2)); + (fixup->simStackPtr = -2); return fixup; } @@ -10204,7 +11224,125 @@ return 3; } +static void +initSimStackForFramefulMethod(sqInt startpc) +{ + CogSimStackEntry *desc; + sqInt i; + (optStatus.isReceiverResultRegLive = 0); + (simSelf.type = SSBaseOffset); + (simSelf.spilled = 1); + (simSelf.annotateUse = 0); + (simSelf.registerr = FPReg); + (simSelf.offset = FoxMFReceiver); + + /* N.B. Includes num args */ + + simSpillBase = methodOrBlockNumTemps; + + /* args */ + + simStackPtr = simSpillBase - 1; + for (i = 0; i <= (methodOrBlockNumArgs - 1); i += 1) { + desc = simStackAt(i); + (desc->type = SSBaseOffset); + (desc->spilled = 1); + (desc->annotateUse = 0); + (desc->registerr = FPReg); + (desc->offset = FoxCallerSavedIP + ((methodOrBlockNumArgs - i) * BytesPerWord)); + (desc->bcptr = startpc); + } + for (i = methodOrBlockNumArgs; i <= simStackPtr; i += 1) { + desc = simStackAt(i); + (desc->type = SSBaseOffset); + (desc->spilled = 1); + (desc->annotateUse = 0); + (desc->registerr = FPReg); + (desc->offset = FoxMFReceiver - (((i - methodOrBlockNumArgs) + 1) * BytesPerWord)); + (desc->bcptr = startpc); + } +} + + +/* The register receiver (he closure itself) and args are pushed by the + closure value primitive(s) + and hence a frameless block has all arguments and copied values pushed to + the stack. However, + the method receiver (self) is put in the ReceiverResultRegister by the + block entry. */ + +static void +initSimStackForFramelessBlock(sqInt startpc) +{ + CogSimStackEntry *desc; + sqInt i; + + (simSelf.type = SSRegister); + (simSelf.spilled = 0); + (simSelf.annotateUse = 0); + (simSelf.registerr = ReceiverResultReg); + (optStatus.isReceiverResultRegLive = 1); + (optStatus.ssEntry = (&simSelf)); + assert(methodOrBlockNumTemps >= methodOrBlockNumArgs); + assert((numRegArgs()) <= 2); + for (i = 0; i <= (methodOrBlockNumTemps - 1); i += 1) { + desc = simStackAt(i); + (desc->type = SSBaseOffset); + (desc->spilled = 1); + (desc->annotateUse = 0); + (desc->registerr = SPReg); + (desc->offset = (methodOrBlockNumTemps - i) * BytesPerWord); + (desc->bcptr = startpc); + } + simSpillBase = simStackPtr = methodOrBlockNumTemps - 1; +} + +static void +initSimStackForFramelessMethod(sqInt startpc) +{ + CogSimStackEntry *desc; + sqInt i; + + (simSelf.type = SSRegister); + (simSelf.spilled = 0); + (simSelf.annotateUse = 0); + (simSelf.registerr = ReceiverResultReg); + (optStatus.isReceiverResultRegLive = 1); + (optStatus.ssEntry = (&simSelf)); + assert(methodOrBlockNumTemps == methodOrBlockNumArgs); + assert((numRegArgs()) <= 2); + if (((methodOrBlockNumArgs >= 1) && (methodOrBlockNumArgs <= (numRegArgs())))) { + desc = simStackAt(0); + (desc->type = SSRegister); + (desc->spilled = 0); + (desc->annotateUse = 0); + (desc->registerr = Arg0Reg); + (desc->bcptr = startpc); + if (methodOrBlockNumArgs > 1) { + desc = simStackAt(1); + (desc->type = SSRegister); + (desc->spilled = 0); + (desc->annotateUse = 0); + (desc->registerr = Arg1Reg); + (desc->bcptr = startpc); + } + } + else { + for (i = 0; i <= (methodOrBlockNumArgs - 1); i += 1) { + desc = simStackAt(i); + (desc->type = SSBaseOffset); + (desc->registerr = SPReg); + (desc->spilled = 1); + (desc->annotateUse = 0); + (desc->offset = (methodOrBlockNumArgs - i) * BytesPerWord); + (desc->bcptr = startpc); + } + } + simSpillBase = simStackPtr = methodOrBlockNumArgs - 1; +} + + /* Answer the inline cache tag for the return address of a send. */ static sqInt @@ -10297,6 +11435,72 @@ } static sqInt +inverseBranchFor(sqInt opcode) +{ + + switch (opcode) { + case JumpLongZero: + return JumpLongNonZero; + + case JumpLongNonZero: + return JumpLongZero; + + case JumpZero: + return JumpNonZero; + + case JumpNonZero: + return JumpZero; + + case JumpNegative: + return JumpNonNegative; + + case JumpNonNegative: + return JumpNegative; + + case JumpOverflow: + return JumpNoOverflow; + + case JumpNoOverflow: + return JumpOverflow; + + case JumpCarry: + return JumpNoCarry; + + case JumpNoCarry: + return JumpCarry; + + case JumpLess: + return JumpGreaterOrEqual; + + case JumpGreaterOrEqual: + return JumpLess; + + case JumpGreater: + return JumpLessOrEqual; + + case JumpLessOrEqual: + return JumpGreater; + + case JumpBelow: + return JumpAboveOrEqual; + + case JumpAboveOrEqual: + return JumpBelow; + + case JumpAbove: + return JumpBelowOrEqual; + + case JumpBelowOrEqual: + return JumpAbove; + + default: + error("Case not found and no otherwise clause"); + } + error("invalid opcode for inverse"); + return 0; +} + +static sqInt isAFixup(AbstractInstruction * self_in_isAFixup, void *fixupOrAddress) { return addressIsInFixups(fixupOrAddress); @@ -10382,6 +11586,12 @@ || (((target >= methodZoneBase) && (target <= (zoneLimit())))); } +static sqInt +isSmallIntegerTagNonZero(void) +{ + return 1; +} + static AbstractInstruction * gJumpAboveOrEqual(void *jumpTarget) { @@ -10489,6 +11699,12 @@ } static AbstractInstruction * +gJumpNoOverflow(void *jumpTarget) +{ + return genoperand(JumpNoOverflow, ((sqInt)jumpTarget)); +} + +static AbstractInstruction * gJumpOverflow(void *jumpTarget) { return genoperand(JumpOverflow, ((sqInt)jumpTarget)); @@ -10727,7 +11943,33 @@ return ((((byteAt(followingAddress - 1)) << 24) + ((byteAt(followingAddress - 2)) << 16)) + ((byteAt(followingAddress - 3)) << 8)) + (byteAt(followingAddress - 4)); } +static sqInt +liveRegisters(void) +{ + sqInt i; + sqInt regsSet; + if (needsFrame) { + regsSet = 0; + } + else { + regsSet = registerMaskFor(ReceiverResultReg); + if ((methodOrBlockNumArgs <= (numRegArgs())) + && (methodOrBlockNumArgs > 0)) { + regsSet = regsSet | (registerMaskFor(Arg0Reg)); + if (((numRegArgs()) > 1) + && (methodOrBlockNumArgs > 1)) { + regsSet = regsSet | (registerMaskFor(Arg1Reg)); + } + } + } + for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= simStackPtr; i += 1) { + regsSet = regsSet | (registerMask(simStackAt(i))); + } + return regsSet; +} + + /* Answer the byte size of a MoveCwR opcode's corresponding machine code */ static sqInt @@ -11450,6 +12692,45 @@ return 0; } + +/* Spill everything on the simulated stack that needs spilling (that below + receiver and arguments). + Marshall receiver and arguments to stack and/or registers depending on arg + count. If the args don't fit in registers push receiver and args (spill + everything), but still assign + the receiver to ReceiverResultReg. */ + +static void +marshallSendArguments(sqInt numArgs) +{ + if (numArgs > (numRegArgs())) { + ssFlushTo(simStackPtr); + storeToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); + } + else { + ssFlushTo((simStackPtr - numArgs) - 1); + if (numArgs > 0) { + if (((numRegArgs()) > 1) + && (numArgs > 1)) { + ssAllocateRequiredRegupThrough(Arg0Reg, simStackPtr - 2); + ssAllocateRequiredRegupThrough(Arg1Reg, simStackPtr - 1); + } + else { + ssAllocateRequiredRegupThrough(Arg0Reg, simStackPtr - 1); + } + } + if (((numRegArgs()) > 1) + && (numArgs > 1)) { + popToReg(simStackAt(simStackPtr), Arg1Reg); + } + if (numArgs > 0) { + popToReg(simStackAt((simStackPtr - numArgs) + 1), Arg0Reg); + } + popToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); + } + ssPop(numArgs + 1); +} + usqInt maxCogMethodAddress(void) { @@ -11523,10 +12804,64 @@ : absPC); } + +/* Discard type information because of a control-flow merge. */ + +static void +mergeAtfrom(CogSimStackEntry * self_in_mergeAtfrom, sqInt baseOffset, sqInt baseRegister) +{ + assert((self_in_mergeAtfrom->spilled)); + if (((self_in_mergeAtfrom->type)) == SSSpill) { + assert((((self_in_mergeAtfrom->offset)) == baseOffset) + && (((self_in_mergeAtfrom->registerr)) == baseRegister)); + } + else { + (self_in_mergeAtfrom->type) = SSSpill; + (self_in_mergeAtfrom->offset) = baseOffset; + (self_in_mergeAtfrom->registerr) = baseRegister; + } +} + + +/* Merge control flow at a fixup. The fixup holds the simStackPtr at the jump + to this target. + See stackToRegisterMapping on the class side for a full description. */ + +static void +mergeafterReturn(BytecodeFixup *fixup, sqInt mergeFollowsReturn) +{ + sqInt i; + + traceMerge(fixup); + (optStatus.isReceiverResultRegLive = 0); + if (mergeFollowsReturn) { + assert((((usqInt)((fixup->targetInstruction)))) >= 2); + simStackPtr = (fixup->simStackPtr); + } + if ((((usqInt)((fixup->targetInstruction)))) <= 2) { + ssFlushTo(simStackPtr); + if (((fixup->simStackPtr)) <= -2) { + (fixup->simStackPtr = simStackPtr); + } + (fixup->targetInstruction = gLabel()); + } + assert(simStackPtr >= ((fixup->simStackPtr))); + ; + simStackPtr = (fixup->simStackPtr); + + /* For now throw away all type information for values on the stack, but sometime consider + the more sophisticated merge described in the class side stackToRegisterMapping. */ + + simSpillBase = methodOrBlockNumTemps; + for (i = methodOrBlockNumTemps; i <= simStackPtr; i += 1) { + mergeAtfrom(simStackAt(i), FoxMFReceiver - (((i - methodOrBlockNumArgs) + 1) * BytesPerOop), FPReg); + } +} + static sqInt methodAbortTrampolineFor(sqInt numArgs) { - return ceMethodAbortTrampoline; + return methodAbortTrampolines[((numArgs < ((numRegArgs()) + 1)) ? numArgs : ((numRegArgs()) + 1))]; } static CogMethod * @@ -11581,6 +12916,12 @@ return genoperand(NegateR, reg); } +static AbstractInstruction * +gNop(void) +{ + return gen(Nop); +} + static sqInt needsFrameIfInBlock(sqInt isInBlock) { @@ -11899,7 +13240,7 @@ static sqInt picAbortTrampolineFor(sqInt numArgs) { - return cePICAbortTrampoline; + return picAbortTrampolines[((numArgs < ((numRegArgs()) + 1)) ? numArgs : ((numRegArgs()) + 1))]; } @@ -11927,7 +13268,71 @@ } } +static void +popToReg(CogSimStackEntry * self_in_popToReg, sqInt reg) +{ + AbstractInstruction *inst; + if ((self_in_popToReg->spilled)) { + inst = gPopR(reg); + } + else { + + switch ((self_in_popToReg->type)) { + case SSBaseOffset: + inst = gMoveMwrR((self_in_popToReg->offset), (self_in_popToReg->registerr), reg); + break; + case SSConstant: + inst = (shouldAnnotateObjectReference((self_in_popToReg->constant)) + ? annotateobjRef(gMoveCwR((self_in_popToReg->constant), reg), (self_in_popToReg->constant)) + : gMoveCqR((self_in_popToReg->constant), reg)); + break; + case SSRegister: + inst = (reg != ((self_in_popToReg->registerr)) + ? gMoveRR((self_in_popToReg->registerr), reg) + : gLabel()); + break; + default: + error("Case not found and no otherwise clause"); + } + } + if ((self_in_popToReg->annotateUse)) { + annotateBytecode(inst); + (self_in_popToReg->annotateUse) = 0; + } +} + +static sqInt +prevInstIsPCAnnotated(void) +{ + InstructionAnnotation *annotation; + sqInt prevIndex; + AbstractInstruction *prevInst; + + if (!(annotationIndex > 0)) { + return 0; + } + annotation = (&(annotations[annotationIndex - 1])); + if (!((((annotation->annotation)) == IsSendCall) + || (((annotation->annotation)) == HasBytecodePC))) { + return 0; + } + prevIndex = opcodeIndex - 1; + while (1) { + if (prevIndex <= 0) { + return 0; + } + prevInst = abstractInstructionAt(prevIndex); + if (((annotation->instruction)) == prevInst) { + return 1; + } + if (!(((prevInst->opcode)) == Label)) break; + prevIndex -= 1; + } + return 0; +} + + /* If there is a generator for the current primitive then answer it; otherwise answer nil. */ @@ -12115,16 +13520,92 @@ } -/* Dummy implementation for CogFooCompiler>callerSavedRegisterMask - which doesn't get pruned due to Slang limitations. */ +/* Answer a bit mask for the receiver's register, if any. */ static sqInt +registerMask(CogSimStackEntry * self_in_registerMask) +{ + return ((((self_in_registerMask->type)) == SSBaseOffset) + || (((self_in_registerMask->type)) == SSRegister) + ? registerMaskFor((self_in_registerMask->registerr)) + : 0); +} + + +/* Answer a bit mask identifying the symbolic register. + Registers are negative numbers. */ + +static sqInt +registerMaskFor(sqInt reg) +{ + return (((1 - reg) < 0) ? ((usqInt) 1 >> -(1 - reg)) : ((usqInt) 1 << (1 - reg))); +} + + +/* Answer a bit mask identifying the symbolic registers. + Registers are negative numbers. */ + +static sqInt +registerMaskForand(sqInt reg1, sqInt reg2) +{ + return ((((1 - reg1) < 0) ? ((usqInt) 1 >> -(1 - reg1)) : ((usqInt) 1 << (1 - reg1)))) | ((((1 - reg2) < 0) ? ((usqInt) 1 >> -(1 - reg2)) : ((usqInt) 1 << (1 - reg2)))); +} + + +/* Answer a bit mask identifying the symbolic registers. + Registers are negative numbers. */ + +static sqInt registerMaskForandand(sqInt reg1, sqInt reg2, sqInt reg3) { - return 0; + return (((((1 - reg1) < 0) ? ((usqInt) 1 >> -(1 - reg1)) : ((usqInt) 1 << (1 - reg1)))) | ((((1 - reg2) < 0) ? ((usqInt) 1 >> -(1 - reg2)) : ((usqInt) 1 << (1 - reg2))))) | ((((1 - reg3) < 0) ? ((usqInt) 1 >> -(1 - reg3)) : ((usqInt) 1 << (1 - reg3)))); } +static sqInt +registerOrNil(CogSimStackEntry * self_in_registerOrNil) +{ + return (((self_in_registerOrNil->type)) == SSRegister + ? (self_in_registerOrNil->registerr) + : 0); +} + + +/* When a block must be recompiled due to overestimating the + numInitialNils fixups must be restored, which means rescannning + since backward branches need their targets initialized. */ + static void +reinitializeFixupsFromthrough(sqInt start, sqInt end) +{ + BytecodeFixup * cascade0; + BytecodeDescriptor *descriptor; + sqInt distance; + sqInt pc; + sqInt targetPC; + + pc = start; + while (pc <= end) { + cascade0 = fixupAt(pc - initialPC); + (cascade0->targetInstruction = 0); + (cascade0->simStackPtr = null); + byte0 = fetchByteofObject(pc, methodObj); + descriptor = generatorAt(byte0); + if ((descriptor->isBackwardBranch)) { + distance = spanForatbyte0in(descriptor, pc, byte0, methodObj); + targetPC = (pc + ((descriptor->numBytes))) + distance; + initializeFixupAt(targetPC - initialPC); + } + if ((descriptor->isBlockCreation)) { + distance = spanForatbyte0in(descriptor, pc, byte0, methodObj); + pc = (pc + ((descriptor->numBytes))) + distance; + } + else { + pc += (descriptor->numBytes); + } + } +} + +static void relocateAndPruneYoungReferrers(void) { CogMethod *cogMethod; @@ -12414,12 +13895,21 @@ } -/* See the subclass for explanation. */ +/* We must ensure the ReceiverResultReg is live across the store check so + that we can store into receiver inst vars in a frameless method since self + exists only in ReceiverResultReg in a frameless method. So if + ReceiverResultReg is + caller-saved we use the fact that ceStoreCheck: answers its argument to + reload ReceiverResultReg cheaply. Otherwise we don't care about the result + and use the cResultRegister, effectively a no-op (see + compileTrampoline...) */ static sqInt returnRegForStoreCheck(void) { - return cResultRegister(backEnd); + return ((registerMaskFor(ReceiverResultReg)) & callerSavedRegMask + ? ReceiverResultReg + : cResultRegister(backEnd)); } @@ -12565,6 +14055,7 @@ BytecodeDescriptor *descriptor; sqInt end; sqInt pc; + sqInt pushingNils; sqInt stackDelta; needsFrame = 0; @@ -12572,6 +14063,7 @@ pc = (blockStart->startpc); end = ((blockStart->startpc)) + ((blockStart->span)); stackDelta = 0; + pushingNils = 1; while (pc < end) { byte0 = fetchByteofObject(pc, methodObj); descriptor = generatorAt(byte0); @@ -12584,19 +14076,22 @@ stackDelta += (descriptor->stackDelta); } } + if (pushingNils) { + if ((pushingNils = (((descriptor->generator)) == (genPushConstantNilBytecode)) + && (((fixupAt(pc - initialPC)->targetInstruction)) == 0))) { + assert(((descriptor->numBytes)) == 1); + (blockStart->numInitialNils = ((blockStart->numInitialNils)) + 1); + } + } pc = nextBytecodePCForatbyte0in(descriptor, pc, byte0, methodObj); } if (!(needsFrame)) { - if (stackDelta < 0) { - error("negative stack delta in block; block contains bogus code or internal error"); - } + assert(stackDelta >= 0); + (blockStart->numInitialNils = ((blockStart->numInitialNils)) - stackDelta); + pc = (blockStart->startpc); while (stackDelta > 0) { - descriptor = generatorAt(fetchByteofObject((blockStart->startpc), methodObj)); - if (((descriptor->generator)) != (genPushConstantNilBytecode)) { - error("frameless block doesn't start with enough pushNils"); - } - (blockStart->startpc = ((blockStart->startpc)) + ((descriptor->numBytes))); - (blockStart->span = ((blockStart->span)) - ((descriptor->numBytes))); + assert(((generatorAt(fetchByteofObject(pc, methodObj))->generator)) == (genPushConstantNilBytecode)); + pc += 1; stackDelta -= 1; } } @@ -12913,7 +14408,318 @@ } } + +/* Allocate a register needed in a run-time call (i.e. flush uses of the + register to the real stack). Since the run-time can smash any and + all caller-saved registers also flush all caller-saved registers. */ + +static void +ssAllocateCallReg(sqInt requiredReg) +{ + ssAllocateRequiredRegMaskupThrough(callerSavedRegMask | (registerMaskFor(requiredReg)), simStackPtr); +} + +static void +ssAllocateCallRegand(sqInt requiredReg1, sqInt requiredReg2) +{ + ssAllocateRequiredRegMaskupThrough(callerSavedRegMask | ((registerMaskFor(requiredReg1)) | (registerMaskFor(requiredReg2))), simStackPtr); +} + static sqInt +ssAllocatePreferredReg(sqInt preferredReg) +{ + sqInt i; + sqInt lastPreferred; + sqInt liveRegs; + sqInt preferredMask; + sqInt reg; + + + /* compute live regs while noting the last occurrence of preferredReg. + If there are none free we must spill from simSpillBase to last occurrence. */ + + lastPreferred = -1; + preferredMask = registerMaskFor(preferredReg); + liveRegs = registerMaskForandand(TempReg, FPReg, SPReg); + for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= simStackPtr; i += 1) { + liveRegs = liveRegs | (registerMask(simStackAt(i))); + if ((liveRegs & preferredMask) != 0) { + lastPreferred = i; + } + } + if ((liveRegs & (registerMaskFor(preferredReg))) == 0) { + return preferredReg; + } + for (reg = GPRegMin; reg <= GPRegMax; reg += 1) { + if ((liveRegs & (registerMaskFor(reg))) == 0) { + return reg; + } + } + ssFlushTo(lastPreferred); + assert(((liveRegisters()) & preferredMask) == 0); + return preferredReg; +} + +static void +ssAllocateRequiredRegMaskupThrough(sqInt requiredRegsMask, sqInt stackPtr) +{ + sqInt i; + sqInt lastRequired; + sqInt liveRegs; + + + /* compute live regs while noting the last occurrence of required regs. + If these are not free we must spill from simSpillBase to last occurrence. + Note we are conservative here; we could allocate FPReg in frameless methods. */ + + lastRequired = -1; + liveRegs = registerMaskForand(FPReg, SPReg); + for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= stackPtr; i += 1) { + liveRegs = liveRegs | (registerMask(simStackAt(i))); + if ((liveRegs & requiredRegsMask) != 0) { + lastRequired = i; + } + } + if (!((liveRegs & requiredRegsMask) == 0)) { + ssFlushTo(lastRequired); + assert(((liveRegisters()) & requiredRegsMask) == 0); + } +} + +static void +ssAllocateRequiredReg(sqInt requiredReg) +{ + ssAllocateRequiredRegMaskupThrough(registerMaskFor(requiredReg), simStackPtr); +} + +static void +ssAllocateRequiredRegand(sqInt requiredReg1, sqInt requiredReg2) +{ + ssAllocateRequiredRegMaskupThrough((registerMaskFor(requiredReg1)) | (registerMaskFor(requiredReg2)), simStackPtr); +} + +static void +ssAllocateRequiredRegupThrough(sqInt requiredReg, sqInt stackPtr) +{ + ssAllocateRequiredRegMaskupThrough(registerMaskFor(requiredReg), stackPtr); +} + +static void +ssFlushTo(sqInt index) +{ + sqInt i; + + for (i = methodOrBlockNumTemps; i <= (simSpillBase - 1); i += 1) { + assert((simStackAt(i)->spilled)); + } + if (simSpillBase <= index) { + for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= index; i += 1) { + assert(needsFrame); + ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i), FPReg); + } + simSpillBase = index + 1; + } +} + + +/* Any occurrences on the stack of the value being stored must + be flushed, and hence any values colder than them stack. */ + +static void +ssFlushUpThroughReceiverVariable(sqInt slotIndex) +{ + CogSimStackEntry *desc; + sqInt index; + + for (index = simStackPtr; index >= (((simSpillBase < 0) ? 0 : simSpillBase)); index += -1) { + desc = simStackAt(index); + if ((((desc->type)) == SSBaseOffset) + && ((((desc->registerr)) == ReceiverResultReg) + && (((desc->offset)) == (slotOffsetOfInstVarIndex(slotIndex))))) { + ssFlushTo(index); + return; + } + } +} + + +/* Any occurrences on the stack of the value being stored must + be flushed, and hence any values colder than them stack. */ + +static void +ssFlushUpThroughTemporaryVariable(sqInt tempIndex) +{ + CogSimStackEntry *desc; + sqInt index; + + for (index = simStackPtr; index >= simSpillBase; index += -1) { + desc = simStackAt(index); + if ((((desc->type)) == SSBaseOffset) + && ((((desc->registerr)) == FPReg) + && (((desc->offset)) == (frameOffsetOfTemporary(tempIndex))))) { + ssFlushTo(index); + return; + } + } +} + +static void +ssPop(sqInt n) +{ + assert(((simStackPtr - n) >= (methodOrBlockNumTemps - 1)) + || ((!needsFrame) + && ((simStackPtr - n) >= -1))); + simStackPtr -= n; +} + +static sqInt +ssPushAnnotatedConstant(sqInt literal) +{ + CogSimStackEntry * cascade0; + + ssPush(1); + if (simSpillBase > simStackPtr) { + simSpillBase = ((simStackPtr < 0) ? 0 : simStackPtr); + } + cascade0 = ssTop(); + (cascade0->type = SSConstant); + (cascade0->annotateUse = 1); + (cascade0->spilled = 0); + (cascade0->constant = literal); + (cascade0->bcptr = bytecodePointer); + return 0; +} + +static sqInt +ssPushBaseoffset(sqInt reg, sqInt offset) +{ + CogSimStackEntry * cascade0; + + ssPush(1); + if (simSpillBase > simStackPtr) { + simSpillBase = ((simStackPtr < 0) ? 0 : simStackPtr); + } + cascade0 = ssTop(); + (cascade0->type = SSBaseOffset); + (cascade0->spilled = 0); + (cascade0->annotateUse = 0); + (cascade0->registerr = reg); + (cascade0->offset = offset); + (cascade0->bcptr = bytecodePointer); + return 0; +} + +static sqInt +ssPushConstant(sqInt literal) +{ + CogSimStackEntry * cascade0; + + ssPush(1); + if (simSpillBase > simStackPtr) { + simSpillBase = ((simStackPtr < 0) ? 0 : simStackPtr); + } + cascade0 = ssTop(); + (cascade0->type = SSConstant); + (cascade0->spilled = 0); + (cascade0->annotateUse = 0); + (cascade0->constant = literal); + (cascade0->bcptr = bytecodePointer); + return 0; +} + +static sqInt +ssPushDesc(CogSimStackEntry simStackEntry) +{ + if (((simStackEntry.type)) == SSSpill) { + (simStackEntry.type = SSBaseOffset); + } + (simStackEntry.spilled = 0); + (simStackEntry.annotateUse = 0); + (simStackEntry.bcptr = bytecodePointer); + simStack[(simStackPtr += 1)] = simStackEntry; + if (simSpillBase > simStackPtr) { + simSpillBase = ((simStackPtr < 0) ? 0 : simStackPtr); + } + return 0; +} + +static sqInt +ssPushRegister(sqInt reg) +{ + CogSimStackEntry * cascade0; + + ssPush(1); + if (simSpillBase > simStackPtr) { + simSpillBase = ((simStackPtr < 0) ? 0 : simStackPtr); + } + cascade0 = ssTop(); + (cascade0->type = SSRegister); + (cascade0->spilled = 0); + (cascade0->annotateUse = 0); + (cascade0->registerr = reg); + (cascade0->bcptr = bytecodePointer); + return 0; +} + +static void +ssPush(sqInt n) +{ + simStackPtr += n; +} + + +/* Store or pop the top simulated stack entry to a register. + Pop to preferredReg if the entry is not itself a register. + Answer the actual register the result ends up in. */ + +static sqInt +ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg) +{ + sqInt actualReg; + + actualReg = preferredReg; + if (popBoolean) { + if ((((ssTop()->type)) == SSRegister) + && (!((ssTop()->spilled)))) { + assert(!((ssTop()->annotateUse))); + actualReg = (ssTop()->registerr); + } + else { + popToReg(ssTop(), preferredReg); + } + ssPop(1); + } + else { + if (((ssTop()->type)) == SSRegister) { + assert(!((ssTop()->annotateUse))); + actualReg = (ssTop()->registerr); + } + else { + storeToReg(ssTop(), preferredReg); + } + } + return actualReg; +} + +static CogSimStackEntry * +ssTop(void) +{ + return simStackAt(simStackPtr); +} + +static CogSimStackEntry +ssTopDescriptor(void) +{ + return simStack[simStackPtr]; +} + +static CogSimStackEntry * +ssValue(sqInt n) +{ + return simStackAt(simStackPtr - n); +} + +static sqInt stackBytesForNumArgs(AbstractInstruction * self_in_stackBytesForNumArgs, sqInt numArgs) { return numArgs * 4; @@ -12957,6 +14763,36 @@ byteAtput(followingAddress - 4, literal & 255); } +static void +storeToReg(CogSimStackEntry * self_in_storeToReg, sqInt reg) +{ + AbstractInstruction *inst; + + + switch ((self_in_storeToReg->type)) { + case SSBaseOffset: + case SSSpill: + inst = gMoveMwrR((self_in_storeToReg->offset), (self_in_storeToReg->registerr), reg); + break; + case SSConstant: + inst = (shouldAnnotateObjectReference((self_in_storeToReg->constant)) + ? annotateobjRef(gMoveCwR((self_in_storeToReg->constant), reg), (self_in_storeToReg->constant)) + : gMoveCqR((self_in_storeToReg->constant), reg)); + break; + case SSRegister: + inst = (reg != ((self_in_storeToReg->registerr)) + ? gMoveRR((self_in_storeToReg->registerr), reg) + : gLabel()); + break; + default: + error("Case not found and no otherwise clause"); + } + if ((self_in_storeToReg->annotateUse)) { + annotateBytecode(inst); + (self_in_storeToReg->annotateUse) = 0; + } +} + static sqInt sib(AbstractInstruction * self_in_sib, sqInt scale, sqInt indexReg, sqInt baseReg) { Modified: branches/Cog/src/vm/cogit.h =================================================================== --- branches/Cog/src/vm/cogit.h 2011-02-06 19:53:20 UTC (rev 2359) +++ branches/Cog/src/vm/cogit.h 2011-02-07 01:59:40 UTC (rev 2360) @@ -10,7 +10,12 @@ sqInt canLinkToYoungClasses(void); extern void (*ceCaptureCStackPointers)(); sqInt ceCPICMissreceiver(CogMethod *cPIC, sqInt receiver); +extern void (*ceEnter0ArgsPIC)(); +extern void (*ceEnter1ArgsPIC)(); +extern void (*ceEnter2ArgsPIC)(); extern void (*ceEnterCogCodePopReceiverAndClassRegs)(); +extern void (*ceEnterCogCodePopReceiverArg0Regs)(); +extern void (*ceEnterCogCodePopReceiverArg1Arg0Regs)(); extern void (*ceEnterCogCodePopReceiverReg)(); sqInt ceSICMiss(sqInt receiver); void checkAssertsEnabledInCogit(void); @@ -24,6 +29,8 @@ void compactCogCompiledCode(void); void enterCogCodePopReceiver(void); void enterCogCodePopReceiverAndClassRegs(void); +void enterCogCodePopReceiverArg0Regs(void); +void enterCogCodePopReceiverArg1Arg0Regs(void); CogBlockMethod * findEnclosingMethodForinHomeMethod(sqInt mcpc, CogMethod *cogMethod); CogBlockMethod * findMethodForStartBcpcinHomeMethod(sqInt startbcpc, CogMethod *cogMethod); sqInt genQuickReturnConst(void); @@ -74,7 +81,12 @@ sqInt ceCannotResumeTrampoline; void (*ceCaptureCStackPointers)(void); sqInt ceCheckForInterruptTrampoline; +void (*ceEnter0ArgsPIC)(void); +void (*ceEnter1ArgsPIC)(void); +void (*ceEnter2ArgsPIC)(void); void (*ceEnterCogCodePopReceiverAndClassRegs)(void); +void (*ceEnterCogCodePopReceiverArg0Regs)(void); +void (*ceEnterCogCodePopReceiverArg1Arg0Regs)(void); void (*ceEnterCogCodePopReceiverReg)(void); unsigned long (*ceGetSP)(void); sqInt ceReturnToInterpreterTrampoline; @@ -85,6 +97,8 @@ sqInt cmNoCheckEntryOffset; unsigned long debugPrimCallStackOffset; void (*realCEEnterCogCodePopReceiverAndClassRegs)(void); +void (*realCEEnterCogCodePopReceiverArg0Regs)(void); +void (*realCEEnterCogCodePopReceiverArg1Arg0Regs)(void); void (*realCEEnterCogCodePopReceiverReg)(void); int traceLinkedSends ; sqInt traceStores; @@ -99,7 +113,7 @@ #define getCStackPointer() CStackPointer #define noCheckEntryOffset() cmNoCheckEntryOffset #define noContextSwitchBlockEntryOffset() blockNoContextSwitchOffset -#define numRegArgs() 0 +#define numRegArgs() 1 #define printOnTrace() (traceLinkedSends & 8) #define recordEventTrace() (traceLinkedSends & 4) #define recordPrimTrace() (traceLinkedSends & 2) |
Free forum by Nabble | Edit this page |