Diff
checker
テキスト
テキスト
画像
ドキュメント
Excel
フォルダ
Legal
Enterprise
デスクトップ
料金
ログイン
Diffchecker デスクトップのダウンロード
テキスト比較
2 つのテキスト ファイルの違いを見つける
ツール
履歴
ライブエディター
未変更行を折りたたむ
折り返しなし
レイアウト
分割
統合
比較精度
スマート
単語
文字
シンタックスハイライト
構文を選択
無視
テキスト変換
最初の差分へ移動
入力を編集
Diffchecker Desktop
Diffcheckerを実行する最も安全な方法。Diffchecker Desktopアプリを入手:あなたの差分はコンピューターから出ることはありません!
Desktopを入手
cogitARMv5.c
作成日
7 年前
差分は期限切れになりません
クリア
エクスポート
共有
説明
12 削除
行
合計
削除
文字
合計
削除
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
554 行
すべてコピー
11 追加
行
合計
追加
文字
合計
追加
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
554 行
すべてコピー
コピー
コピー済み
コピー
コピー済み
cogitARMv5.c
0ab0a27
[
GOOD
]
cogitARMv5.c
968ed91
[
BAD
]
/* Automatically generated by
/* Automatically generated by
コピー
コピー済み
コピー
コピー済み
CCodeGenerator VMMaker.oscog-
eem.2482
uuid:
7df020b4-6565-4768-9e4a-75bc5464ed95
CCodeGenerator VMMaker.oscog-
nice.2501
uuid:
0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8
from
from
コピー
コピー済み
コピー
コピー済み
StackToRegisterMappingCogit VMMaker.oscog-
eem.2482
uuid:
7df020b4-6565-4768-9e4a-75bc5464ed95
StackToRegisterMappingCogit VMMaker.oscog-
nice.2501
uuid:
0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8
*/
*/
コピー
コピー済み
コピー
コピー済み
static char __buildInfo[] = "StackToRegisterMappingCogit VMMaker.oscog-
eem.2482
uuid:
7df020b4-6565-4768-9e4a-75bc5464ed95
" __DATE__ ;
static char __buildInfo[] = "StackToRegisterMappingCogit VMMaker.oscog-
nice.2501
uuid:
0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8
" __DATE__ ;
char *__cogitBuildInfo = __buildInfo;
char *__cogitBuildInfo = __buildInfo;
#include <stddef.h>
#include <stddef.h>
#include "sq.h"
#include "sq.h"
#include "sqCogStackAlignment.h"
#include "sqCogStackAlignment.h"
#include "dispdbg.h"
#include "dispdbg.h"
#include "cogmethod.h"
#include "cogmethod.h"
#if COGMTVM
#if COGMTVM
#include "cointerpmt.h"
#include "cointerpmt.h"
#else
#else
#include "cointerp.h"
#include "cointerp.h"
#endif
#endif
#include "cogit.h"
#include "cogit.h"
/*** Constants ***/
/*** Constants ***/
#define AddCqR 101
#define AddCqR 101
#define AddCwR 109
#define AddCwR 109
#define AddOpcode 4
#define AddOpcode 4
#define AddRdRd 120
#define AddRdRd 120
#define AddRR 95
#define AddRR 95
#define AL 14
#define AL 14
#define AlignmentNops 3
#define AlignmentNops 3
#define AltBlockCreationBytecodeSize 3
#define AltBlockCreationBytecodeSize 3
#define AltFirstSpecialSelector 96
#define AltFirstSpecialSelector 96
#define AltNumSpecialSelectors 32
#define AltNumSpecialSelectors 32
#define AndCqR 103
#define AndCqR 103
#define AndCqRR 118
#define AndCqRR 118
#define AndCwR 111
#define AndCwR 111
#define AndOpcode 0
#define AndOpcode 0
#define AndRR 97
#define AndRR 97
#define AnnotationShift 5
#define AnnotationShift 5
#define Arg0Reg 3
#define Arg0Reg 3
#define Arg1Reg 4
#define Arg1Reg 4
#define ArithmeticShiftRightCqR 86
#define ArithmeticShiftRightCqR 86
#define ArithmeticShiftRightRR 87
#define ArithmeticShiftRightRR 87
#define BadRegisterSet 1
#define BadRegisterSet 1
#define BicOpcode 14
#define BicOpcode 14
#define BlockCreationBytecodeSize 4
#define BlockCreationBytecodeSize 4
#define BytecodeSetHasDirectedSuperSend 1
#define BytecodeSetHasDirectedSuperSend 1
#define CArg0Reg 0
#define CArg0Reg 0
#define CArg1Reg 1
#define CArg1Reg 1
#define CArg2Reg 2
#define CArg2Reg 2
#define CArg3Reg 3
#define CArg3Reg 3
#define Call 6
#define Call 6
#define CallerSavedRegisterMask 0x120C
#define CallerSavedRegisterMask 0x120C
#define CallFull 7
#define CallFull 7
#define CC 3
#define CC 3
#if !defined(CheckRememberedInTrampoline) /* Allow this to be overridden on the compiler command line */
#if !defined(CheckRememberedInTrampoline) /* Allow this to be overridden on the compiler command line */
# define CheckRememberedInTrampoline 0
# define CheckRememberedInTrampoline 0
#endif
#endif
#define ClassArray 7
#define ClassArray 7
#define ClassArrayCompactIndex 51
#define ClassArrayCompactIndex 51
#define ClassBlockClosureCompactIndex 37
#define ClassBlockClosureCompactIndex 37
#define ClassFloatCompactIndex 34
#define ClassFloatCompactIndex 34
#define ClassFullBlockClosureCompactIndex 38
#define ClassFullBlockClosureCompactIndex 38
#define ClassLargePositiveIntegerCompactIndex 33
#define ClassLargePositiveIntegerCompactIndex 33
#define ClassMethodContextCompactIndex 36
#define ClassMethodContextCompactIndex 36
#define ClassReg 2
#define ClassReg 2
#define ClosureFirstCopiedValueIndex 3
#define ClosureFirstCopiedValueIndex 3
#define ClosureIndex 4
#define ClosureIndex 4
#define ClosureNumArgsIndex 2
#define ClosureNumArgsIndex 2
#define ClosureOuterContextIndex 0
#define ClosureOuterContextIndex 0
#define ClosureStartPCIndex 1
#define ClosureStartPCIndex 1
#define CMBlock 3
#define CMBlock 3
#define CMClosedPIC 4
#define CMClosedPIC 4
#define CMFree 1
#define CMFree 1
#define CMMaxUsageCount 7
#define CMMaxUsageCount 7
#define CMMethod 2
#define CMMethod 2
#define CMOpenPIC 5
#define CMOpenPIC 5
#define CMPSMULL 152
#define CMPSMULL 152
#define CmpC32R 108
#define CmpC32R 108
#define CmpCqR 100
#define CmpCqR 100
#define CmpCwR 107
#define CmpCwR 107
#define CmpNotOpcode 11
#define CmpNotOpcode 11
#define CmpOpcode 10
#define CmpOpcode 10
#define CmpRdRd 119
#define CmpRdRd 119
#define CmpRR 94
#define CmpRR 94
#define CompletePrimitive 4
#define CompletePrimitive 4
#define ConcreteIPReg 12
#define ConcreteIPReg 12
#define ConcreteVarBaseReg 10
#define ConcreteVarBaseReg 10
#define ConstZero 1
#define ConstZero 1
#define ConvertRRd 133
#define ConvertRRd 133
#define CS 2
#define CS 2
#define Debug DEBUGVM
#define Debug DEBUGVM
#define DisplacementMask 0x1F
#define DisplacementMask 0x1F
#define DisplacementX2N 0
#define DisplacementX2N 0
#define DivRdRd 123
#define DivRdRd 123
#define DPFPReg0 0
#define DPFPReg0 0
#define DPFPReg1 1
#define DPFPReg1 1
#define DPFPReg2 2
#define DPFPReg2 2
#define DPFPReg3 3
#define DPFPReg3 3
#define DPFPReg4 4
#define DPFPReg4 4
#define DPFPReg5 5
#define DPFPReg5 5
#define DPFPReg6 6
#define DPFPReg6 6
#define DPFPReg7 7
#define DPFPReg7 7
#define EncounteredUnknownBytecode -6
#define EncounteredUnknownBytecode -6
#define EQ 0
#define EQ 0
#define Extra0Reg 7
#define Extra0Reg 7
#define Extra1Reg 8
#define Extra1Reg 8
#define Extra2Reg 9
#define Extra2Reg 9
#define Fill32 4
#define Fill32 4
#define FirstAnnotation 64
#define FirstAnnotation 64
#define FirstJump 12
#define FirstJump 12
#define FirstSpecialSelector 176
#define FirstSpecialSelector 176
#define FoxCallerSavedIP 4
#define FoxCallerSavedIP 4
#define FoxMethod -4
#define FoxMethod -4
#define FoxMFReceiver -12
#define FoxMFReceiver -12
#define FoxSavedFP 0
#define FoxSavedFP 0
#define FoxThisContext -8
#define FoxThisContext -8
#define FPReg 11
#define FPReg 11
#define FullClosureCompiledBlockIndex 1
#define FullClosureCompiledBlockIndex 1
#define FullClosureFirstCopiedValueIndex 4
#define FullClosureFirstCopiedValueIndex 4
#define FullClosureReceiverIndex 3
#define FullClosureReceiverIndex 3
#define GCModeBecome 8
#define GCModeBecome 8
#define GCModeFull 1
#define GCModeFull 1
#define GCModeNewSpace 2
#define GCModeNewSpace 2
#define GE 10
#define GE 10
#define GT 12
#define GT 12
#define HasBytecodePC 5
#define HasBytecodePC 5
#define HashMultiplyConstant 1664525
#define HashMultiplyConstant 1664525
#define HashMultiplyMask 0xFFFFFFF
#define HashMultiplyMask 0xFFFFFFF
#define HeaderIndex 0
#define HeaderIndex 0
#define HI 8
#define HI 8
#if !defined(IMMUTABILITY) /* Allow this to be overridden on the compiler command line */
#if !defined(IMMUTABILITY) /* Allow this to be overridden on the compiler command line */
# define IMMUTABILITY 1
# define IMMUTABILITY 1
#endif
#endif
#define InFullBlock 2
#define InFullBlock 2
#define InstanceSpecificationIndex 2
#define InstanceSpecificationIndex 2
#define InstructionPointerIndex 1
#define InstructionPointerIndex 1
#define InsufficientCodeSpace -2
#define InsufficientCodeSpace -2
#define InVanillaBlock 1
#define InVanillaBlock 1
#define IsAbsPCReference 3
#define IsAbsPCReference 3
#define IsAnnotationExtension 1
#define IsAnnotationExtension 1
#define IsDirectedSuperBindingSend 10
#define IsDirectedSuperBindingSend 10
#define IsDirectedSuperSend 9
#define IsDirectedSuperSend 9
#define IsDisplacementX2N 0
#define IsDisplacementX2N 0
#define IsNSDynamicSuperSend null
#define IsNSDynamicSuperSend null
#define IsNSSelfSend null
#define IsNSSelfSend null
#define IsNSSendCall null
#define IsNSSendCall null
#define IsObjectReference 2
#define IsObjectReference 2
#define IsRelativeCall 4
#define IsRelativeCall 4
#define IsSendCall 7
#define IsSendCall 7
#define IsSuperSend 8
#define IsSuperSend 8
#define Jump 16
#define Jump 16
#define JumpAbove 31
#define JumpAbove 31
#define JumpAboveOrEqual 30
#define JumpAboveOrEqual 30
#define JumpBelow 29
#define JumpBelow 29
#define JumpBelowOrEqual 32
#define JumpBelowOrEqual 32
#define JumpCarry 23
#define JumpCarry 23
#define JumpFPEqual 33
#define JumpFPEqual 33
#define JumpFPGreater 37
#define JumpFPGreater 37
#define JumpFPGreaterOrEqual 38
#define JumpFPGreaterOrEqual 38
#define JumpFPLess 35
#define JumpFPLess 35
#define JumpFPLessOrEqual 36
#define JumpFPLessOrEqual 36
#define JumpFPNotEqual 34
#define JumpFPNotEqual 34
#define JumpFPOrdered 39
#define JumpFPOrdered 39
#define JumpFPUnordered 40
#define JumpFPUnordered 40
#define JumpFull 12
#define JumpFull 12
#define JumpGreater 27
#define JumpGreater 27
#define JumpGreaterOrEqual 26
#define JumpGreaterOrEqual 26
#define JumpLess 25
#define JumpLess 25
#define JumpLessOrEqual 28
#define JumpLessOrEqual 28
#define JumpLong 13
#define JumpLong 13
#define JumpLongNonZero 15
#define JumpLongNonZero 15
#define JumpLongZero 14
#define JumpLongZero 14
#define JumpNegative 19
#define JumpNegative 19
#define JumpNoCarry 24
#define JumpNoCarry 24
#define JumpNonNegative 20
#define JumpNonNegative 20
#define JumpNonZero 18
#define JumpNonZero 18
#define JumpNoOverflow 22
#define JumpNoOverflow 22
#define JumpOverflow 21
#define JumpOverflow 21
#define JumpR 10
#define JumpR 10
#define JumpZero 17
#define JumpZero 17
#define Label 1
#define Label 1
#define LargeContextSlots 62
#define LargeContextSlots 62
#define LastJump 40
#define LastJump 40
#define LE 13
#define LE 13
#define LinkReg 14
#define LinkReg 14
#define Literal 2
#define Literal 2
#define LiteralStart 1
#define LiteralStart 1
#define LoadEffectiveAddressMwrR 83
#define LoadEffectiveAddressMwrR 83
#define LogicalShiftLeftCqR 90
#define LogicalShiftLeftCqR 90
#define LogicalShiftLeftRR 91
#define LogicalShiftLeftRR 91
#define LogicalShiftRightCqR 88
#define LogicalShiftRightCqR 88
#define LogicalShiftRightRR 89
#define LogicalShiftRightRR 89
#define LowcodeVM 0
#define LowcodeVM 0
#define LR 14
#define LR 14
#define LS 9
#define LS 9
#define LT 11
#define LT 11
#define MapEnd 0
#define MapEnd 0
#define MaxCompiledPrimitiveIndex 222
#define MaxCompiledPrimitiveIndex 222
#define MaxCPICCases 6
#define MaxCPICCases 6
#define MaxMethodSize 65535
#define MaxMethodSize 65535
#define MaxNegativeErrorCode -8
#define MaxNegativeErrorCode -8
#define MaxNumArgs 15
#define MaxNumArgs 15
#define MaxStackAllocSize 1572864
#define MaxStackAllocSize 1572864
#define MaxStackCheckOffset 0xFFF
#define MaxStackCheckOffset 0xFFF
#define MaxX2NDisplacement 992
#define MaxX2NDisplacement 992
#define MethodCacheClass 2
#define MethodCacheClass 2
#define MethodCacheMask 0xFFC
#define MethodCacheMask 0xFFC
#define MethodCacheMethod 3
#define MethodCacheMethod 3
#define MethodCacheSelector 1
#define MethodCacheSelector 1
#define MethodIndex 3
#define MethodIndex 3
#define MethodTooBig -4
#define MethodTooBig -4
#define MFMethodFlagHasContextFlag 1
#define MFMethodFlagHasContextFlag 1
#define MFMethodFlagIsBlockFlag 2
#define MFMethodFlagIsBlockFlag 2
#define MI 4
#define MI 4
#define MoveAbR 46
#define MoveAbR 46
#define MoveAwR 42
#define MoveAwR 42
#define MoveC32R 69
#define MoveC32R 69
#define MoveCqR 67
#define MoveCqR 67
#define MoveCwR 68
#define MoveCwR 68
#define MoveM16rR 55
#define MoveM16rR 55
#define MoveM64rRd 73
#define MoveM64rRd 73
#define MoveMbrR 63
#define MoveMbrR 63
#define MoveMwrR 48
#define MoveMwrR 48
#define MoveNotOpcode 15
#define MoveNotOpcode 15
#define MoveOpcode 13
#define MoveOpcode 13
#define MoveRAb 47
#define MoveRAb 47
#define MoveRAw 44
#define MoveRAw 44
#define MoveRdM64r 74
#define MoveRdM64r 74
#define MoveRdRd 72
#define MoveRdRd 72
#define MoveRM16r 56
#define MoveRM16r 56
#define MoveRMbr 64
#define MoveRMbr 64
#define MoveRMwr 49
#define MoveRMwr 49
#define MoveRR 41
#define MoveRR 41
#define MoveRXbrR 66
#define MoveRXbrR 66
#define MoveRXwrR 51
#define MoveRXwrR 51
#define MoveXbrRR 65
#define MoveXbrRR 65
#define MoveXwrRR 50
#define MoveXwrRR 50
#define MSR 146
#define MSR 146
#define MULTIPLEBYTECODESETS 1
#define MULTIPLEBYTECODESETS 1
#define MulRdRd 122
#define MulRdRd 122
#define NE 1
#define NE 1
#define NeedsMergeFixupFlag 2
#define NeedsMergeFixupFlag 2
#define NeedsNonMergeFixupFlag 1
#define NeedsNonMergeFixupFlag 1
#define NegateR 84
#define NegateR 84
#define NewspeakVM 0
#define NewspeakVM 0
#define Nop 5
#define Nop 5
#define NoReg -1
#define NoReg -1
#define NotFullyInitialized -1
#define NotFullyInitialized -1
#define NumObjRefsInRuntime 0
#define NumObjRefsInRuntime 0
#define NumOopsPerNSC 6
#define NumOopsPerNSC 6
#define NumSendTrampolines 4
#define NumSendTrampolines 4
#define NumSpecialSelectors 32
#define NumSpecialSelectors 32
#define NumStoreTrampolines 5
#define NumStoreTrampolines 5
#define NumTrampolines 74
#define NumTrampolines 74
#define OrCqR 104
#define OrCqR 104
#define OrCwR 112
#define OrCwR 112
#define OrOpcode 12
#define OrOpcode 12
#define OrRR 98
#define OrRR 98
#define PC 15
#define PC 15
#define PCReg 15
#define PCReg 15
#define PL 5
#define PL 5
#define PopLDM 148
#define PopLDM 148
#define PopR 78
#define PopR 78
#define PrefetchAw 82
#define PrefetchAw 82
#define PrimCallCollectsProfileSamples 16
#define PrimCallCollectsProfileSamples 16
#define PrimCallDoNotJIT 64
#define PrimCallDoNotJIT 64
#define PrimCallMayCallBack 4
#define PrimCallMayCallBack 4
#define PrimCallNeedsNewMethod 1
#define PrimCallNeedsNewMethod 1
#define PrimCallNeedsPrimitiveFunction 2
#define PrimCallNeedsPrimitiveFunction 2
#define PrimCallOnSmalltalkStack 8
#define PrimCallOnSmalltalkStack 8
#define PrimErrNoMemory 9
#define PrimErrNoMemory 9
#define PrimErrWritePastObject 17
#define PrimErrWritePastObject 17
#define PushCq 80
#define PushCq 80
#define PushCw 81
#define PushCw 81
#define PushR 79
#define PushR 79
#define PushSTM 149
#define PushSTM 149
#define R0 0
#define R0 0
#define ReceiverIndex 5
#define ReceiverIndex 5
#define ReceiverResultReg 5
#define ReceiverResultReg 5
#define RetN 9
#define RetN 9
#define RISCTempReg 12
#define RISCTempReg 12
#define RsbOpcode 3
#define RsbOpcode 3
#define SelectorCannotInterpret 34
#define SelectorCannotInterpret 34
#define SelectorDoesNotUnderstand 20
#define SelectorDoesNotUnderstand 20
#define SenderIndex 0
#define SenderIndex 0
#define SendNumArgsReg 6
#define SendNumArgsReg 6
#define ShouldNotJIT -8
#define ShouldNotJIT -8
#define SignExtend16RR 140
#define SignExtend16RR 140
#define SignExtend8RR 139
#define SignExtend8RR 139
#define SistaV1BytecodeSet 1
#define SistaV1BytecodeSet 1
#define SistaVM 0
#define SistaVM 0
#define SMULL 145
#define SMULL 145
#define SmallContextSlots 22
#define SmallContextSlots 22
#define SP 13
#define SP 13
#define SPReg 13
#define SPReg 13
#define SPURVM 1
#define SPURVM 1
#define SqrtRd 124
#define SqrtRd 124
#define SSBaseOffset 1
#define SSBaseOffset 1
#define SSConstant 2
#define SSConstant 2
#define SSRegister 3
#define SSRegister 3
#define SSSpill 4
#define SSSpill 4
#define StackPointerIndex 2
#define StackPointerIndex 2
#define Stop 11
#define Stop 11
#define SubCqR 102
#define SubCqR 102
#define SubCwR 110
#define SubCwR 110
#define SubOpcode 2
#define SubOpcode 2
#define SubRdRd 121
#define SubRdRd 121
#define SubRR 96
#define SubRR 96
#define TempReg 0
#define TempReg 0
#define TempVectReadBarrier 0
#define TempVectReadBarrier 0
#define TstCqR 105
#define TstCqR 105
#define TstOpcode 8
#define TstOpcode 8
#define UnfailingPrimitive 3
#define UnfailingPrimitive 3
#define UnimplementedPrimitive -7
#define UnimplementedPrimitive -7
#define ValueIndex 1
#define ValueIndex 1
#define VarBaseReg 10
#define VarBaseReg 10
#define VC 7
#define VC 7
#define VS 6
#define VS 6
#define XorCqR 106
#define XorCqR 106
#define XorCwR 113
#define XorCwR 113
#define XorOpcode 1
#define XorOpcode 1
#define XorRR 99
#define XorRR 99
#define YoungSelectorInPIC -5
#define YoungSelectorInPIC -5
typedef struct _AbstractInstruction {
typedef struct _AbstractInstruction {
unsigned char opcode;
unsigned char opcode;
unsigned char machineCodeSize;
unsigned char machineCodeSize;
unsigned char maxSize;
unsigned char maxSize;
unsigned char annotation;
unsigned char annotation;
unsigned char conditionOrNil;
unsigned char conditionOrNil;
usqInt operands [3];
usqInt operands [3];
usqInt address;
usqInt address;
struct _AbstractInstruction *dependent;
struct _AbstractInstruction *dependent;
unsigned int machineCode [5];
unsigned int machineCode [5];
} AbstractInstruction;
} AbstractInstruction;
#define CogOutOfLineLiteralsARMCompiler AbstractInstruction
#define CogOutOfLineLiteralsARMCompiler AbstractInstruction
#define CogARMCompiler AbstractInstruction
#define CogARMCompiler AbstractInstruction
#define CogAbstractInstruction AbstractInstruction
#define CogAbstractInstruction AbstractInstruction
typedef struct {
typedef struct {
AbstractInstruction *fakeHeader;
AbstractInstruction *fakeHeader;
AbstractInstruction *fillInstruction;
AbstractInstruction *fillInstruction;
sqInt numArgs;
sqInt numArgs;
sqInt numCopied;
sqInt numCopied;
sqInt numInitialNils;
sqInt numInitialNils;
sqInt startpc;
sqInt startpc;
AbstractInstruction *entryLabel;
AbstractInstruction *entryLabel;
AbstractInstruction *stackCheckLabel;
AbstractInstruction *stackCheckLabel;
sqInt span;
sqInt span;
sqInt hasInstVarRef;
sqInt hasInstVarRef;
} BlockStart;
} BlockStart;
#define CogBlockStart BlockStart
#define CogBlockStart BlockStart
typedef struct _BytecodeDescriptor {
typedef struct _BytecodeDescriptor {
sqInt (*generator )(void);
sqInt (*generator )(void);
sqInt NoDbgRegParms (*spanFunction )(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt);
sqInt NoDbgRegParms (*spanFunction )(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt);
sqInt NoDbgRegParms (*needsFrameFunction )(sqInt);
sqInt NoDbgRegParms (*needsFrameFunction )(sqInt);
signed char stackDelta;
signed char stackDelta;
unsigned char opcode;
unsigned char opcode;
unsigned char numBytes;
unsigned char numBytes;
unsigned isBranchTrue : 1;
unsigned isBranchTrue : 1;
unsigned isBranchFalse : 1;
unsigned isBranchFalse : 1;
unsigned isReturn : 1;
unsigned isReturn : 1;
unsigned isBlockCreation : 1;
unsigned isBlockCreation : 1;
unsigned isMapped : 1;
unsigned isMapped : 1;
unsigned isMappedInBlock : 1;
unsigned isMappedInBlock : 1;
unsigned isExtension : 1;
unsigned isExtension : 1;
unsigned isInstVarRef : 1;
unsigned isInstVarRef : 1;
unsigned is1ByteInstVarStore : 1;
unsigned is1ByteInstVarStore : 1;
unsigned hasUnsafeJump : 1;
unsigned hasUnsafeJump : 1;
} BytecodeDescriptor;
} BytecodeDescriptor;
#define CogBytecodeDescriptor BytecodeDescriptor
#define CogBytecodeDescriptor BytecodeDescriptor
typedef struct {
typedef struct {
sqInt (*primitiveGenerator )(void);
sqInt (*primitiveGenerator )(void);
sqInt primNumArgs;
sqInt primNumArgs;
} PrimitiveDescriptor;
} PrimitiveDescriptor;
#define CogPrimitiveDescriptor PrimitiveDescriptor
#define CogPrimitiveDescriptor PrimitiveDescriptor
typedef struct {
typedef struct {
char type;
char type;
char spilled;
char spilled;
signed char liveRegister;
signed char liveRegister;
signed char registerr;
signed char registerr;
sqInt offset;
sqInt offset;
sqInt constant;
sqInt constant;
sqInt bcptr;
sqInt bcptr;
} SimStackEntry;
} SimStackEntry;
#define CogSimStackEntry SimStackEntry
#define CogSimStackEntry SimStackEntry
typedef struct {
typedef struct {
AbstractInstruction *targetInstruction;
AbstractInstruction *targetInstruction;
unsigned char simStackPtr;
unsigned char simStackPtr;
char isTargetOfBackwardBranch;
char isTargetOfBackwardBranch;
unsigned short instructionIndex;
unsigned short instructionIndex;
#if LowcodeVM
#if LowcodeVM
short simNativeStackPtr;
short simNativeStackPtr;
unsigned short simNativeStackSize;
unsigned short simNativeStackSize;
#endif
#endif
} BytecodeFixup;
} BytecodeFixup;
#define CogSSBytecodeFixup BytecodeFixup
#define CogSSBytecodeFixup BytecodeFixup
#define CogBytecodeFixup BytecodeFixup
#define CogBytecodeFixup BytecodeFixup
typedef struct {
typedef struct {
sqInt isReceiverResultRegLive;
sqInt isReceiverResultRegLive;
CogSimStackEntry *ssEntry;
CogSimStackEntry *ssEntry;
} CogSSOptStatus;
} CogSSOptStatus;
/*** Function Prototypes ***/
/*** Function Prototypes ***/
#if !PRODUCTION && defined(PlatformNoDbgRegParms)
#if !PRODUCTION && defined(PlatformNoDbgRegParms)
# define NoDbgRegParms PlatformNoDbgRegParms
# define NoDbgRegParms PlatformNoDbgRegParms
#endif
#endif
#if !defined(NoDbgRegParms)
#if !defined(NoDbgRegParms)
# define NoDbgRegParms /*empty*/
# define NoDbgRegParms /*empty*/
#endif
#endif
#if !defined(NeverInline)
#if !defined(NeverInline)
# define NeverInline /*empty*/
# define NeverInline /*empty*/
#endif
#endif
static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction);
static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction);
static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask);
static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask);
static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral);
static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral);
static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp);
static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp);
static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister);
static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister);
static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal);
static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal);
static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal);
static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal);
static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction);
static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction);
static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump);
static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump);
static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress);
static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress);
static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction);
static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction);
static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress);
static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress);
static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta);
static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta);
static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta);
static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta);
static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget);
static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget);
static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
コピー
コピー済み
コピー
コピー済み
static sqInt NoDbgRegParms unalignedLongAt(AbstractInstruction * self_in_unalignedLongAt, sqInt byteAddress);
static sqInt NoDbgRegParms unalignedLongAtput(AbstractInstruction * self_in_unalignedLongAtput, sqInt byteAddress, sqInt aWord);
static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject);
static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject);
static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg);
static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg);
static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr);
static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr);
static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask);
static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask);
static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot);
static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset);
static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset);
static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset);
static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset);
コピー
コピー済み
コピー
コピー済み
static sqInt NoDbgRegParms callFullTargetFromReturnAddress(AbstractInstruction * self_in_callFullTargetFromReturnAddress, sqInt callSiteReturnAddress);
static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize);
static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize);
static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress);
static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress);
static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize);
static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize);
static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask);
static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask);
static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask);
static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask);
static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress);
static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress);
static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL);
static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL);
static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction);
static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction);
static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32);
static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32);
static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR);
static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR);
static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush);
static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush);
static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL);
static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL);
static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr);
static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr);
static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft);
static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft);
static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize);
static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize);
static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB);
static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB);
static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB);
static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB);
static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative);
static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative);
static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder);
static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder);
static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer);
static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer);
static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers);
static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers);
static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers);
static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers);
static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest);
static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest);
static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs);
static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs);
static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored);
static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored);
static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers);
static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers);
static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc);
static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc);
static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress);
static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress);
static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr);
static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr);
static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr);
static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr);
static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr);
static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr);
static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr);
static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr);
static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr);
static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr);
static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr);
static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr);
static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr);
static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr);
static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr);
static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr);
static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc);
static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc);
static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode);
static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode);
static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc);
static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc);
static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand);
static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand);
static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc);
static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc);
static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr);
static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr);
static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize);
static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize);
static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize);
static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize);
static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc);
static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc);
static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc);
static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc);
static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue);
static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue);
static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue);
static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg);
static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg);
static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg);
static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize);
static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize);
static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes);
static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes);
static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords);
static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords);
static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8);
static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8);
static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset);
static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset);
static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg);
static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue);
static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue);
static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg);
static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg);
static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg);
static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg);
static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags);
static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags);
static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs);
static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs);
static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot);
static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr);
static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr);
static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg);
static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg);
static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize);
static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize);
static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg);
static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg);
static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta);
static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta);
static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress);
static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode);
static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode);
コピー
コピー済み
コピー
コピー済み
static sqInt NoDbgRegParms shiftSetsCondition
CodesFor(AbstractInstruction * self_in_shiftSetsConditionCodesFor, sqInt aConditionalJumpOpcode);
static sqInt NoDbgRegParms shiftSetsCondition
static sqInt NoDbgRegParms stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes);
static AbstractInstruction * NoDbgRegParms stopsFromto(AbstractInstruction * self_in_stopsFromto, sqInt startAddr, sqInt endAddr);
static sqInt NoDbgRegParms strbrnplusimm(
保存された差分
原文
ファイルを開く
cogitARMv5.c 0ab0a27 [GOOD] /* Automatically generated by CCodeGenerator VMMaker.oscog-eem.2482 uuid: 7df020b4-6565-4768-9e4a-75bc5464ed95 from StackToRegisterMappingCogit VMMaker.oscog-eem.2482 uuid: 7df020b4-6565-4768-9e4a-75bc5464ed95 */ static char __buildInfo[] = "StackToRegisterMappingCogit VMMaker.oscog-eem.2482 uuid: 7df020b4-6565-4768-9e4a-75bc5464ed95 " __DATE__ ; char *__cogitBuildInfo = __buildInfo; #include <stddef.h> #include "sq.h" #include "sqCogStackAlignment.h" #include "dispdbg.h" #include "cogmethod.h" #if COGMTVM #include "cointerpmt.h" #else #include "cointerp.h" #endif #include "cogit.h" /*** Constants ***/ #define AddCqR 101 #define AddCwR 109 #define AddOpcode 4 #define AddRdRd 120 #define AddRR 95 #define AL 14 #define AlignmentNops 3 #define AltBlockCreationBytecodeSize 3 #define AltFirstSpecialSelector 96 #define AltNumSpecialSelectors 32 #define AndCqR 103 #define AndCqRR 118 #define AndCwR 111 #define AndOpcode 0 #define AndRR 97 #define AnnotationShift 5 #define Arg0Reg 3 #define Arg1Reg 4 #define ArithmeticShiftRightCqR 86 #define ArithmeticShiftRightRR 87 #define BadRegisterSet 1 #define BicOpcode 14 #define BlockCreationBytecodeSize 4 #define BytecodeSetHasDirectedSuperSend 1 #define CArg0Reg 0 #define CArg1Reg 1 #define CArg2Reg 2 #define CArg3Reg 3 #define Call 6 #define CallerSavedRegisterMask 0x120C #define CallFull 7 #define CC 3 #if !defined(CheckRememberedInTrampoline) /* Allow this to be overridden on the compiler command line */ # define CheckRememberedInTrampoline 0 #endif #define ClassArray 7 #define ClassArrayCompactIndex 51 #define ClassBlockClosureCompactIndex 37 #define ClassFloatCompactIndex 34 #define ClassFullBlockClosureCompactIndex 38 #define ClassLargePositiveIntegerCompactIndex 33 #define ClassMethodContextCompactIndex 36 #define ClassReg 2 #define ClosureFirstCopiedValueIndex 3 #define ClosureIndex 4 #define ClosureNumArgsIndex 2 #define ClosureOuterContextIndex 0 #define ClosureStartPCIndex 1 #define CMBlock 3 #define CMClosedPIC 4 #define CMFree 1 #define CMMaxUsageCount 7 #define CMMethod 2 #define CMOpenPIC 5 #define CMPSMULL 152 #define CmpC32R 108 #define CmpCqR 100 #define CmpCwR 107 #define CmpNotOpcode 11 #define CmpOpcode 10 #define CmpRdRd 119 #define CmpRR 94 #define CompletePrimitive 4 #define ConcreteIPReg 12 #define ConcreteVarBaseReg 10 #define ConstZero 1 #define ConvertRRd 133 #define CS 2 #define Debug DEBUGVM #define DisplacementMask 0x1F #define DisplacementX2N 0 #define DivRdRd 123 #define DPFPReg0 0 #define DPFPReg1 1 #define DPFPReg2 2 #define DPFPReg3 3 #define DPFPReg4 4 #define DPFPReg5 5 #define DPFPReg6 6 #define DPFPReg7 7 #define EncounteredUnknownBytecode -6 #define EQ 0 #define Extra0Reg 7 #define Extra1Reg 8 #define Extra2Reg 9 #define Fill32 4 #define FirstAnnotation 64 #define FirstJump 12 #define FirstSpecialSelector 176 #define FoxCallerSavedIP 4 #define FoxMethod -4 #define FoxMFReceiver -12 #define FoxSavedFP 0 #define FoxThisContext -8 #define FPReg 11 #define FullClosureCompiledBlockIndex 1 #define FullClosureFirstCopiedValueIndex 4 #define FullClosureReceiverIndex 3 #define GCModeBecome 8 #define GCModeFull 1 #define GCModeNewSpace 2 #define GE 10 #define GT 12 #define HasBytecodePC 5 #define HashMultiplyConstant 1664525 #define HashMultiplyMask 0xFFFFFFF #define HeaderIndex 0 #define HI 8 #if !defined(IMMUTABILITY) /* Allow this to be overridden on the compiler command line */ # define IMMUTABILITY 1 #endif #define InFullBlock 2 #define InstanceSpecificationIndex 2 #define InstructionPointerIndex 1 #define InsufficientCodeSpace -2 #define InVanillaBlock 1 #define IsAbsPCReference 3 #define IsAnnotationExtension 1 #define IsDirectedSuperBindingSend 10 #define IsDirectedSuperSend 9 #define IsDisplacementX2N 0 #define IsNSDynamicSuperSend null #define IsNSSelfSend null #define IsNSSendCall null #define IsObjectReference 2 #define IsRelativeCall 4 #define IsSendCall 7 #define IsSuperSend 8 #define Jump 16 #define JumpAbove 31 #define JumpAboveOrEqual 30 #define JumpBelow 29 #define JumpBelowOrEqual 32 #define JumpCarry 23 #define JumpFPEqual 33 #define JumpFPGreater 37 #define JumpFPGreaterOrEqual 38 #define JumpFPLess 35 #define JumpFPLessOrEqual 36 #define JumpFPNotEqual 34 #define JumpFPOrdered 39 #define JumpFPUnordered 40 #define JumpFull 12 #define JumpGreater 27 #define JumpGreaterOrEqual 26 #define JumpLess 25 #define JumpLessOrEqual 28 #define JumpLong 13 #define JumpLongNonZero 15 #define JumpLongZero 14 #define JumpNegative 19 #define JumpNoCarry 24 #define JumpNonNegative 20 #define JumpNonZero 18 #define JumpNoOverflow 22 #define JumpOverflow 21 #define JumpR 10 #define JumpZero 17 #define Label 1 #define LargeContextSlots 62 #define LastJump 40 #define LE 13 #define LinkReg 14 #define Literal 2 #define LiteralStart 1 #define LoadEffectiveAddressMwrR 83 #define LogicalShiftLeftCqR 90 #define LogicalShiftLeftRR 91 #define LogicalShiftRightCqR 88 #define LogicalShiftRightRR 89 #define LowcodeVM 0 #define LR 14 #define LS 9 #define LT 11 #define MapEnd 0 #define MaxCompiledPrimitiveIndex 222 #define MaxCPICCases 6 #define MaxMethodSize 65535 #define MaxNegativeErrorCode -8 #define MaxNumArgs 15 #define MaxStackAllocSize 1572864 #define MaxStackCheckOffset 0xFFF #define MaxX2NDisplacement 992 #define MethodCacheClass 2 #define MethodCacheMask 0xFFC #define MethodCacheMethod 3 #define MethodCacheSelector 1 #define MethodIndex 3 #define MethodTooBig -4 #define MFMethodFlagHasContextFlag 1 #define MFMethodFlagIsBlockFlag 2 #define MI 4 #define MoveAbR 46 #define MoveAwR 42 #define MoveC32R 69 #define MoveCqR 67 #define MoveCwR 68 #define MoveM16rR 55 #define MoveM64rRd 73 #define MoveMbrR 63 #define MoveMwrR 48 #define MoveNotOpcode 15 #define MoveOpcode 13 #define MoveRAb 47 #define MoveRAw 44 #define MoveRdM64r 74 #define MoveRdRd 72 #define MoveRM16r 56 #define MoveRMbr 64 #define MoveRMwr 49 #define MoveRR 41 #define MoveRXbrR 66 #define MoveRXwrR 51 #define MoveXbrRR 65 #define MoveXwrRR 50 #define MSR 146 #define MULTIPLEBYTECODESETS 1 #define MulRdRd 122 #define NE 1 #define NeedsMergeFixupFlag 2 #define NeedsNonMergeFixupFlag 1 #define NegateR 84 #define NewspeakVM 0 #define Nop 5 #define NoReg -1 #define NotFullyInitialized -1 #define NumObjRefsInRuntime 0 #define NumOopsPerNSC 6 #define NumSendTrampolines 4 #define NumSpecialSelectors 32 #define NumStoreTrampolines 5 #define NumTrampolines 74 #define OrCqR 104 #define OrCwR 112 #define OrOpcode 12 #define OrRR 98 #define PC 15 #define PCReg 15 #define PL 5 #define PopLDM 148 #define PopR 78 #define PrefetchAw 82 #define PrimCallCollectsProfileSamples 16 #define PrimCallDoNotJIT 64 #define PrimCallMayCallBack 4 #define PrimCallNeedsNewMethod 1 #define PrimCallNeedsPrimitiveFunction 2 #define PrimCallOnSmalltalkStack 8 #define PrimErrNoMemory 9 #define PrimErrWritePastObject 17 #define PushCq 80 #define PushCw 81 #define PushR 79 #define PushSTM 149 #define R0 0 #define ReceiverIndex 5 #define ReceiverResultReg 5 #define RetN 9 #define RISCTempReg 12 #define RsbOpcode 3 #define SelectorCannotInterpret 34 #define SelectorDoesNotUnderstand 20 #define SenderIndex 0 #define SendNumArgsReg 6 #define ShouldNotJIT -8 #define SignExtend16RR 140 #define SignExtend8RR 139 #define SistaV1BytecodeSet 1 #define SistaVM 0 #define SMULL 145 #define SmallContextSlots 22 #define SP 13 #define SPReg 13 #define SPURVM 1 #define SqrtRd 124 #define SSBaseOffset 1 #define SSConstant 2 #define SSRegister 3 #define SSSpill 4 #define StackPointerIndex 2 #define Stop 11 #define SubCqR 102 #define SubCwR 110 #define SubOpcode 2 #define SubRdRd 121 #define SubRR 96 #define TempReg 0 #define TempVectReadBarrier 0 #define TstCqR 105 #define TstOpcode 8 #define UnfailingPrimitive 3 #define UnimplementedPrimitive -7 #define ValueIndex 1 #define VarBaseReg 10 #define VC 7 #define VS 6 #define XorCqR 106 #define XorCwR 113 #define XorOpcode 1 #define XorRR 99 #define YoungSelectorInPIC -5 typedef struct _AbstractInstruction { unsigned char opcode; unsigned char machineCodeSize; unsigned char maxSize; unsigned char annotation; unsigned char conditionOrNil; usqInt operands [3]; usqInt address; struct _AbstractInstruction *dependent; unsigned int machineCode [5]; } AbstractInstruction; #define CogOutOfLineLiteralsARMCompiler AbstractInstruction #define CogARMCompiler AbstractInstruction #define CogAbstractInstruction AbstractInstruction typedef struct { AbstractInstruction *fakeHeader; AbstractInstruction *fillInstruction; sqInt numArgs; sqInt numCopied; sqInt numInitialNils; sqInt startpc; AbstractInstruction *entryLabel; AbstractInstruction *stackCheckLabel; sqInt span; sqInt hasInstVarRef; } BlockStart; #define CogBlockStart BlockStart typedef struct _BytecodeDescriptor { sqInt (*generator )(void); sqInt NoDbgRegParms (*spanFunction )(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt); sqInt NoDbgRegParms (*needsFrameFunction )(sqInt); signed char stackDelta; unsigned char opcode; unsigned char numBytes; unsigned isBranchTrue : 1; unsigned isBranchFalse : 1; unsigned isReturn : 1; unsigned isBlockCreation : 1; unsigned isMapped : 1; unsigned isMappedInBlock : 1; unsigned isExtension : 1; unsigned isInstVarRef : 1; unsigned is1ByteInstVarStore : 1; unsigned hasUnsafeJump : 1; } BytecodeDescriptor; #define CogBytecodeDescriptor BytecodeDescriptor typedef struct { sqInt (*primitiveGenerator )(void); sqInt primNumArgs; } PrimitiveDescriptor; #define CogPrimitiveDescriptor PrimitiveDescriptor typedef struct { char type; char spilled; signed char liveRegister; signed char registerr; sqInt offset; sqInt constant; sqInt bcptr; } SimStackEntry; #define CogSimStackEntry SimStackEntry typedef struct { AbstractInstruction *targetInstruction; unsigned char simStackPtr; char isTargetOfBackwardBranch; unsigned short instructionIndex; #if LowcodeVM short simNativeStackPtr; unsigned short simNativeStackSize; #endif } BytecodeFixup; #define CogSSBytecodeFixup BytecodeFixup #define CogBytecodeFixup BytecodeFixup typedef struct { sqInt isReceiverResultRegLive; CogSimStackEntry *ssEntry; } CogSSOptStatus; /*** Function Prototypes ***/ #if !PRODUCTION && defined(PlatformNoDbgRegParms) # define NoDbgRegParms PlatformNoDbgRegParms #endif #if !defined(NoDbgRegParms) # define NoDbgRegParms /*empty*/ #endif #if !defined(NeverInline) # define NeverInline /*empty*/ #endif static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction); static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask); static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral); static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp); static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister); static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal); static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal); static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction); static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump); static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress); static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction); static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress); static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta); static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta); static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget); static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject); static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg); static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr); static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask); static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset); static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset); static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize); static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize); static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask); static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask); static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress); static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL); static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction); static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32); static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR); static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush); static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL); static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr); static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft); static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize); static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB); static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB); static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative); static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder); static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer); static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers); static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers); static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest); static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs); static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored); static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers); static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc); static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress); static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr); static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr); static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr); static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr); static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr); static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr); static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr); static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr); static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc); static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode); static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc); static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand); static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc); static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr); static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize); static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize); static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc); static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc); static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue); static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg); static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize); static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes); static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords); static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8); static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset); static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue); static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg); static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg); static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags); static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs); static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr); static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg); static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize); static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg); static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta); static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode); static sqInt NoDbgRegParms shiftSetsConditionCodesFor(AbstractInstruction * self_in_shiftSetsConditionCodesFor, sqInt aConditionalJumpOpcode); static sqInt NoDbgRegParms stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes); static AbstractInstruction * NoDbgRegParms stopsFromto(AbstractInstruction * self_in_stopsFromto, sqInt startAddr, sqInt endAddr); static sqInt NoDbgRegParms strbrnplusimm(AbstractInstruction * self_in_strbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms strbrnrm(AbstractInstruction * self_in_strbrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms strhrnplusimm(AbstractInstruction * self_in_strhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue); static sqInt NoDbgRegParms strhrnrm(AbstractInstruction * self_in_strhrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms strrnplusImm(AbstractInstruction * self_in_strrnplusImm, sqInt srcReg, sqInt baseReg, sqInt immediate12bitValue); static sqInt NoDbgRegParms strrnplusimm(AbstractInstruction * self_in_strrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms strrnrm(AbstractInstruction * self_in_strrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms subsrnimmror(AbstractInstruction * self_in_subsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms subrnimmror(AbstractInstruction * self_in_subrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms tstrnimmror(AbstractInstruction * self_in_tstrnimmror, sqInt ignored, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms zoneCallsAreRelative(AbstractInstruction * self_in_zoneCallsAreRelative); static CogMethod * NoDbgRegParms cmHomeMethod(CogBlockMethod * self_in_cmHomeMethod); static sqInt NoDbgRegParms isBranch(BytecodeDescriptor * self_in_isBranch); static AbstractInstruction * NoDbgRegParms gAddCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * NoDbgRegParms gAndCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * NoDbgRegParms gAndCqRR(sqInt quickConstant, sqInt srcReg, sqInt destReg); extern sqInt abortOffset(void); static void addCleanBlockStarts(void); extern void addCogMethodsToHeapMap(void); static sqInt NoDbgRegParms addressIsInCurrentCompilation(sqInt address); static sqInt NoDbgRegParms addressIsInFixups(BytecodeFixup *address); static sqInt NoDbgRegParms addressIsInInstructions(AbstractInstruction *address); static sqInt NoDbgRegParms addressOfEndOfCaseinCPIC(sqInt n, CogMethod *cPIC); static sqInt NoDbgRegParms alignUptoRoutineBoundary(sqInt anAddress); static sqInt allMachineCodeObjectReferencesValid(void); static sqInt allMethodsHaveCorrectHeader(void); static AbstractInstruction * NoDbgRegParms annotateAbsolutePCRef(AbstractInstruction *abstractInstruction); static AbstractInstruction * NoDbgRegParms annotateBytecode(AbstractInstruction *abstractInstruction); static AbstractInstruction * NoDbgRegParms annotateobjRef(AbstractInstruction *abstractInstruction, sqInt anOop); static void NoDbgRegParms assertSaneJumpTarget(AbstractInstruction *jumpTarget); static sqInt NoDbgRegParms blockDispatchTargetsForperformarg(CogMethod *cogMethod, usqInt (*binaryFunction)(sqInt mcpc, sqInt arg), sqInt arg); extern sqInt bytecodePCForstartBcpcin(sqInt mcpc, sqInt startbcpc, CogBlockMethod *cogMethod); static AbstractInstruction * NoDbgRegParms CallFullRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved); static AbstractInstruction * NoDbgRegParms CallRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved); static AbstractInstruction * NoDbgRegParms gCall(sqInt callTarget); static AbstractInstruction * NoDbgRegParms gCmpCqR(sqInt quickConstant, sqInt reg); extern void callCogCodePopReceiver(void); extern void callCogCodePopReceiverAndClassRegs(void); extern sqInt ceCPICMissreceiver(CogMethod *cPIC, sqInt receiver); extern void ceFree(void *pointer); extern void* ceMalloc(size_t size); extern sqInt ceSICMiss(sqInt receiver); extern void checkAssertsEnabledInCogit(void); static sqInt NoDbgRegParms checkIfValidOopRefAndTargetpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod); static sqInt NoDbgRegParms checkIfValidOopRefpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod); extern sqInt checkIntegrityOfObjectReferencesInCode(sqInt gcModes); static sqInt NoDbgRegParms checkMaybeObjRefInClosedPIC(sqInt maybeObject); static sqInt NoDbgRegParms checkValidObjectReferencesInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms NeverInline cleanUpFailingCogCodeConstituents(CogMethod *cogMethodArg); static sqInt NoDbgRegParms closedPICRefersToUnmarkedObject(CogMethod *cPIC); extern char * codeEntryFor(char *address); extern char * codeEntryNameFor(char *address); extern sqInt cogCodeBase(void); extern sqInt cogCodeConstituents(sqInt withDetails); static sqInt NoDbgRegParms cogExtendPICCaseNMethodtagisMNUCase(CogMethod *cPIC, sqInt caseNMethod, sqInt caseNTag, sqInt isMNUCase); extern CogMethod * cogFullBlockMethodnumCopied(sqInt aMethodObj, sqInt numCopied); extern void cogitPostGCAction(sqInt gcMode); extern sqInt cogMethodDoesntLookKosher(CogMethod *cogMethod); extern CogMethod * cogMNUPICSelectorreceivermethodOperandnumArgs(sqInt selector, sqInt rcvr, sqInt methodOperand, sqInt numArgs); static CogMethod * NoDbgRegParms cogOpenPICSelectornumArgs(sqInt selector, sqInt numArgs); static CogMethod * NoDbgRegParms cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase(sqInt selector, sqInt numArgs, CogMethod *case0CogMethod, sqInt case1MethodOrNil, sqInt case1Tag, sqInt isMNUCase); extern CogMethod * cogselector(sqInt aMethodObj, sqInt aSelectorOop); static sqInt NoDbgRegParms collectCogConstituentForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg); static sqInt NoDbgRegParms collectCogMethodConstituent(CogMethod *cogMethod); extern void compactCogCompiledCode(void); static void compactPICsWithFreedTargets(void); static AbstractInstruction * compileAbort(void); static sqInt NoDbgRegParms compileBlockDispatchFromto(sqInt lowBlockStartIndex, sqInt highBlockStartIndex); static void NoDbgRegParms compileBlockEntry(BlockStart *blockStart); static void NoDbgRegParms compileCallFornumArgsargargargargresultRegregsToSave(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt resultRegOrNone, sqInt regMask); static AbstractInstruction * compileCPICEntry(void); static sqInt NoDbgRegParms compileEntireFullBlockMethod(sqInt numCopied); static void compileEntry(void); static sqInt compileFullBlockEntry(void); static sqInt compileMethodBody(void); static sqInt NoDbgRegParms compilePICAbort(sqInt numArgs); static void NoDbgRegParms compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone); static void computeEntryOffsets(void); static void computeFullBlockEntryOffsets(void); static void computeMaximumSizes(void); static sqInt NoDbgRegParms configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(CogMethod *cPIC, CogMethod *case0CogMethod, sqInt case1Method, sqInt case1Tag, sqInt isMNUCase, sqInt numArgs, sqInt addrDelta); static sqInt NoDbgRegParms configureMNUCPICmethodOperandnumArgsdelta(CogMethod *cPIC, sqInt methodOperand, sqInt numArgs, sqInt addrDelta); static sqInt NoDbgRegParms cPICCompactAndIsNowEmpty(CogMethod *cPIC); static sqInt NoDbgRegParms cPICHasForwardedClass(CogMethod *cPIC); static sqInt NoDbgRegParms cPICHasFreedTargets(CogMethod *cPIC); static sqInt cPICPrototypeCaseOffset(void); static sqInt NoDbgRegParms cPICHasTarget(CogMethod *cPIC, CogMethod *targetMethod); static sqInt NoDbgRegParms createCPICData(CogMethod *cPIC); static AbstractInstruction * NoDbgRegParms gDivRRQuoRem(sqInt rDivisor, sqInt rDividend, sqInt rQuotient, sqInt rRemainder); extern sqInt defaultCogCodeSize(void); static sqInt NoDbgRegParms deltaToSkipPrimAndErrorStoreInheader(sqInt aMethodObj, sqInt aMethodHeader); static sqInt NoDbgRegParms endPCOf(sqInt aMethod); extern void enterCogCodePopReceiver(void); static sqInt NoDbgRegParms entryPointTagIsSelector(sqInt entryPoint); static sqInt NoDbgRegParms expectedClosedPICPrototype(CogMethod *cPIC); static sqInt extABytecode(void); static sqInt extBBytecode(void); static sqInt NoDbgRegParms fillInBlockHeadersAt(sqInt startAddress); static CogMethod * NoDbgRegParms fillInMethodHeadersizeselector(CogMethod *method, sqInt size, sqInt selector); static sqInt NoDbgRegParms findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetBcpc); static usqInt NoDbgRegParms findBlockMethodWithEntrystartBcpc(sqInt blockEntryMcpc, sqInt startBcpc); static sqInt NoDbgRegParms findMapLocationForMcpcinMethod(usqInt targetMcpc, CogMethod *cogMethod); extern CogBlockMethod * findMethodForStartBcpcinHomeMethod(sqInt startbcpc, CogMethod *cogMethod); static sqInt NoDbgRegParms findIsBackwardBranchMcpcBcpcMatchingMcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetMcpc); static sqInt NoDbgRegParms firstMappedPCFor(CogMethod *cogMethod); static sqInt firstPrototypeMethodOop(void); static BytecodeFixup * NoDbgRegParms fixupAt(sqInt fixupPC); extern void followForwardedLiteralsIn(CogMethod *cogMethod); extern void followForwardedMethods(void); static sqInt NoDbgRegParms followMaybeObjRefInClosedPICAt(sqInt mcpc); static sqInt NoDbgRegParms followMethodReferencesInClosedPIC(CogMethod *cPIC); extern void freeUnmarkedMachineCode(void); static AbstractInstruction * NoDbgRegParms genCallMustBeBooleanFor(sqInt boolean); static sqInt genCheckForInterruptsTrampoline(void); static AbstractInstruction * NoDbgRegParms genConditionalBranchoperand(sqInt opcode, sqInt operandOne); static void (*genEnilopmartForandandforCallcalled(sqInt regArg1, sqInt regArg2OrNone, sqInt regArg3OrNone, sqInt forCall, char *trampolineName))(void) ; static void NoDbgRegParms genEnilopmartReturn(sqInt forCall); static void NoDbgRegParms generateCaptureCStackPointers(sqInt captureFramePointer); static void generateClosedPICPrototype(void); static CogMethod * generateCogFullBlock(void); static CogMethod * NoDbgRegParms generateCogMethod(sqInt selector); static sqInt NoDbgRegParms generateMapAtstart(usqInt addressOrNull, usqInt startAddress); static void generateOpenPICPrototype(void); static void generateRunTimeTrampolines(void); static void generateStackPointerCapture(void); static void generateTrampolines(void); static BytecodeDescriptor * NoDbgRegParms generatorForPC(sqInt pc); static void genGetLeafCallStackPointer(void); static sqInt NoDbgRegParms genInnerPICAbortTrampoline(char *name); static sqInt genLoadCStackPointersForPrimCall(void); static void NoDbgRegParms genLoadInlineCacheWithSelector(sqInt selectorIndex); static sqInt genNonLocalReturnTrampoline(void); static sqInt NoDbgRegParms genReturnTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0); static sqInt NoDbgRegParms genSmalltalkToCStackSwitch(sqInt pushLinkReg); static sqInt NoDbgRegParms genTrampolineForcalled(void *aRoutine, char *aString); static sqInt NoDbgRegParms genTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0); static sqInt NoDbgRegParms genTrampolineForcalledargargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcalledargargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regMask); static sqInt NoDbgRegParms genTrampolineForcalledargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcalledargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regMask); static sqInt NoDbgRegParms genTrampolineForcalledargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(void *aRoutine, char *trampolineName, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone, sqInt appendBoolean); static sqInt NoDbgRegParms genTrampolineForcalledregsToSave(void *aRoutine, char *aString, sqInt regMask); static AbstractInstruction * NoDbgRegParms gen(sqInt opcode); static AbstractInstruction * NoDbgRegParms genoperand(sqInt opcode, sqInt operand); static AbstractInstruction * NoDbgRegParms genoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo); static AbstractInstruction * NoDbgRegParms genoperandoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo, sqInt operandThree); static sqInt NoDbgRegParms getLiteral(sqInt litIndex); static sqInt getOpcodeIndex(void); static sqInt NoDbgRegParms incrementUsageOfTargetIfLinkedSendmcpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms indexForSelectorinat(sqInt selector, CogMethod *cogMethod, sqInt mcpc); static sqInt initialClosedPICUsageCount(void); static void initializeBackend(void); extern void initializeCodeZoneFromupTo(sqInt startAddress, sqInt endAddress); static sqInt initialMethodUsageCount(void); static sqInt initialOpenPICUsageCount(void); static sqInt NoDbgRegParms inlineCacheValueForSelectorinat(sqInt selector, CogMethod *aCogMethod, sqInt mcpc); static sqInt NoDbgRegParms inverseBranchFor(sqInt opcode); static sqInt NoDbgRegParms isPCMappedAnnotation(sqInt annotation); extern sqInt isPCWithinMethodZone(void *address); extern sqInt isSendReturnPC(sqInt retpc); static AbstractInstruction * NoDbgRegParms gJumpFPEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPGreaterOrEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPGreater(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPNotEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gLogicalShiftLeftCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * lastOpcode(void); extern void linkSendAtintooffsetreceiver(sqInt callSiteReturnAddress, CogMethod *sendingMethod, CogMethod *targetMethod, sqInt theEntryOffset, sqInt receiver); static BytecodeDescriptor * loadBytesAndGetDescriptor(void); static void NoDbgRegParms loadSubsequentBytesForDescriptorat(BytecodeDescriptor *descriptor, sqInt pc); static AbstractInstruction * NoDbgRegParms gMoveAwR(sqInt address, sqInt reg); static AbstractInstruction * NoDbgRegParms gMoveCwR(sqInt wordConstant, sqInt reg); static sqInt NoDbgRegParms mapEndFor(CogMethod *cogMethod); static sqInt NoDbgRegParms mapForperformUntilarg(CogMethod *cogMethod, sqInt (*functionSymbol)(sqInt annotation, char *mcpc, sqInt arg), sqInt arg); static sqInt NoDbgRegParms mapObjectReferencesInClosedPIC(CogMethod *cPIC); static void mapObjectReferencesInGeneratedRuntime(void); static void mapObjectReferencesInMachineCodeForBecome(void); static void mapObjectReferencesInMachineCodeForFullGC(void); static void mapObjectReferencesInMachineCodeForYoungGC(void); extern void mapObjectReferencesInMachineCode(sqInt gcMode); extern void markAndTraceMachineCodeOfMarkedMethods(void); static void markAndTraceObjectReferencesInGeneratedRuntime(void); static sqInt NoDbgRegParms markAndTraceOrFreeCogMethodfirstVisit(CogMethod *cogMethod, sqInt firstVisit); static sqInt NoDbgRegParms markAndTraceOrFreePICTargetin(sqInt entryPoint, CogMethod *cPIC); static sqInt NoDbgRegParms markLiteralsAndUnlinkIfUnmarkedSendpcmethod(sqInt annotation, char *mcpc, sqInt cogMethod); static sqInt NoDbgRegParms markLiteralspcmethod(sqInt annotation, char *mcpc, sqInt cogMethod); extern void markMethodAndReferents(CogBlockMethod *aCogMethod); extern usqInt maxCogMethodAddress(void); static sqInt maybeAllocAndInitIRCs(void); static sqInt NoDbgRegParms maybeFreeCogMethodDoesntLookKosher(CogMethod *cogMethod); static void NoDbgRegParms maybeMarkCountersIn(CogMethod *cogMethod); static sqInt mclassIsSmallInteger(void); extern usqInt mcPCForBackwardBranchstartBcpcin(sqInt bcpc, sqInt startbcpc, CogBlockMethod *cogMethod); static sqInt NoDbgRegParms methodhasSameCodeAscheckPenultimate(sqInt methodA, sqInt methodB, sqInt comparePenultimateLiteral); extern sqInt minCogMethodAddress(void); extern sqInt mnuOffset(void); static sqInt NoDbgRegParms needsFrameIfImmutability(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameIfInBlock(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameNever(sqInt stackDelta); static sqInt NoDbgRegParms noAssertMethodClassAssociationOf(sqInt methodPointer); static sqInt noCogMethodsMaximallyMarked(void); static sqInt NoDbgRegParms noTargetsFreeInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms outputInstructionsAt(sqInt startAddress); static sqInt NoDbgRegParms outputInstructionsForGeneratedRuntimeAt(sqInt startAddress); static AbstractInstruction * NoDbgRegParms gPushCw(sqInt wordConstant); extern sqInt patchToOpenPICFornumArgsreceiver(sqInt selector, sqInt numArgs, sqInt receiver); static sqInt picAbortDiscriminatorValue(void); static sqInt picInterpretAbortOffset(void); extern void printCogMethodFor(void *address); extern void printTrampolineTable(void); static sqInt processorHasDivQuoRemAndMClassIsSmallInteger(void); static sqInt processorHasMultiplyAndMClassIsSmallInteger(void); static void NoDbgRegParms recordGeneratedRunTimeaddress(char *aString, sqInt address); extern sqInt recordPrimTraceFunc(void); static void recordRunTimeObjectReferences(void); static sqInt NoDbgRegParms registerMaskFor(sqInt reg); static void NoDbgRegParms relocateCallsAndSelfReferencesInMethod(CogMethod *cogMethod); static void NoDbgRegParms relocateCallsInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms relocateIfCallOrMethodReferencemcpcdelta(sqInt annotation, char *mcpc, sqInt refDelta); static sqInt NoDbgRegParms remapIfObjectRefpchasYoung(sqInt annotation, char *mcpc, sqInt hasYoungPtr); static sqInt NoDbgRegParms remapMaybeObjRefInClosedPICAt(sqInt mcpc); static void NoDbgRegParms rewriteCPICCaseAttagobjReftarget(sqInt followingAddress, sqInt newTag, sqInt newObjRef, sqInt newTarget); static AbstractInstruction * NoDbgRegParms gSubCwR(sqInt wordConstant, sqInt reg); static sqInt scanForCleanBlocks(void); extern void setBreakMethod(sqInt anObj); extern void setPostCompileHook(void (*aFunction)(CogMethod *)); extern void setSelectorOfto(CogMethod *cogMethod, sqInt aSelectorOop); static sqInt NoDbgRegParms spanForCleanBlockStartingAt(sqInt startPC); static sqInt subsequentPrototypeMethodOop(void); extern sqInt traceLinkedSendOffset(void); static sqInt NoDbgRegParms trampolineArgConstant(sqInt booleanOrInteger); static char * NoDbgRegParms trampolineNamenumArgs(char *routinePrefix, sqInt numArgs); static char * NoDbgRegParms trampolineNamenumArgslimit(char *routinePrefix, int numArgs, sqInt argsLimit); static char * NoDbgRegParms trampolineNamenumRegArgs(char *routinePrefix, sqInt numArgs); static sqInt unknownBytecode(void); extern void unlinkAllSends(void); static sqInt NoDbgRegParms unlinkIfFreeOrLinkedSendpcof(sqInt annotation, char *mcpc, sqInt theSelector); static sqInt NoDbgRegParms unlinkIfInvalidClassSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendToFreepcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendpcto(sqInt annotation, char *mcpc, sqInt theCogMethod); extern void unlinkSendsLinkedForInvalidClasses(void); extern void unlinkSendsOfisMNUSelector(sqInt selector, sqInt isMNUSelector); extern void unlinkSendsToFree(void); extern void unlinkSendsToandFreeIf(sqInt targetMethodObject, sqInt freeIfTrue); static AbstractInstruction * NoDbgRegParms gXorCwR(sqInt wordConstant, sqInt reg); static void zeroOpcodeIndex(void); static void zeroOpcodeIndexForNewOpcodes(void); static sqInt NoDbgRegParms counters(CogMethod * self_in_counters); extern void addAllToYoungReferrers(void); static void NoDbgRegParms addToOpenPICList(CogMethod *anOpenPIC); static void NoDbgRegParms addToYoungReferrers(CogMethod *cogMethod); static usqInt NoDbgRegParms allocate(sqInt numBytes); static void clearCogCompiledCode(void); static void compactCompiledCode(void); static void NoDbgRegParms ensureInYoungReferrers(CogMethod *cogMethod); static void followForwardedLiteralsInOpenPICList(void); extern void freeMethod(CogMethod *cogMethod); static void freeOlderMethodsForCompaction(void); static sqInt kosherYoungReferrers(void); static void NoDbgRegParms manageFromto(sqInt theStartAddress, sqInt theLimitAddress); extern CogMethod * methodFor(void *address); extern sqInt methodsCompiledToMachineCodeInto(sqInt arrayObj); extern sqInt numMethods(void); extern sqInt numMethodsOfType(sqInt cogMethodType); static sqInt NoDbgRegParms occurrencesInYoungReferrers(CogMethod *cogMethod); static CogMethod * NoDbgRegParms openPICWithSelector(sqInt aSelector); static void planCompaction(void); extern void printCogMethods(void); extern void printCogMethodsOfType(sqInt cmType); extern void printCogMethodsWithMethod(sqInt methodOop); extern void printCogMethodsWithPrimitive(sqInt primIdx); extern void printCogMethodsWithSelector(sqInt selectorOop); extern void printCogYoungReferrers(void); extern sqInt printOpenPICList(void); static sqInt pruneYoungReferrers(void); static sqInt relocateAndPruneYoungReferrers(void); static sqInt relocateMethodsPreCompaction(void); static sqInt NoDbgRegParms removeFromOpenPICList(CogMethod *anOpenPIC); static void voidOpenPICList(void); static void voidYoungReferrersPostTenureAll(void); extern char * whereIsMaybeCodeThing(sqInt anOop); static sqInt NoDbgRegParms checkValidObjectReference(sqInt anOop); static AbstractInstruction * NoDbgRegParms genCmpClassFloatCompactIndexR(sqInt reg); static AbstractInstruction * NoDbgRegParms genCmpClassMethodContextCompactIndexR(sqInt reg); static sqInt NoDbgRegParms genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)); static sqInt NoDbgRegParms genDoubleComparisoninvert(AbstractInstruction * NoDbgRegParms (*jumpOpcodeGenerator)(void *), sqInt invertComparison); static sqInt NoDbgRegParms genGetMethodHeaderOfintoscratch(sqInt methodReg, sqInt headerReg, sqInt scratchReg); static sqInt NoDbgRegParms genLoadSlotsourceRegdestReg(sqInt index, sqInt sourceReg, sqInt destReg); static sqInt genPrimitiveAdd(void); static sqInt genPrimitiveAsFloat(void); static sqInt genPrimitiveBitAnd(void); static sqInt genPrimitiveBitOr(void); static sqInt genPrimitiveBitShift(void); static sqInt genPrimitiveBitXor(void); static sqInt genPrimitiveClass(void); static sqInt genPrimitiveDiv(void); static sqInt genPrimitiveDivide(void); static sqInt genPrimitiveEqual(void); static sqInt genPrimitiveFloatAdd(void); static sqInt genPrimitiveFloatDivide(void); static sqInt genPrimitiveFloatEqual(void); static sqInt genPrimitiveFloatGreaterOrEqual(void); static sqInt genPrimitiveFloatGreaterThan(void); static sqInt genPrimitiveFloatLessOrEqual(void); static sqInt genPrimitiveFloatLessThan(void); static sqInt genPrimitiveFloatMultiply(void); static sqInt genPrimitiveFloatNotEqual(void); static sqInt genPrimitiveFloatSquareRoot(void); static sqInt genPrimitiveFloatSubtract(void); static sqInt genPrimitiveGreaterOrEqual(void); static sqInt genPrimitiveGreaterThan(void); static sqInt genPrimitiveIdentical(void); static sqInt genPrimitiveLessOrEqual(void); static sqInt genPrimitiveLessThan(void); static sqInt genPrimitiveMod(void); static sqInt genPrimitiveMultiply(void); static sqInt genPrimitiveNewMethod(void); static sqInt genPrimitiveNotEqual(void); static sqInt genPrimitiveNotIdentical(void); static sqInt genPrimitiveQuo(void); static sqInt genPrimitiveSubtract(void); static sqInt NoDbgRegParms genSmallIntegerComparison(sqInt jumpOpcode); static sqInt NoDbgRegParms genSmallIntegerComparisonorDoubleComparisoninvert(sqInt jumpOpcode, AbstractInstruction * NoDbgRegParms (*jumpFPOpcodeGenerator)(void *), sqInt invertComparison); static sqInt NoDbgRegParms isUnannotatableConstant(CogSimStackEntry *simStackEntry); static sqInt NoDbgRegParms classForInlineCacheTag(sqInt inlineCacheTag); static sqInt NoDbgRegParms genAddSmallIntegerTagsTo(sqInt aRegister); static sqInt NoDbgRegParms genClearAndSetSmallIntegerTagsIn(sqInt scratchReg); static void NoDbgRegParms genConvertCharacterToSmallIntegerInReg(sqInt reg); static sqInt NoDbgRegParms genConvertIntegerToSmallIntegerInReg(sqInt reg); static void NoDbgRegParms genConvertSmallIntegerToCharacterInReg(sqInt reg); static sqInt NoDbgRegParms genConvertSmallIntegerToIntegerInReg(sqInt reg); static sqInt NoDbgRegParms genGetHashFieldNonImmOfasSmallIntegerInto(sqInt instReg, sqInt destReg); static sqInt NoDbgRegParms genGetHashFieldNonImmOfinto(sqInt instReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genGetInlineCacheClassTagFromintoforEntry(sqInt sourceReg, sqInt destReg, sqInt forEntry); static sqInt NoDbgRegParms genGetNumBytesOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetOverflowSlotsOfinto(sqInt srcReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genJumpIsSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg); static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerInScratchReg(sqInt aRegister); static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg); static AbstractInstruction * NoDbgRegParms genJumpNotSmallInteger(sqInt aRegister); static AbstractInstruction * NoDbgRegParms genJumpSmallInteger(sqInt aRegister); static sqInt genPrimitiveAtPut(void); static sqInt NoDbgRegParms genPrimitiveAtPutSigned(sqInt signedVersion); static sqInt NoDbgRegParms genPrimitiveAtSigned(sqInt signedVersion); static sqInt genPrimitiveIdentityHash(void); static sqInt genPrimitiveImmediateAsInteger(void); static sqInt genPrimitiveNew(void); static sqInt genPrimitiveNewWithArg(void); static sqInt genPrimitiveShallowCopy(void); static sqInt genPrimitiveStringAt(void); static sqInt genPrimitiveStringAtPut(void); static sqInt NoDbgRegParms genRemoveSmallIntegerTagsInScratchReg(sqInt scratchReg); static sqInt NoDbgRegParms genShiftAwaySmallIntegerTagsInScratchReg(sqInt scratchReg); static sqInt NoDbgRegParms getLiteralCountOfplusOneinBytesintoscratch(sqInt methodReg, sqInt plusOne, sqInt inBytes, sqInt litCountReg, sqInt scratchReg); static sqInt NoDbgRegParms inlineCacheTagForInstance(sqInt oop); static AbstractInstruction * NoDbgRegParms jumpNotSmallIntegerUnsignedValueInRegister(sqInt reg); static sqInt NoDbgRegParms markAndTraceCacheTagLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address); static sqInt numSmallIntegerBits(void); static sqInt NoDbgRegParms validInlineCacheTag(usqInt classIndexOrTagPattern); static sqInt NoDbgRegParms cacheTagIsMarked(sqInt cacheTag); static void callStoreCheckTrampoline(void); static sqInt NoDbgRegParms checkValidDerivedObjectReference(sqInt bodyAddress); static sqInt NoDbgRegParms checkValidOopReference(sqInt anOop); static sqInt NoDbgRegParms couldBeDerivedObject(sqInt bodyAddress); static sqInt NoDbgRegParms couldBeObject(sqInt literal); static sqInt NoDbgRegParms genActiveContextTrampolineLargeinBlockcalled(sqInt isLarge, sqInt isInBlock, char *aString); static AbstractInstruction * NoDbgRegParms genAllocFloatValueintoscratchRegscratchReg(sqInt dpreg, sqInt resultReg, sqInt scratch1, sqInt scratch2); static AbstractInstruction * NoDbgRegParms genCheckRememberedBitOfscratch(sqInt objReg, sqInt scratchReg); static sqInt NoDbgRegParms genConvertCharacterToCodeInReg(sqInt reg); static sqInt NoDbgRegParms genConvertIntegerToCharacterInReg(sqInt reg); static sqInt NoDbgRegParms genCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock); static sqInt NoDbgRegParms genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(sqInt compiledBlock, sqInt numArgs, sqInt numCopied, sqInt ignoreContext, sqInt contextNumArgs, sqInt contextIsLarge, sqInt contextIsBlock); static sqInt NoDbgRegParms genEnsureObjInRegNotForwardedscratchReg(sqInt reg, sqInt scratch); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchReg(sqInt reg, sqInt scratch); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(sqInt reg, sqInt scratch, sqInt fwdJumpTarget, sqInt nonFwdJumpTargetOrZero); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(sqInt reg, sqInt scratch, sqInt index, sqInt objReg); static void generateObjectRepresentationTrampolines(void); static sqInt NoDbgRegParms genGetActiveContextLargeinBlock(sqInt isLarge, sqInt isInBlock); static sqInt NoDbgRegParms genGetActiveContextNumArgslargeinBlock(sqInt numArgs, sqInt isLargeContext, sqInt isInBlock); static sqInt NoDbgRegParms genGetBitsofFormatByteOfinto(sqInt mask, sqInt sourceReg, sqInt destReg); static sqInt NoDbgRegParms genGetClassIndexOfNonImminto(sqInt sourceReg, sqInt destReg); static sqInt NoDbgRegParms genGetClassObjectOfClassIndexintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg); static sqInt NoDbgRegParms genGetClassObjectOfintoscratchReginstRegIsReceiver(sqInt instReg, sqInt destReg, sqInt scratchReg, sqInt instRegIsReceiver); static AbstractInstruction * NoDbgRegParms genGetClassTagOfintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg); static sqInt NoDbgRegParms genGetCompactClassIndexNonImmOfinto(sqInt instReg, sqInt destReg); static sqInt NoDbgRegParms genGetDoubleValueOfinto(sqInt srcReg, sqInt destFPReg); static sqInt NoDbgRegParms genGetFormatOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(sqInt sourceReg, sqInt destReg, sqInt scratchRegOrNone); static sqInt NoDbgRegParms genGetNumSlotsOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetRawSlotSizeOfNonImminto(sqInt sourceReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genJumpImmediate(sqInt aRegister); #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpImmutablescratchReg(sqInt sourceReg, sqInt scratchReg); #endif /* IMMUTABILITY */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpMutablescratchReg(sqInt sourceReg, sqInt scratchReg); #endif /* IMMUTABILITY */ static AbstractInstruction * NoDbgRegParms genJumpNotCharacterInScratchReg(sqInt reg); static sqInt NoDbgRegParms genNewArrayOfSizeinitialized(sqInt size, sqInt initialized); static sqInt NoDbgRegParms genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock); static sqInt genPrimitiveAsCharacter(void); static sqInt genPrimitiveAt(void); static sqInt NoDbgRegParms genPrimitiveIdenticalOrNotIf(sqInt orNot); static sqInt genPrimitiveIntegerAt(void); static sqInt genPrimitiveIntegerAtPut(void); static sqInt genPrimitiveObjectAt(void); static sqInt genPrimitiveSize(void); static sqInt genPrimitiveStringCompareWith(void); static sqInt genPrimitiveStringReplace(void); static sqInt NoDbgRegParms genSetSmallIntegerTagsIn(sqInt scratchReg); static sqInt genStoreCheckContextReceiverTrampoline(void); static sqInt NoDbgRegParms genStoreCheckReceiverRegvalueRegscratchReginFrame(sqInt destReg, sqInt valueReg, sqInt scratchReg, sqInt inFrame); static sqInt NoDbgRegParms genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt inFrame, sqInt needsStoreCheck); static sqInt NoDbgRegParms genStoreSourceRegslotIndexintoNewObjectInDestReg(sqInt sourceReg, sqInt index, sqInt destReg); #if IMMUTABILITY static sqInt NoDbgRegParms genStoreTrampolineCalledinstVarIndex(char *trampolineName, sqInt instVarIndex); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needsStoreCheck, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ static sqInt getActiveContextAllocatesInMachineCode(void); static sqInt NoDbgRegParms inlineCacheTagIsYoung(sqInt cacheTag); static AbstractInstruction * NoDbgRegParms jumpNotCharacterUnsignedValueInRegister(sqInt reg); static sqInt NoDbgRegParms markAndTraceLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address); static void NoDbgRegParms markAndTraceLiteralinat(sqInt literal, CogMethod *cogMethod, sqInt *address); static void NoDbgRegParms markAndTraceUpdatedLiteralin(sqInt objOop, CogMethod *cogMethodOrNil); static sqInt NoDbgRegParms maybeCompileRetryOnPrimitiveFail(sqInt primIndex); static sqInt NoDbgRegParms maybeShiftClassTagRegisterForMethodCacheProbe(sqInt classTagReg); static sqInt numCharacterBits(void); extern sqInt numRegArgs(void); static sqInt NoDbgRegParms remapObject(sqInt objOop); static sqInt NoDbgRegParms remapOop(sqInt objOop); static sqInt NoDbgRegParms shouldAnnotateObjectReference(sqInt anOop); static sqInt NoDbgRegParms slotOffsetOfInstVarIndex(sqInt index); static sqInt NoDbgRegParms cmpC32RTempByteSize(AbstractInstruction * self_in_cmpC32RTempByteSize); static AbstractInstruction * NoDbgRegParms concretizeLiteral(AbstractInstruction * self_in_concretizeLiteral); static sqInt NoDbgRegParms inlineCacheTagAt(AbstractInstruction * self_in_inlineCacheTagAt, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms isPCDependent(AbstractInstruction * self_in_isPCDependent); static sqInt NoDbgRegParms literalBeforeFollowingAddress(AbstractInstruction * self_in_literalBeforeFollowingAddress, sqInt followingAddress); static sqInt NoDbgRegParms literalLoadInstructionBytes(AbstractInstruction * self_in_literalLoadInstructionBytes); static sqInt NoDbgRegParms loadLiteralByteSize(AbstractInstruction * self_in_loadLiteralByteSize); static sqInt NoDbgRegParms nsSendCacheAt(AbstractInstruction * self_in_nsSendCacheAt, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms outOfLineLiteralOpcodeLimit(AbstractInstruction * self_in_outOfLineLiteralOpcodeLimit); static sqInt NoDbgRegParms pcRelativeAddressAt(AbstractInstruction * self_in_pcRelativeAddressAt, sqInt instrAddress); static AbstractInstruction * NoDbgRegParms relocateMethodReferenceBeforeAddressby(AbstractInstruction * self_in_relocateMethodReferenceBeforeAddressby, sqInt pc, sqInt delta); static sqInt NoDbgRegParms rewriteFullTransferAttargetexpectedInstruction(AbstractInstruction * self_in_rewriteFullTransferAttargetexpectedInstruction, usqInt callSiteReturnAddress, usqInt callTargetAddress, sqInt expectedInstruction); static sqInt NoDbgRegParms rewriteInlineCacheAttagtarget(AbstractInstruction * self_in_rewriteInlineCacheAttagtarget, usqInt callSiteReturnAddress, sqInt cacheTag, usqInt callTargetAddress); static AbstractInstruction * NoDbgRegParms rewriteInlineCacheTagat(AbstractInstruction * self_in_rewriteInlineCacheTagat, sqInt cacheTag, sqInt callSiteReturnAddress); static usqInt NoDbgRegParms sizePCDependentInstructionAt(AbstractInstruction * self_in_sizePCDependentInstructionAt, sqInt eventualAbsoluteAddress); static AbstractInstruction * NoDbgRegParms storeLiteralbeforeFollowingAddress(AbstractInstruction * self_in_storeLiteralbeforeFollowingAddress, sqInt literal, sqInt followingAddress); static AbstractInstruction * NoDbgRegParms updateLabel(AbstractInstruction * self_in_updateLabel, AbstractInstruction *labelInstruction); static sqInt NoDbgRegParms usesOutOfLineLiteral(AbstractInstruction * self_in_usesOutOfLineLiteral); static SimStackEntry * NoDbgRegParms ensureSpilledAtfrom(SimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister); static sqInt NoDbgRegParms isSameEntryAs(SimStackEntry * self_in_isSameEntryAs, CogSimStackEntry *ssEntry); static SimStackEntry * NoDbgRegParms popToReg(SimStackEntry * self_in_popToReg, sqInt reg); static sqInt NoDbgRegParms registerMask(SimStackEntry * self_in_registerMask); static sqInt NoDbgRegParms registerMaskOrNone(SimStackEntry * self_in_registerMaskOrNone); static sqInt NoDbgRegParms registerOrNone(SimStackEntry * self_in_registerOrNone); static SimStackEntry * NoDbgRegParms storeToReg(SimStackEntry * self_in_storeToReg, sqInt reg); static sqInt NoDbgRegParms isMergeFixup(BytecodeFixup * self_in_isMergeFixup); static AbstractInstruction * NoDbgRegParms allocateLiteral(sqInt aLiteral); static AbstractInstruction * NoDbgRegParms checkLiteralforInstruction(sqInt literal, AbstractInstruction *anInstruction); static AbstractInstruction * NoDbgRegParms checkQuickConstantforInstruction(sqInt literal, AbstractInstruction *anInstruction); static sqInt NoDbgRegParms dumpLiterals(sqInt generateBranchAround); static sqInt endSizeOffset(void); static sqInt NoDbgRegParms literalInstructionInRange(AbstractInstruction *litInst); static AbstractInstruction * NoDbgRegParms locateLiteral(sqInt aLiteral); static sqInt NoDbgRegParms mustDumpLiterals(sqInt currentOpcodeIndex); static sqInt compileBlockDispatch(void); static void compileGetErrorCode(void); static sqInt compileInterpreterPrimitive(void); static sqInt NoDbgRegParms compileInterpreterPrimitiveflags(void (*primitiveRoutine)(void), sqInt flags); static sqInt NoDbgRegParms compileMachineCodeInterpreterPrimitive(void (*primitiveRoutine)(void)); static AbstractInstruction * NoDbgRegParms compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selector, sqInt shift, sqInt baseRegOrNone); static void NoDbgRegParms compileOpenPICnumArgs(sqInt selector, sqInt numArgs); static AbstractInstruction * NoDbgRegParms compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selectorReg, sqInt shift, sqInt baseRegOrNone); static sqInt compilePrimitive(void); static sqInt extendedPushBytecode(void); static sqInt extendedStoreAndPopBytecode(void); static sqInt extendedStoreBytecode(void); static sqInt NoDbgRegParms frameOffsetOfTemporary(sqInt index); static sqInt genCallMappedInlinedPrimitive(void); static AbstractInstruction * NoDbgRegParms genDoubleFailIfZeroArgRcvrarg(int rcvrReg, int argReg); static sqInt genExtendedSendBytecode(void); static sqInt genExtendedSuperBytecode(void); static sqInt genExtJumpIfFalse(void); static sqInt genExtJumpIfTrue(void); static sqInt genExtNopBytecode(void); static sqInt genExtPushCharacterBytecode(void); static sqInt genExtPushIntegerBytecode(void); static sqInt genExtPushLiteralBytecode(void); static sqInt genExtPushLiteralVariableBytecode(void); static sqInt genExtPushPseudoVariable(void); static sqInt genExtPushReceiverVariableBytecode(void); static sqInt genExtSendBytecode(void); static sqInt genExtSendSuperBytecode(void); static sqInt genExtStoreAndPopLiteralVariableBytecode(void); static sqInt genExtStoreAndPopReceiverVariableBytecode(void); static sqInt genExtStoreLiteralVariableBytecode(void); static sqInt genExtStoreReceiverVariableBytecode(void); static sqInt genExtUnconditionalJump(void); static sqInt genFastPrimFail(void); static void NoDbgRegParms genFastPrimTraceUsingand(sqInt r1, sqInt r2); static sqInt genLongJumpIfFalse(void); static sqInt genLongJumpIfTrue(void); static sqInt genLongPushTemporaryVariableBytecode(void); static sqInt genLongStoreAndPopTemporaryVariableBytecode(void); static sqInt genLongStoreTemporaryVariableBytecode(void); static sqInt genLongUnconditionalBackwardJump(void); static sqInt genLongUnconditionalForwardJump(void); static sqInt NoDbgRegParms genLookupForPerformNumArgs(sqInt numArgs); static AbstractInstruction * NoDbgRegParms genMoveConstantR(sqInt constant, sqInt reg); static sqInt NoDbgRegParms genMustBeBooleanTrampolineForcalled(sqInt boolean, char *trampolineName); static sqInt genPrimitiveHashMultiply(void); static void NoDbgRegParms genPrimReturnEnterCogCodeEnilopmart(sqInt profiling); static sqInt genPushClosureTempsBytecode(void); static sqInt genPushConstantFalseBytecode(void); static sqInt genPushConstantNilBytecode(void); static sqInt genPushConstantOneBytecode(void); static sqInt genPushConstantTrueBytecode(void); static sqInt genPushConstantZeroBytecode(void); static sqInt genPushLiteralConstantBytecode(void); static sqInt genPushLiteralVariable16CasesBytecode(void); static sqInt genPushLiteralVariableBytecode(void); static sqInt genPushQuickIntegerConstantBytecode(void); static sqInt genPushReceiverVariableBytecode(void); static sqInt genPushTemporaryVariableBytecode(void); extern sqInt genQuickReturnConst(void); extern sqInt genQuickReturnInstVar(void); extern sqInt genQuickReturnSelf(void); static sqInt genReturnFalse(void); static sqInt genReturnNil(void); static sqInt genReturnNilFromBlock(void); static sqInt genReturnTrue(void); static sqInt genSecondExtendedSendBytecode(void); static sqInt genSendLiteralSelector0ArgsBytecode(void); static sqInt genSendLiteralSelector1ArgBytecode(void); static sqInt genSendLiteralSelector2ArgsBytecode(void); static sqInt genShortJumpIfFalse(void); static sqInt genShortJumpIfTrue(void); static sqInt genShortUnconditionalJump(void); static sqInt genSpecialSelectorEqualsEquals(void); static sqInt genSpecialSelectorNotEqualsEquals(void); static sqInt genSpecialSelectorSend(void); static sqInt genStoreAndPopReceiverVariableBytecode(void); static sqInt genStoreAndPopRemoteTempLongBytecode(void); static sqInt genStoreAndPopTemporaryVariableBytecode(void); static sqInt genStoreRemoteTempLongBytecode(void); static sqInt genUnconditionalTrapBytecode(void); extern sqInt mapPCDataForinto(CogMethod *cogMethod, sqInt arrayObj); static void maybeCompileAllocFillerCheck(void); static sqInt numSpecialSelectors(void); static usqInt NoDbgRegParms pcDataForBlockEntryMethod(sqInt blockEntryMcpc, sqInt cogMethod); static sqInt NoDbgRegParms pcDataForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg); static PrimitiveDescriptor * primitiveGeneratorOrNil(void); extern void recordCallOffsetIn(CogMethod *cogMethod); extern void rewritePrimInvocationInto(CogMethod *cogMethod, void (*primFunctionPointer)(void)); static sqInt NoDbgRegParms seemsToBeInstantiating(sqInt format); static sqInt NoDbgRegParms v3BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3ShortForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); extern void voidCogCompiledCode(void); static BlockStart * NoDbgRegParms addBlockStartAtnumArgsnumCopiedspan(sqInt bytecodepc, sqInt numArgs, sqInt numCopied, sqInt span); static void NoDbgRegParms adjustArgumentsForPerform(sqInt numArgs); static sqInt NoDbgRegParms allocateRegForStackEntryAtnotConflictingWith(sqInt index, sqInt regMask); static sqInt NoDbgRegParms allocateRegNotConflictingWith(sqInt regMask); static sqInt NoDbgRegParms anyReferencesToRegisterinTopNItems(sqInt reg, sqInt n); extern void callCogCodePopReceiverArg0Regs(void); extern void callCogCodePopReceiverArg1Arg0Regs(void); static sqInt NoDbgRegParms compileAbstractInstructionsFromthrough(sqInt start, sqInt end); static sqInt compileBlockBodies(void); static void NoDbgRegParms compileBlockFrameBuild(BlockStart *blockStart); static void NoDbgRegParms compileBlockFramelessEntry(BlockStart *blockStart); static CogMethod * NoDbgRegParms compileCogFullBlockMethod(sqInt numCopied); static CogMethod * NoDbgRegParms compileCogMethod(sqInt selector); static sqInt compileEntireMethod(void); static void compileFrameBuild(void); static void NoDbgRegParms compileFullBlockFramelessEntry(sqInt numCopied); static void NoDbgRegParms compileFullBlockMethodFrameBuild(sqInt numCopied); #if IMMUTABILITY static void compileTwoPathFrameBuild(void); #endif /* IMMUTABILITY */ static void compileTwoPathFramelessInit(void); static sqInt NoDbgRegParms cPICMissTrampolineFor(sqInt numArgs); static sqInt doubleExtendedDoAnythingBytecode(void); static sqInt duplicateTopBytecode(void); static BytecodeFixup * NoDbgRegParms ensureFixupAt(sqInt targetPC); static BytecodeFixup * NoDbgRegParms ensureNonMergeFixupAt(sqInt targetPC); static void ensureReceiverResultRegContainsSelf(void); static void NoDbgRegParms evaluateat(BytecodeDescriptor *descriptor, sqInt pc); static sqInt NoDbgRegParms eventualTargetOf(sqInt targetBytecodePC); static sqInt NoDbgRegParms freeAnyRegNotConflictingWith(sqInt regMask); static sqInt genBlockReturn(void); static void (*genCallPICEnilopmartNumArgs(sqInt numArgs))(void) ; static sqInt genCallPrimitiveBytecode(void); static sqInt genExternalizePointersForPrimitiveCall(void); static sqInt genExtPushClosureBytecode(void); static sqInt genExtPushFullClosureBytecode(void); static void generateEnilopmarts(void); static sqInt NoDbgRegParms generateInstructionsAt(sqInt eventualAbsoluteAddress); static void generateMissAbortTrampolines(void); static void generateSendTrampolines(void); static void generateTracingTrampolines(void); static sqInt NoDbgRegParms genForwardersInlinedIdenticalOrNotIf(sqInt orNot); static sqInt NoDbgRegParms genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(sqInt argIsConstant, sqInt rcvrIsConstant, sqInt argReg, sqInt rcvrRegOrNone, sqInt orNot); static sqInt NoDbgRegParms genInlinedIdenticalOrNotIf(sqInt orNot); static sqInt NoDbgRegParms genJumpBackTo(sqInt targetBytecodePC); static sqInt NoDbgRegParms genJumpIfto(sqInt boolean, sqInt targetBytecodePC); static sqInt NoDbgRegParms genJumpTo(sqInt targetBytecodePC); static sqInt NoDbgRegParms genMarshalledSendnumArgssendTable(sqInt selectorIndex, sqInt numArgs, sqInt *sendTable); static sqInt NoDbgRegParms genMethodAbortTrampolineFor(sqInt numArgs); static sqInt NoDbgRegParms genPICAbortTrampolineFor(sqInt numArgs); static sqInt NoDbgRegParms genPICMissTrampolineFor(sqInt numArgs); static sqInt genPopStackBytecode(void); static sqInt genPrimitiveClosureValue(void); static sqInt genPrimitiveFullClosureValue(void); static sqInt genPrimitivePerform(void); static sqInt genPushActiveContextBytecode(void); static sqInt genPushClosureCopyCopiedValuesBytecode(void); static sqInt NoDbgRegParms genPushLiteralIndex(sqInt literalIndex); static sqInt NoDbgRegParms genPushLiteralVariable(sqInt literalIndex); static sqInt NoDbgRegParms genPushLiteral(sqInt literal); static sqInt NoDbgRegParms genPushMaybeContextReceiverVariable(sqInt slotIndex); static sqInt genPushNewArrayBytecode(void); static sqInt genPushReceiverBytecode(void); static sqInt NoDbgRegParms genPushReceiverVariable(sqInt index); static void genPushRegisterArgs(void); static sqInt genPushRemoteTempLongBytecode(void); static sqInt NoDbgRegParms genPushTemporaryVariable(sqInt index); static sqInt genReturnReceiver(void); static sqInt genReturnTopFromBlock(void); static sqInt genReturnTopFromMethod(void); static sqInt NoDbgRegParms genSendDirectedSupernumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt NoDbgRegParms genSendSupernumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt NoDbgRegParms genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3); static sqInt NoDbgRegParms genSendnumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt genSpecialSelectorArithmetic(void); static sqInt genSpecialSelectorClass(void); static sqInt genSpecialSelectorComparison(void); static sqInt genStaticallyResolvedSpecialSelectorComparison(void); static sqInt NoDbgRegParms genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt litVarIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopRemoteTempAtneedsStoreCheck(sqInt popBoolean, sqInt slotIndex, sqInt remoteTempIndex, sqInt needsStoreCheck); static sqInt NoDbgRegParms genStorePopTemporaryVariable(sqInt popBoolean, sqInt tempIndex); static sqInt genUpArrowReturn(void); static void NoDbgRegParms initSimStackForFramefulMethod(sqInt startpc); static void NoDbgRegParms initSimStackForFramelessBlock(sqInt startpc); static void NoDbgRegParms initSimStackForFramelessMethod(sqInt startpc); static sqInt liveRegisters(void); static sqInt NoDbgRegParms mapDeadDescriptorIfNeeded(BytecodeDescriptor *descriptor); static void NoDbgRegParms marshallSendArguments(sqInt numArgs); static sqInt maybeCompilingFirstPassOfBlockWithInitialPushNil(void); static sqInt NoDbgRegParms mergeWithFixupIfRequired(BytecodeFixup *fixup); static sqInt NoDbgRegParms methodAbortTrampolineFor(sqInt numArgs); static sqInt methodFoundInvalidPostScan(void); static sqInt NoDbgRegParms needsFrameIfMod16GENumArgs(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameIfStackGreaterThanOne(sqInt stackDelta); static sqInt NoDbgRegParms numberOfSpillsInTopNItems(sqInt n); static sqInt NoDbgRegParms picAbortTrampolineFor(sqInt numArgs); static sqInt prevInstIsPCAnnotated(void); static sqInt receiverIsInReceiverResultReg(void); static void NoDbgRegParms reinitializeFixupsFromthrough(sqInt start, sqInt end); static sqInt NoDbgRegParms scanBlock(BlockStart *blockStart); static sqInt scanMethod(void); static sqInt NoDbgRegParms squeakV3orSistaV1PushNilSizenumInitialNils(sqInt aMethodObj, sqInt numInitialNils); static sqInt NoDbgRegParms squeakV3orSistaV1NumPushNils(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static void NoDbgRegParms ssAllocateRequiredRegMaskupThroughupThroughNative(sqInt requiredRegsMask, sqInt stackPtr, sqInt nativeStackPtr); static void NoDbgRegParms ssFlushUpThroughReceiverVariable(sqInt slotIndex); static void NoDbgRegParms ssFlushUpThroughTemporaryVariable(sqInt tempIndex); static void NoDbgRegParms ssPop(sqInt n); static sqInt NoDbgRegParms ssPushAnnotatedConstant(sqInt literal); static sqInt NoDbgRegParms ssPushBaseoffset(sqInt reg, sqInt offset); static sqInt NoDbgRegParms ssPushConstant(sqInt literal); static sqInt NoDbgRegParms ssPushDesc(SimStackEntry simStackEntry); static sqInt NoDbgRegParms ssPushRegister(sqInt reg); static void NoDbgRegParms ssPush(sqInt n); static SimStackEntry ssSelfDescriptor(void); static void NoDbgRegParms ssStoreAndReplacePoptoReg(sqInt popBoolean, sqInt reg); static sqInt NoDbgRegParms ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg); static void NoDbgRegParms ssStorePoptoReg(sqInt popBoolean, sqInt reg); static CogSimStackEntry * ssTop(void); static CogSimStackEntry * NoDbgRegParms ssValue(sqInt n); static sqInt NoDbgRegParms stackEntryIsBoolean(CogSimStackEntry *simStackEntry); static sqInt tempsValidAndVolatileEntriesSpilled(void); static sqInt NoDbgRegParms tryCollapseTempVectorInitializationOfSize(sqInt slots); static sqInt violatesEnsureSpilledSpillAssert(void); static void voidReceiverResultRegContainsSelf(void); /*** Variables ***/ static AbstractInstruction * abstractOpcodes; static AbstractInstruction aMethodLabel; static AbstractInstruction * const backEnd = &aMethodLabel; static usqInt baseAddress; static sqInt blockCount; static AbstractInstruction * blockEntryLabel; static AbstractInstruction * blockEntryNoContextSwitch; sqInt blockNoContextSwitchOffset; static BlockStart * blockStarts; static sqInt breakBlock; static sqInt breakMethod; sqInt breakPC; static sqInt byte0; static sqInt byte1; static sqInt byte2; static sqInt byte3; static sqInt bytecodePC; static sqInt bytecodeSetOffset; void * CFramePointer; void * CStackPointer; sqInt cbEntryOffset; sqInt cbNoSwitchEntryOffset; sqInt ceBaseFrameReturnTrampoline; static sqInt ceByteSizeOfTrampoline; void (*ceCall0ArgsPIC)(void); void (*ceCall1ArgsPIC)(void); void (*ceCall2ArgsPIC)(void); void (*ceCallCogCodePopReceiverAndClassRegs)(void); void (*ceCallCogCodePopReceiverArg0Regs)(void); void (*ceCallCogCodePopReceiverArg1Arg0Regs)(void); void (*ceCallCogCodePopReceiverReg)(void); sqInt ceCannotResumeTrampoline; void (*ceCaptureCStackPointers)(void); static usqIntptr_t (*ceCheckFeaturesFunction)(void); sqInt ceCheckForInterruptTrampoline; static sqInt ceCPICMissTrampoline; void (*ceEnterCogCodePopReceiverReg)(void); static sqInt ceFetchContextInstVarTrampoline; static sqInt ceFFICalloutTrampoline; static sqInt ceFloatObjectOfTrampoline; static sqInt ceFloatValueOfTrampoline; static void (*ceFlushICache)(usqIntptr_t from, usqIntptr_t to); static sqInt ceFreeTrampoline; usqIntptr_t (*ceGetFP)(void); usqIntptr_t (*ceGetSP)(void); static sqInt ceInlineNewHashTrampoline; static sqInt ceInstantiateClassIndexableSizeTrampoline; static sqInt ceInstantiateClassTrampoline; static sqInt ceLargeActiveContextInBlockTrampoline; static sqInt ceLargeActiveContextInFullBlockTrampoline; static sqInt ceLargeActiveContextInMethodTrampoline; static sqInt ceMallocTrampoline; static sqInt ceMethodAbortTrampoline; static sqInt ceNewHashTrampoline; static sqInt ceNonLocalReturnTrampoline; static sqInt cePICAbortTrampoline; static sqInt cePositive32BitIntegerTrampoline; static sqInt cePositive32BitValueOfTrampoline; static sqInt cePositive64BitIntegerTrampoline; static sqInt cePositive64BitValueOfTrampoline; static sqInt cePrimReturnEnterCogCode; static sqInt cePrimReturnEnterCogCodeProfiling; static sqInt ceReapAndResetErrorCodeTrampoline; sqInt ceReturnToInterpreterTrampoline; static sqInt ceScheduleScavengeTrampoline; static sqInt ceSendMustBeBooleanAddFalseTrampoline; static sqInt ceSendMustBeBooleanAddTrueTrampoline; static sqInt ceSigned32BitIntegerTrampoline; static sqInt ceSigned32BitValueOfTrampoline; static sqInt ceSigned64BitIntegerTrampoline; static sqInt ceSigned64BitValueOfTrampoline; static sqInt ceSmallActiveContextInBlockTrampoline; static sqInt ceSmallActiveContextInFullBlockTrampoline; static sqInt ceSmallActiveContextInMethodTrampoline; static sqInt ceStoreCheckContextReceiverTrampoline; static sqInt ceStoreCheckTrampoline; static sqInt ceStoreContextInstVarTrampoline; #if IMMUTABILITY sqInt ceStoreTrampolines[5]; #endif static sqInt ceTraceBlockActivationTrampoline; static sqInt ceTraceLinkedSendTrampoline; static sqInt ceTraceStoreTrampoline; usqIntptr_t (*ceTryLockVMOwner)(void); void (*ceUnlockVMOwner)(void); sqInt cFramePointerInUse; static sqInt checkedEntryAlignment; static sqInt closedPICSize; sqInt cmEntryOffset; sqInt cmNoCheckEntryOffset; static sqInt codeBase; static sqInt codeModified; static sqInt cogConstituentIndex; static sqInt compactionInProgress; static sqInt compilationPass; static sqInt compilationTrace; static sqInt cPICCaseSize; static sqInt cPICEndOfCodeOffset; static sqInt cPICEndSize; static sqInt cPICPrototype; static sqInt currentCallCleanUpSize; static sqInt deadCode; static sqInt debugBytecodePointers; static sqInt debugFixupBreaks; static sqInt debugOpcodeIndices; usqIntptr_t debugPrimCallStackOffset; static sqInt debugStackPointers; static sqInt directedSendUsesBinding; static sqInt directedSuperBindingSendTrampolines[NumSendTrampolines]; static sqInt directedSuperSendTrampolines[NumSendTrampolines]; static sqInt disassemblingMethod; static AbstractInstruction * endCPICCase0; static sqInt endPC; static AbstractInstruction * entry; static sqInt entryPointMask; static CogMethod * enumeratingCogMethod; static sqInt expectedFPAlignment; static sqInt expectedSPAlignment; static sqInt extA; static sqInt extB; static sqInt externalPrimCallOffsets[MaxNumArgs + 1]; static sqInt externalPrimJumpOffsets[MaxNumArgs + 1]; static sqInt externalSetPrimOffsets[MaxNumArgs + 1]; static sqInt firstCPICCaseOffset; static sqInt firstOpcodeIndex; static sqInt firstSend; static BytecodeFixup * fixups; static AbstractInstruction * fullBlockEntry; static AbstractInstruction * fullBlockNoContextSwitchEntry; static BytecodeDescriptor generatorTable[512] = { { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushReceiverBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantTrueBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantFalseBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantNilBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genReturnReceiver, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTrue, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnFalse, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNil, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromMethod, 0, needsFrameIfInBlock, -1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extendedPushBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { extendedStoreBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { extendedStoreAndPopBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtendedSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { doubleExtendedDoAnythingBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtendedSuperBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, { genSecondExtendedSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genPopStackBytecode, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { duplicateTopBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushActiveContextBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushNewArrayBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genCallPrimitiveBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushClosureCopyCopiedValuesBytecode, v3BlockCodeSize, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AddRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, SubRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLess, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreater, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLessOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreaterOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpNonZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AndRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, OrRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorClass, 0, needsFrameIfStackGreaterThanOne, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorNotEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushReceiverBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantTrueBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantFalseBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantNilBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantZeroBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantOneBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushPseudoVariable, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { duplicateTopBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genReturnReceiver, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTrue, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnFalse, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNil, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromMethod, 0, needsFrameIfInBlock, -1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNilFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { genReturnTopFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { genExtNopBytecode, 0, needsFrameNever, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AddRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, SubRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLess, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreater, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLessOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreaterOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpNonZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AndRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, OrRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorClass, 0, needsFrameIfStackGreaterThanOne, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorNotEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPopStackBytecode, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genUnconditionalTrapBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extABytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extBBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genExtPushReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genExtPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushLiteralBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongPushTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genPushNewArrayBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushIntegerBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushCharacterBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtSendSuperBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genCallMappedInlinedPrimitive, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }, { genExtUnconditionalJump, v4LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtJumpIfTrue, v4LongBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtJumpIfFalse, v4LongBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtStoreAndPopReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtStoreAndPopLiteralVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 0, 0, 0 }, { genLongStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtStoreReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtStoreLiteralVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 0, 0, 0 }, { genLongStoreTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genCallPrimitiveBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, { genExtPushFullClosureBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushClosureBytecode, v4BlockCodeSize, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { genPushRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 } }; static sqInt guardPageSize; static sqInt hasNativeFrame; static sqInt hasYoungReferent; static sqInt inBlock; static sqInt initialPC; static sqInt introspectionData; static sqInt introspectionDataIndex; static int labelCounter; static sqInt lastDumpedLiteralIndex; static sqInt lastSend; static usqInt limitAddress; static AbstractInstruction * literals; static sqInt literalsSize; static sqInt maxLitIndex; static sqInt methodAbortTrampolines[4]; static sqInt methodBytesFreedSinceLastCompaction; static sqInt methodCount; static sqInt methodHeader; static AbstractInstruction * const methodLabel = &aMethodLabel; static sqInt methodObj; static sqInt methodOrBlockNumArgs; static sqInt methodOrBlockNumTemps; static sqInt methodZoneBase; static usqIntptr_t minValidCallAddress; sqInt missOffset; static usqInt mzFreeStart; static sqInt needsFrame; static sqInt nextLiteralIndex; static AbstractInstruction * noCheckEntry; static sqInt numAbstractOpcodes; static sqInt numExtB; static usqInt objectReferencesInRuntime[NumObjRefsInRuntime+1]; static sqInt opcodeIndex; static CogMethod *openPICList = 0; static sqInt openPICSize; static sqInt ordinarySendTrampolines[NumSendTrampolines]; static sqInt picAbortTrampolines[4]; static AbstractInstruction * picInterpretAbort; static sqInt picMissTrampolines[4]; static AbstractInstruction * picMNUAbort; static void (*postCompileHook)(CogMethod *); static BytecodeDescriptor * prevBCDescriptor; static AbstractInstruction * primInvokeInstruction; static sqInt primitiveIndex; static AbstractInstruction * primSetFunctionLabel; void (*realCECallCogCodePopReceiverAndClassRegs)(void); void (*realCECallCogCodePopReceiverArg0Regs)(void); void (*realCECallCogCodePopReceiverArg1Arg0Regs)(void); void (*realCECallCogCodePopReceiverReg)(void); void (*realCEEnterCogCodePopReceiverReg)(void); static sqInt receiverTags; static sqInt regArgsHaveBeenPushed; static sqInt runtimeObjectRefIndex; static AbstractInstruction * sendMiss; static sqInt simNativeSpillBase; static sqInt simNativeStack; static sqInt simNativeStackPtr; static sqInt simNativeStackSize; static sqInt simSpillBase; static SimStackEntry simStack[70]; static sqInt simStackPtr; static AbstractInstruction * stackCheckLabel; static AbstractInstruction * stackOverflowCall; static sqInt superSendTrampolines[NumSendTrampolines]; static sqInt tempOop; int traceFlags = 8 /* prim trace log on by default */; sqInt traceStores; static char *trampolineAddresses[NumTrampolines*2]; static sqInt trampolineTableIndex; static sqInt uncheckedEntryAlignment; static usqInt unpairedMethodList; static sqInt useTwoPaths; static usqInt youngReferrers; /*** Macros ***/ #define flushICacheFromto(me,startAddress,endAddress) __clear_cache((char*) startAddress, (char*) (endAddress )) #define cPICNumCases stackCheckOffset #define cPICNumCasesHack hack hack hack i.e. the getter macro does all the work #define abstractInstructionAt(index) (&abstractOpcodes[index]) #define allocateBlockStarts(numBlocks) do { \ blockStarts = (numBlocks) ? alloca(sizeof(BlockStart) * (numBlocks)) : 0; \ } while (0) #define backEnd() backEnd #define blockAlignment(self) 8 #define blockStartAt(index) (&blockStarts[index]) #define breakOnImplicitReceiver() (traceFlags & 64) #define ceBaseFrameReturnPC() ceBaseFrameReturnTrampoline #define ceCannotResumePC() ((usqInt)ceCannotResumeTrampoline) #define ceCheckFeatures() ceCheckFeaturesFunction() #define ceReturnToInterpreterPC() ((usqInt)ceReturnToInterpreterTrampoline) #define cFramePointerAddress() ((usqIntptr_t)&CFramePointer) #define compileSendTrace() ((traceFlags & 258) == 258) #define cr() putchar('\n') #define cStackPointerAddress() ((usqIntptr_t)&CStackPointer) #define entryOffset() cmEntryOffset #define generatorAt(index) (&generatorTable[index]) #define getCFramePointer() CFramePointer #define getCStackPointer() CStackPointer #define getIsObjectReference() 2 #define halt() warning("halt") #define haltmsg(msg) warning("halt: " msg) #define interpretOffset() missOffset #define maxCogCodeSize() (16*1024*1024) #define maybeBreakGeneratingAt(address) 0 #define maybeHaltIfDebugPC() 0 #define methodLabel() methodLabel #define methodZoneBase() methodZoneBase #define minCallAddress() minValidCallAddress #define noCheckEntryOffset() cmNoCheckEntryOffset #define noContextSwitchBlockEntryOffset() blockNoContextSwitchOffset #define notYetImplemented() warning("not yet implemented") #define printNum(n) printf("%ld", (long) n) #define printOnTrace() (traceFlags & 1) #define print(aString) printf("%s", aString) #define recordBlockTrace() (traceFlags & 4) #define recordEventTrace() (traceFlags & 16) #define recordOverflowTrace() (traceFlags & 32) #define recordPrimTrace() (traceFlags & 8) #define recordSendTrace() (traceFlags & 2) #define reportError(n) warning("compilation error") #define setCFramePointer(theFP) (CFramePointer = (void *)(theFP)) #define setCStackPointer(theSP) (CStackPointer = (void *)(theSP)) #define tryLockVMOwner() (ceTryLockVMOwner() != 0) #define unlockVMOwner() ceUnlockVMOwner() #define nextOpenPIC methodObject #define nextOpenPICHack hack hack hack i.e. the getter macro does all the work #define freeStart() mzFreeStart #define limitZony() ((CogMethod *)mzFreeStart) #define methodBytesFreedSinceLastCompaction() methodBytesFreedSinceLastCompaction #define roundUpLength(numBytes) ((numBytes) + 7 & -8) #define youngReferrers() youngReferrers #define maybeConstant(sse) ((sse)->constant) #define literalInstructionAt(index) (&literals[index]) #define fullBlockEntryOffset() cbEntryOffset #define fullBlockNoContextSwitchEntryOffset() cbNoSwitchEntryOffset #define fixupAtIndex(index) (&fixups[index]) #define simNativeStackAt(index) (simNativeStack + (index)) #define simSelf() simStack #define simStackAt(index) (simStack + (index)) #define traceDescriptor(ign) 0 #define traceFixupmerge(igu,ana) 0 #define traceMerge(ign) 0 #define traceSimStack() 0 #define traceSpill(ign) 0 #define allocatype(numElements, elementType) alloca((numElements)*sizeof(elementType)) #define numElementsIn(anArray) (sizeof(anArray)/sizeof(anArray[0])) #define oopisGreaterThanOrEqualTo(anOop,otherOop) ((usqInt)(anOop) >= (usqInt)(otherOop)) #define oopisGreaterThanOrEqualToandLessThanOrEqualTo(anOop,baseOop,limitOop) ((usqInt)(anOop) >= (usqInt)(baseOop) && (usqInt)(anOop) <= (usqInt)(limitOop)) #define oopisGreaterThanOrEqualToandLessThan(anOop,baseOop,limitOop) ((usqInt)(anOop) >= (usqInt)(baseOop) && (usqInt)(anOop) < (usqInt)(limitOop)) #define oopisGreaterThan(anOop,otherOop) ((usqInt)(anOop) > (usqInt)(otherOop)) #define oopisGreaterThanandLessThan(anOop,baseOop,limitOop) ((usqInt)(anOop) > (usqInt)(baseOop) && (usqInt)(anOop) < (usqInt)(limitOop)) #define oopisLessThanOrEqualTo(anOop,otherOop) ((usqInt)(anOop) <= (usqInt)(otherOop)) #define oopisLessThan(anOop,otherOop) ((usqInt)(anOop) < (usqInt)(otherOop)) /* CogAbstractInstruction>>#addDependent: */ static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction) { if (!(((self_in_addDependent->dependent)) == null)) { (anInstruction->dependent = (self_in_addDependent->dependent)); } return ((self_in_addDependent->dependent) = anInstruction); } /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. */ /* CogAbstractInstruction>>#availableFloatRegisterOrNoneFor: */ static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask) { if (!(liveRegsMask & (1U << DPFPReg0))) { return DPFPReg0; } if (!(liveRegsMask & (1U << DPFPReg1))) { return DPFPReg1; } if (!(liveRegsMask & (1U << DPFPReg2))) { return DPFPReg2; } if (!(liveRegsMask & (1U << DPFPReg3))) { return DPFPReg3; } if (!(liveRegsMask & (1U << DPFPReg4))) { return DPFPReg4; } if (!(liveRegsMask & (1U << DPFPReg5))) { return DPFPReg5; } if (!(liveRegsMask & (1U << DPFPReg6))) { return DPFPReg6; } if (!(liveRegsMask & (1U << DPFPReg7))) { return DPFPReg7; } return NoReg; } /* For out-of-line literal support, clone a literal from a literal. */ /* CogAbstractInstruction>>#cloneLiteralFrom: */ static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral) { assert((((existingLiteral->opcode)) == Literal) && ((((self_in_cloneLiteralFrom->dependent)) == null) && (((self_in_cloneLiteralFrom->address)) == null))); (self_in_cloneLiteralFrom->opcode) = Literal; (self_in_cloneLiteralFrom->annotation) = (existingLiteral->annotation); ((self_in_cloneLiteralFrom->operands))[0] = (((existingLiteral->operands))[0]); ((self_in_cloneLiteralFrom->operands))[1] = (((existingLiteral->operands))[1]); ((self_in_cloneLiteralFrom->operands))[2] = (((existingLiteral->operands))[2]); return self_in_cloneLiteralFrom; } /* Generic register swap code. Subclasses for processors that have a true exchange operation will override to use it. */ /* CogAbstractInstruction>>#genSwapR:R:Scratch: */ static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp) { AbstractInstruction *first; first = genoperandoperand(MoveRR, regA, regTmp); genoperandoperand(MoveRR, regB, regA); genoperandoperand(MoveRR, TempReg, regB); return first; } /* CogAbstractInstruction>>#genWriteCResultIntoReg: */ static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister) { sqInt cResultReg; cResultReg = R0; if (abstractRegister != cResultReg) { genoperandoperand(MoveRR, cResultReg, abstractRegister); } return self_in_genWriteCResultIntoReg; } /* For out-of-line literal support, initialize a sharable literal. */ /* CogAbstractInstruction>>#initializeSharableLiteral: */ static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal) { (self_in_initializeSharableLiteral->opcode) = Literal; /* separate := nil for Slang */ (self_in_initializeSharableLiteral->annotation) = null; (self_in_initializeSharableLiteral->address) = null; (self_in_initializeSharableLiteral->dependent) = null; ((self_in_initializeSharableLiteral->operands))[0] = literal; ((self_in_initializeSharableLiteral->operands))[1] = 1; ((self_in_initializeSharableLiteral->operands))[2] = -1; return self_in_initializeSharableLiteral; } /* For out-of-line literal support, initialize an unsharable literal. */ /* CogAbstractInstruction>>#initializeUniqueLiteral: */ static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal) { (self_in_initializeUniqueLiteral->opcode) = Literal; /* separate := nil for Slang */ (self_in_initializeUniqueLiteral->annotation) = null; (self_in_initializeUniqueLiteral->address) = null; (self_in_initializeUniqueLiteral->dependent) = null; ((self_in_initializeUniqueLiteral->operands))[0] = literal; ((self_in_initializeUniqueLiteral->operands))[1] = 0; ((self_in_initializeUniqueLiteral->operands))[2] = -1; return self_in_initializeUniqueLiteral; } /* CogAbstractInstruction>>#isAnInstruction: */ static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction) { return (addressIsInInstructions(addressOrInstruction)) || (addressOrInstruction == (methodLabel())); } /* CogAbstractInstruction>>#isJump */ static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump) { return ((((self_in_isJump->opcode)) >= FirstJump) && (((self_in_isJump->opcode)) <= LastJump)); } /* Answer if an address can be accessed using the offset in a MoveMw:r:R: or similar instruction. We assume this is true for 32-bit processors and expect 64-bit processors to answer false for values in the interpreter or the object memory. */ /* CogAbstractInstruction>>#isWithinMwOffsetRange: */ static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress) { return 1; } /* Set the target of a jump instruction. These all have the target in the first operand. */ /* CogAbstractInstruction>>#jmpTarget: */ static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction) { ((self_in_jmpTarget->operands))[0] = (((usqInt)anAbstractInstruction)); return anAbstractInstruction; } /* Answer the constant loaded by the instruction sequence just before this address: */ /* CogAbstractInstruction>>#literal32BeforeFollowingAddress: */ static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress) { return literalBeforeFollowingAddress(self_in_literal32BeforeFollowingAddress, followingAddress); } /* We assume here that calls and jumps look the same as regards their displacement. This works on at least x86, ARM and x86_64. Processors on which that isn't the case can override as necessary. */ /* CogAbstractInstruction>>#relocateJumpLongBeforeFollowingAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta) { relocateCallBeforeReturnPCby(self_in_relocateJumpLongBeforeFollowingAddressby, pc, delta); return self_in_relocateJumpLongBeforeFollowingAddressby; } /* Relocate a long conditional jump before pc. Default to relocating a non-conditional jump. Processors that have different formats for conditional and unconditional jumps override. */ /* CogAbstractInstruction>>#relocateJumpLongConditionalBeforeFollowingAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta) { relocateJumpLongBeforeFollowingAddressby(self_in_relocateJumpLongConditionalBeforeFollowingAddressby, pc, delta); return self_in_relocateJumpLongConditionalBeforeFollowingAddressby; } /* CogAbstractInstruction>>#resolveJumpTarget */ static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget) { BytecodeFixup *fixup; assert(isJump(self_in_resolveJumpTarget)); fixup = ((BytecodeFixup *) (((self_in_resolveJumpTarget->operands))[0])); if (addressIsInFixups(fixup)) { assert(addressIsInInstructions((fixup->targetInstruction))); jmpTarget(self_in_resolveJumpTarget, (fixup->targetInstruction)); } return self_in_resolveJumpTarget; } /* Rewrite a conditional jump long to jump to target. This version defaults to using rewriteJumpLongAt:, which works for many ISAs. Subclasses override if necessary. */ /* CogAbstractInstruction>>#rewriteConditionalJumpLongAt:target: */ static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteJumpLongAttarget(self_in_rewriteConditionalJumpLongAttarget, callSiteReturnAddress, callTargetAddress); } /* A hack hook to allow ARM to override the simulated address for the short-cut trampolines, and to allow x64 to address CStackPointer and CFramePointer relative to VarBaseReg. */ /* CogAbstractInstruction>>#wantsNearAddressFor: */ static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject) { return 0; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc ADDS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-23 */ /* CogARMCompiler>>#adds:rn:imm:ror: */ static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. ADD destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-23 */ /* CogARMCompiler>>#add:rn:imm:ror: */ static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* return an ADD destReg, srcReg, addReg instruction ADD destReg, srcReg, addReg - ARM_ARM v7 DDI10406 p. A8-24 */ /* CogARMCompiler>>#add:rn:rm: */ static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (addReg & 0xFFF); } /* Answer the address of the __aeabi_idivmod() call provided by the ARM low level libs to do an integer divide that returns the quo in R0 and rem in R1. A word on the somewhat strange usage of idivmod herein; we need a declaration for the _aeabi_idivmod helper function, despite the fact that in a simple C program test, you don't. To get that declaration we need a variable to hang it off; thus the non-existent var idivmod, and in simulation we need to simulate it, which is what aeabiDiv:Mod: does. */ /* CogARMCompiler>>#aeabiDivModFunctionAddr */ static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr) { extern void __aeabi_idivmod(int dividend, int divisor); return (usqInt)__aeabi_idivmod; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc ANDS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-34 */ /* CogARMCompiler>>#ands:rn:imm:ror: */ static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc AND destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-34 */ /* CogARMCompiler>>#and:rn:imm:ror: */ static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. N.B. Do /not/ allocate TempReg. */ /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. N.B. Do /not/ allocate TempReg. */ /* CogARMCompiler>>#availableRegisterOrNoneFor: */ static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask) { if (!(liveRegsMask & (1U << Extra0Reg))) { return Extra0Reg; } if (!(liveRegsMask & (1U << Extra1Reg))) { return Extra1Reg; } if (!(liveRegsMask & (1U << Extra2Reg))) { return Extra2Reg; } if (!(liveRegsMask & (1U << Arg1Reg))) { return Arg1Reg; } if (!(liveRegsMask & (1U << Arg0Reg))) { return Arg0Reg; } if (!(liveRegsMask & (1U << SendNumArgsReg))) { return SendNumArgsReg; } if (!(liveRegsMask & (1U << ClassReg))) { return ClassReg; } if (!(liveRegsMask & (1U << ReceiverResultReg))) { return ReceiverResultReg; } return NoReg; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc BICS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 pp. A8-50-1 */ /* CogARMCompiler>>#bics:rn:imm:ror: */ static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(BicOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* return a BL offset instruction; offset is signed 24bits of WORD offset, so +_32Mbyte range. Return address is in LR BL offset - ARM_ARM v7 DDI10406 pp. A8-58-9 */ /* CogARMCompiler>>#bl: */ static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset) { return (((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (1 & 1))) << 24))) | ((((usqInt) offset) >> 2) & 0xFFFFFF)); } /* return a B offset instruction; offset is signed 24bits of WORD offset, so +_32Mbyte range B offset - ARM_ARM v7 DDI10406 pp. A8-44-5 */ /* CogARMCompiler>>#b: */ static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset) { return (((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset) >> 2) & 0xFFFFFF)); } /* ARM calls and jumps span +/- 32 mb, more than enough for intra-zone calls and jumps. */ /* CogARMCompiler>>#callInstructionByteSize */ static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize) { return 4; } /* Answer the address that the call immediately preceding callSiteReturnAddress will jump to. */ /* this is also used by #jumpLongTargetBeforeFollowingAddress:. */ /* CogARMCompiler>>#callTargetFromReturnAddress: */ static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress) { sqInt call; sqInt callDistance; sqInt relativeJump; call = longAt(callSiteReturnAddress - 4); assert((instructionIsB(self_in_callTargetFromReturnAddress, call)) || (instructionIsBL(self_in_callTargetFromReturnAddress, call))); /* begin extractOffsetFromBL: */ relativeJump = call & 0xFFFFFF; relativeJump = (relativeJump & (1U << 23) ? ((int) (((sqInt)((usqInt)((relativeJump | 0x3F000000)) << 2)))) : ((sqInt)((usqInt)(relativeJump) << 2))); callDistance = relativeJump; return (callSiteReturnAddress + 4) + (((int) callDistance)); } /* Because we don't use Thumb, each ARM instruction has 4 bytes. Many abstract opcodes need more than one instruction. Instructions that refer to constants and/or literals depend on literals being stored in-line or out-of-line. N.B. The ^N forms are to get around the bytecode compiler's long branch limits which are exceeded when each case jumps around the otherwise. */ /* CogARMCompiler>>#computeMaximumSize */ static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize) { sqInt constant; sqInt constant1; sqInt constant2; sqInt constant4; sqInt constant5; sqInt i1; sqInt i2; sqInt i3; sqInt value; unsigned int value1; switch ((self_in_computeMaximumSize->opcode)) { case Label: return 0; case Literal: case Fill32: case Nop: case Call: case JumpR: case Jump: case JumpLong: case JumpZero: case JumpNonZero: case JumpNegative: case JumpNonNegative: case JumpOverflow: case JumpNoOverflow: case JumpCarry: case JumpNoCarry: case JumpLess: case JumpGreaterOrEqual: case JumpGreater: case JumpLessOrEqual: case JumpBelow: case JumpAboveOrEqual: case JumpAbove: case JumpBelowOrEqual: case JumpLongZero: case JumpLongNonZero: case Stop: case AddRR: case AndRR: case CmpRR: case OrRR: case XorRR: case SubRR: case NegateR: case LogicalShiftLeftCqR: case LogicalShiftRightCqR: case ArithmeticShiftRightCqR: case LogicalShiftLeftRR: case LogicalShiftRightRR: case ArithmeticShiftRightRR: case AddRdRd: case CmpRdRd: case SubRdRd: case MulRdRd: case DivRdRd: case SqrtRd: case SMULL: case MSR: case CMPSMULL: case PopLDM: case PushSTM: case MoveRR: case MoveRdRd: case MoveXbrRR: case MoveRXbrR: case MoveXwrRR: case MoveRXwrR: case PopR: case PushR: return 4; case AlignmentNops: return (((self_in_computeMaximumSize->operands))[0]) - 4; case CallFull: case JumpFull: case AddCwR: case AndCwR: case CmpCwR: case OrCwR: case SubCwR: case XorCwR: case MoveRdM64r: case MoveM64rRd: return 4 /* literalLoadInstructionBytes */ + 4; case JumpFPEqual: case JumpFPNotEqual: case JumpFPLess: case JumpFPGreaterOrEqual: case JumpFPGreater: case JumpFPLessOrEqual: case JumpFPOrdered: case JumpFPUnordered: case ConvertRRd: return 8; case RetN: return ((((self_in_computeMaximumSize->operands))[0]) == 0 ? 4 : 8); case AddCqR: case CmpCqR: case SubCqR: /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ constant = ((self_in_computeMaximumSize->operands))[0]; value = constant; while (1) { if ((value & 0xFF) == value) { return 4; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value) { return 4; } } if (!((value == constant) && (constant != 0))) break; value = -constant; } return 4 /* literalLoadInstructionBytes */ + 4; case AndCqR: case AndCqRR: case XorCqR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant1 = ((self_in_computeMaximumSize->operands))[0]; value1 = constant1; while (1) { if ((value1 & 0xFF) == value1) { return 4; } for (i2 = 2; i2 <= 30; i2 += 2) { if ((value1 & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == value1) { return 4; } } if (!(value1 == constant1)) break; value1 = (constant1 < 0 ? -1 - constant1 : (unsigned int)~constant1); } return 8; case OrCqR: case TstCqR: case LoadEffectiveAddressMwrR: case MoveM16rR: /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ constant2 = ((self_in_computeMaximumSize->operands))[0]; if ((constant2 & 0xFF) == constant2) { return 4; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant2 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant2) { return 4; } } return 4 /* literalLoadInstructionBytes */ + 4; case MoveCqR: return 4 /* literalLoadInstructionBytes */; case MoveCwR: return 4 /* literalLoadInstructionBytes */; case MoveAwR: case MoveAbR: case PrefetchAw: return (((((self_in_computeMaximumSize->operands))[0]) != null) && (((((self_in_computeMaximumSize->operands))[0]) >= (varBaseAddress())) && (((((self_in_computeMaximumSize->operands))[0]) - (varBaseAddress())) < (1U << 12))) ? 4 : 4 /* literalLoadInstructionBytes */ + 4); case MoveRAw: case MoveRAb: return (((((self_in_computeMaximumSize->operands))[1]) != null) && (((((self_in_computeMaximumSize->operands))[1]) >= (varBaseAddress())) && (((((self_in_computeMaximumSize->operands))[1]) - (varBaseAddress())) < (1U << 12))) ? 4 : 4 /* literalLoadInstructionBytes */ + 4); case MoveRMwr: case MoveRMbr: case MoveRM16r: /* begin is12BitValue:ifTrue:ifFalse: */ constant4 = ((self_in_computeMaximumSize->operands))[1]; if ((SQABS(constant4)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant4 >= 0) { return 4; } else { return 4; } } else { return 4 /* literalLoadInstructionBytes */ + 4; } case MoveMbrR: case MoveMwrR: /* begin is12BitValue:ifTrue:ifFalse: */ constant5 = ((self_in_computeMaximumSize->operands))[0]; if ((SQABS(constant5)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant5 >= 0) { return 4; } else { return 4; } } else { return 4 /* literalLoadInstructionBytes */ + 4; } case PushCw: return 4 /* literalLoadInstructionBytes */ + 4; case PushCq: return 4 /* literalLoadInstructionBytes */ + 4; default: error("Case not found and no otherwise clause"); } return 0; } /* According to IHI0042E ARM Architecture Procedure Calling Standard, in section 5.1.1: A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate r9 as v6). SP = r13, so... */ /* CogARMCompiler>>#concreteCalleeSavedRegisterMask */ static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask) { return 3568; } /* According to IHI0042E ARM Architecture Procedure Calling Standard, in section 5.1.1: A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate r9 as v6). SP = r13, so the callee-saved regs are r4-r8 & r10-r12. The caller-saved registers are those that are not callee-saved and not reserved for hardware/abi uses, i..e r0-r3, r9 & r12. */ /* CogARMCompiler>>#concreteCallerSavedRegisterMask */ static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask) { return 4623; } /* Generate concrete machine code for the instruction at actualAddress, setting machineCodeSize, and answer the following address. */ /* Generate concrete machine code for the instruction at actualAddress, setting machineCodeSize, and answer the following address. */ /* CogARMCompiler>>#concretizeAt: */ static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress) { assert((actualAddress % 4) == 0); (self_in_concretizeAt->address) = actualAddress; dispatchConcretize(self_in_concretizeAt); assert((((self_in_concretizeAt->maxSize)) == null) || (((self_in_concretizeAt->maxSize)) >= ((self_in_concretizeAt->machineCodeSize)))); return actualAddress + ((self_in_concretizeAt->machineCodeSize)); } /* Generate a CMP a, b, ASR #31 instruction, specifically for comparing the resutls of SMULLs in genMulR:R: */ /* CogARMCompiler>>#concretizeCMPSMULL */ static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL) { sqInt aWord; usqInt hiReg; usqInt loReg; hiReg = ((self_in_concretizeCMPSMULL->operands))[0]; loReg = ((self_in_concretizeCMPSMULL->operands))[1]; /* begin machineCodeAt:put: */ aWord = (((((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((hiReg << 16) | (0U << 12))) + (0x1FU << 7)) + (2U << 5)) + loReg; ((self_in_concretizeCMPSMULL->machineCode))[0 / 4] = aWord; return ((self_in_concretizeCMPSMULL->machineCodeSize) = 4); } /* Concretize the current instruction, but with a condition. */ /* CogARMCompiler>>#concretizeConditionalInstruction */ static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction) { sqInt aWord; sqInt i; usqInt instr; unsigned char savedCond; assert(((self_in_concretizeConditionalInstruction->conditionOrNil)) != null); savedCond = (self_in_concretizeConditionalInstruction->conditionOrNil); (self_in_concretizeConditionalInstruction->conditionOrNil) = null; dispatchConcretize(self_in_concretizeConditionalInstruction); (self_in_concretizeConditionalInstruction->conditionOrNil) = savedCond; for (i = 0; i < ((self_in_concretizeConditionalInstruction->machineCodeSize)); i += 4) { instr = (((((self_in_concretizeConditionalInstruction->machineCode))[i / 4]) | (15U << 28)) - (15U << 28)); /* begin machineCodeAt:put: */ aWord = instr | (((int)((usqInt)((((self_in_concretizeConditionalInstruction->conditionOrNil)) & 15)) << 28))); ((self_in_concretizeConditionalInstruction->machineCode))[i / 4] = aWord; } return; } /* fill with operand 0 according to the processor's endianness */ /* CogARMCompiler>>#concretizeFill32 */ static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32) { sqInt aWord; /* begin machineCodeAt:put: */ aWord = ((self_in_concretizeFill32->operands))[0]; ((self_in_concretizeFill32->machineCode))[0 / 4] = aWord; return ((self_in_concretizeFill32->machineCodeSize) = 4); } /* Generate an MSR CPSR_f, #flags instruction. Note that we only have business with the NZCV flags so we use N -> 8 Z -> 4 C -> 2 V -> 1. You don't want to mess with this too much. */ /* CogARMCompiler>>#concretizeMSR */ static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR) { sqInt aWord; usqInt flags; flags = ((self_in_concretizeMSR->operands))[0]; /* begin machineCodeAt:put: */ aWord = msr(self_in_concretizeMSR, flags); ((self_in_concretizeMSR->machineCode))[0 / 4] = aWord; return ((self_in_concretizeMSR->machineCodeSize) = 4); } /* CogARMCompiler>>#concretizePushOrPopMultipleRegisters: */ static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush) { assert((((self_in_concretizePushOrPopMultipleRegisters->operands))[0]) != 0); ((self_in_concretizePushOrPopMultipleRegisters->machineCode))[0] = ((((((int)((usqInt)(AL) << 28))) + ((doPush ? 146U << 20 : 139U << 20))) + (((int)((usqInt)(SP) << 16)))) + (((self_in_concretizePushOrPopMultipleRegisters->operands))[0])); return ((self_in_concretizePushOrPopMultipleRegisters->machineCodeSize) = 4); } /* Generate an SMULL loResultReg, hiResultReg, srcA, srcB instruction */ /* CogARMCompiler>>#concretizeSMULL */ static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL) { sqInt aWord; sqInt hiResultReg; usqInt loResultReg; usqInt srcA; usqInt srcB; /* NOTE: srcB contains the other mutiplicand at this point. It is OK to use it as the destination for the low part of the result and in fact this saves us moving it later */ srcA = ((self_in_concretizeSMULL->operands))[0]; loResultReg = (srcB = ((self_in_concretizeSMULL->operands))[1]); hiResultReg = RISCTempReg; /* begin machineCodeAt:put: */ aWord = (((((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((6U << 21) | (0U << 20)))) | ((((sqInt)((usqInt)(hiResultReg) << 16))) | (loResultReg << 12))) + (srcA << 8)) + (9U << 4)) + srcB; ((self_in_concretizeSMULL->machineCode))[0 / 4] = aWord; return ((self_in_concretizeSMULL->machineCodeSize) = 4); } /* test for the NV condition code; this isn't allowed as an actual condition and is used to encdoe many of the newer instructions */ /* CogARMCompiler>>#conditionIsNotNever: */ static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr) { return (((usqInt) instr) >> 28) < 15; } /* return an {opcode} destReg, srcReg, addReg lsl #shft */ /* important detail - a 0 shft requires setting the shift-type code to 0 to avoid potential instruction confusion */ /* CogARMCompiler>>#dataOpType:rd:rn:rm:lsr: */ static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft) { if (shft == 0) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(armOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (addReg & 0xFFF); } else { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(armOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | ((((((sqInt)((usqInt)(shft) << 7))) | 32) | addReg) & 0xFFF); } } /* Attempt to generate concrete machine code for the instruction at address. This is the inner dispatch of concretizeAt: actualAddress which exists only to get around the branch size limits in the SqueakV3 (blue book derived) bytecode set. */ /* CogARMCompiler>>#dispatchConcretize */ static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize) { usqInt addressOperand; sqInt aWord; sqInt aWord1; sqInt aWord10; sqInt aWord11; sqInt aWord110; sqInt aWord111; sqInt aWord1110; sqInt aWord1111; sqInt aWord1112; sqInt aWord1113; sqInt aWord112; sqInt aWord113; sqInt aWord114; sqInt aWord115; sqInt aWord116; sqInt aWord117; sqInt aWord118; sqInt aWord119; sqInt aWord12; sqInt aWord120; sqInt aWord121; sqInt aWord1210; sqInt aWord1211; sqInt aWord122; sqInt aWord123; sqInt aWord124; sqInt aWord125; sqInt aWord126; sqInt aWord127; sqInt aWord128; sqInt aWord129; sqInt aWord13; sqInt aWord130; sqInt aWord131; sqInt aWord132; sqInt aWord133; sqInt aWord134; sqInt aWord14; sqInt aWord15; sqInt aWord16; sqInt aWord17; sqInt aWord18; sqInt aWord19; sqInt aWord2; sqInt aWord20; sqInt aWord21; sqInt aWord210; sqInt aWord211; sqInt aWord2110; sqInt aWord2111; sqInt aWord212; sqInt aWord213; sqInt aWord214; sqInt aWord215; sqInt aWord216; sqInt aWord217; sqInt aWord218; sqInt aWord219; sqInt aWord22; sqInt aWord220; sqInt aWord221; sqInt aWord222; sqInt aWord223; sqInt aWord224; sqInt aWord225; sqInt aWord226; sqInt aWord23; sqInt aWord24; sqInt aWord25; sqInt aWord26; sqInt aWord27; sqInt aWord28; sqInt aWord29; sqInt aWord3; sqInt aWord30; sqInt aWord31; sqInt aWord310; sqInt aWord311; sqInt aWord312; sqInt aWord313; sqInt aWord314; sqInt aWord315; sqInt aWord316; sqInt aWord32; sqInt aWord33; sqInt aWord34; sqInt aWord35; sqInt aWord36; sqInt aWord37; sqInt aWord38; sqInt aWord39; sqInt aWord4; sqInt aWord40; sqInt aWord41; sqInt aWord410; sqInt aWord411; sqInt aWord42; sqInt aWord43; sqInt aWord44; sqInt aWord45; sqInt aWord46; sqInt aWord47; sqInt aWord48; sqInt aWord49; sqInt aWord5; sqInt aWord50; sqInt aWord51; sqInt aWord52; sqInt aWord53; sqInt aWord54; sqInt aWord55; sqInt aWord56; sqInt aWord57; sqInt aWord58; sqInt aWord59; sqInt aWord6; sqInt aWord60; sqInt aWord61; sqInt aWord62; sqInt aWord63; sqInt aWord64; sqInt aWord65; sqInt aWord66; sqInt aWord67; sqInt aWord68; sqInt aWord7; sqInt aWord8; sqInt aWord9; usqInt base; usqInt base1; usqInt base2; usqInt base3; usqInt baseReg; usqInt baseReg1; usqInt baseReg2; usqInt constant; usqInt constant1; usqInt constant10; sqInt constant11; usqInt constant12; usqInt constant13; usqInt constant14; usqInt constant2; usqInt constant3; usqInt constant4; usqInt constant5; usqInt constant6; usqInt constant7; usqInt constant8; usqInt constant9; AbstractInstruction *dependentChain; usqInt dest; usqInt dest1; usqInt destAddr; usqInt destAddr1; usqInt destReg; usqInt destReg1; usqInt destReg10; usqInt destReg11; usqInt destReg12; usqInt destReg2; usqInt destReg3; usqInt destReg4; usqInt destReg5; usqInt destReg6; usqInt destReg7; usqInt destReg8; usqInt destReg9; sqInt distance; sqInt distance1; sqInt distance2; usqInt distReg; usqInt distReg1; usqInt distReg2; usqInt dstReg; usqInt dstReg1; sqInt flagsOrOpcode; sqInt flagsOrOpcode1; sqInt flagsOrOpcode11; sqInt flagsOrOpcode12; sqInt flagsOrOpcode2; sqInt flagsOrOpcode3; sqInt flagsOrOpcode4; sqInt flagsOrOpcode5; usqInt fpReg; sqInt hb; sqInt hb1; sqInt hb11; sqInt hb12; sqInt hb2; sqInt hb3; sqInt hb4; sqInt hb5; sqInt i; sqInt i1; sqInt i10; sqInt i11; sqInt i12; sqInt i13; sqInt i14; sqInt i15; sqInt i2; sqInt i3; sqInt i4; sqInt i5; sqInt i6; sqInt i7; sqInt i8; sqInt i9; sqInt immediate; sqInt immediate1; sqInt immediate10; sqInt immediate11; sqInt immediate12; sqInt immediate13; sqInt immediate14; sqInt immediate15; sqInt immediate16; sqInt immediate17; sqInt immediate18; sqInt immediate19; sqInt immediate2; sqInt immediate20; sqInt immediate3; sqInt immediate4; sqInt immediate5; sqInt immediate6; sqInt immediate7; sqInt immediate8; sqInt immediate9; usqInt index; usqInt index1; usqInt index2; usqInt index3; usqInt instrOffset; usqInt instrOffset1; usqInt instrOffset10; usqInt instrOffset11; usqInt instrOffset12; usqInt instrOffset13; usqInt instrOffset14; usqInt instrOffset15; usqInt instrOffset16; sqInt instrOffset17; sqInt instrOffset18; sqInt instrOffset19; usqInt instrOffset2; usqInt instrOffset20; usqInt instrOffset21; usqInt instrOffset22; sqInt instrOffset23; usqInt instrOffset24; usqInt instrOffset25; usqInt instrOffset26; usqInt instrOffset27; usqInt instrOffset28; usqInt instrOffset29; usqInt instrOffset3; usqInt instrOffset4; usqInt instrOffset5; usqInt instrOffset6; usqInt instrOffset7; usqInt instrOffset8; usqInt instrOffset9; sqInt invert; sqInt invert1; sqInt invert2; sqInt invert3; sqInt invert4; unsigned int invVal; AbstractInstruction *jumpTarget; AbstractInstruction *jumpTarget1; AbstractInstruction *jumpTarget10; AbstractInstruction *jumpTarget11; AbstractInstruction *jumpTarget110; AbstractInstruction *jumpTarget111; AbstractInstruction *jumpTarget112; AbstractInstruction *jumpTarget113; AbstractInstruction *jumpTarget114; AbstractInstruction *jumpTarget115; AbstractInstruction *jumpTarget116; AbstractInstruction *jumpTarget117; AbstractInstruction *jumpTarget118; AbstractInstruction *jumpTarget119; AbstractInstruction *jumpTarget12; AbstractInstruction *jumpTarget120; AbstractInstruction *jumpTarget121; AbstractInstruction *jumpTarget122; AbstractInstruction *jumpTarget123; AbstractInstruction *jumpTarget124; AbstractInstruction *jumpTarget13; AbstractInstruction *jumpTarget14; AbstractInstruction *jumpTarget15; AbstractInstruction *jumpTarget16; AbstractInstruction *jumpTarget17; AbstractInstruction *jumpTarget18; AbstractInstruction *jumpTarget19; AbstractInstruction *jumpTarget2; AbstractInstruction *jumpTarget20; AbstractInstruction *jumpTarget21; AbstractInstruction *jumpTarget22; AbstractInstruction *jumpTarget23; AbstractInstruction *jumpTarget24; AbstractInstruction *jumpTarget25; AbstractInstruction *jumpTarget26; AbstractInstruction *jumpTarget27; AbstractInstruction *jumpTarget28; AbstractInstruction *jumpTarget29; AbstractInstruction *jumpTarget3; AbstractInstruction *jumpTarget30; AbstractInstruction *jumpTarget31; AbstractInstruction *jumpTarget32; AbstractInstruction *jumpTarget33; AbstractInstruction *jumpTarget34; AbstractInstruction *jumpTarget4; AbstractInstruction *jumpTarget5; AbstractInstruction *jumpTarget6; AbstractInstruction *jumpTarget7; AbstractInstruction *jumpTarget8; AbstractInstruction *jumpTarget9; sqInt negate; sqInt negate1; sqInt offset; sqInt offset1; sqInt offset10; sqInt offset11; sqInt offset12; sqInt offset13; sqInt offset14; sqInt offset15; sqInt offset16; sqInt offset17; sqInt offset18; sqInt offset19; sqInt offset2; sqInt offset20; sqInt offset21; sqInt offset22; sqInt offset23; sqInt offset24; sqInt offset25; sqInt offset26; usqInt offset27; sqInt offset28; sqInt offset29; sqInt offset3; sqInt offset30; sqInt offset31; sqInt offset32; sqInt offset33; sqInt offset4; sqInt offset5; sqInt offset6; sqInt offset7; sqInt offset8; sqInt offset9; sqInt p; int rd; int rd1; int rd10; int rd11; int rd110; int rd111; int rd12; int rd13; int rd14; int rd15; int rd16; int rd17; int rd18; int rd19; int rd2; int rd20; int rd21; int rd22; int rd3; int rd4; int rd5; int rd6; int rd7; int rd8; int rd9; usqInt reg; usqInt reg1; usqInt reg2; usqInt reg3; usqInt reg4; usqInt reg5; usqInt reg6; usqInt reg7; usqInt regA; usqInt regB; usqInt regLHS; usqInt regLHS1; usqInt regLHS2; usqInt regLHS3; usqInt regLHS4; usqInt regRHS; usqInt regRHS1; usqInt regRHS2; usqInt regRHS3; usqInt rn; usqInt rn1; usqInt rn10; usqInt rn11; usqInt rn110; usqInt rn111; usqInt rn12; usqInt rn13; usqInt rn14; usqInt rn15; usqInt rn16; usqInt rn17; usqInt rn18; usqInt rn19; usqInt rn2; usqInt rn20; usqInt rn21; usqInt rn22; usqInt rn23; usqInt rn24; usqInt rn3; usqInt rn4; usqInt rn5; usqInt rn6; usqInt rn7; usqInt rn8; usqInt rn9; sqInt rot; sqInt rot1; sqInt rot10; sqInt rot11; sqInt rot12; sqInt rot13; sqInt rot2; sqInt rot3; sqInt rot4; sqInt rot5; sqInt rot6; sqInt rot7; sqInt rot8; sqInt rot9; usqInt src; usqInt src1; usqInt srcAddr; usqInt srcAddr1; usqInt srcReg; usqInt srcReg1; usqInt srcReg10; usqInt srcReg11; usqInt srcReg12; usqInt srcReg13; usqInt srcReg14; usqInt srcReg15; usqInt srcReg16; usqInt srcReg17; usqInt srcReg18; usqInt srcReg19; usqInt srcReg2; usqInt srcReg3; usqInt srcReg4; usqInt srcReg5; usqInt srcReg6; usqInt srcReg7; usqInt srcReg8; usqInt srcReg9; int u; int u1; sqInt val; sqInt val1; sqInt val11; sqInt val12; sqInt val2; usqInt val3; sqInt val4; sqInt val5; sqInt value; sqInt value1; unsigned int value2; unsigned int value3; unsigned int value4; unsigned int value5; unsigned int value6; sqInt word; sqInt word1; usqInt word2; usqInt word3; if (!(((self_in_dispatchConcretize->conditionOrNil)) == null)) { concretizeConditionalInstruction(self_in_dispatchConcretize); return; } switch ((self_in_dispatchConcretize->opcode)) { case Label: /* begin concretizeLabel */ dependentChain = (self_in_dispatchConcretize->dependent); while (!(dependentChain == null)) { /* begin updateLabel: */ if (((dependentChain->opcode)) != Literal) { assert((((dependentChain->opcode)) == MoveCwR) || (((dependentChain->opcode)) == PushCw)); ((dependentChain->operands))[0] = (((self_in_dispatchConcretize->address)) + (((self_in_dispatchConcretize->operands))[1])); } dependentChain = (dependentChain->dependent); } (self_in_dispatchConcretize->machineCodeSize) = 0; return; case Literal: concretizeLiteral(self_in_dispatchConcretize); return; case AlignmentNops: /* begin concretizeAlignmentNops */ assert((((self_in_dispatchConcretize->machineCodeSize)) % 4) == 0); for (p = 0; p < ((self_in_dispatchConcretize->machineCodeSize)); p += 4) { /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[p / 4] = 3785359360U; } return; case Fill32: concretizeFill32(self_in_dispatchConcretize); return; case Nop: /* begin concretizeNop */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 3785359360U; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case Call: /* begin concretizeCall */ assert((((self_in_dispatchConcretize->operands))[0]) != 0); assert(((((self_in_dispatchConcretize->operands))[0]) % 4) == 0); /* normal pc offset */ offset2 = (((int) (((self_in_dispatchConcretize->operands))[0]))) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset2)); /* begin machineCodeAt:put: */ aWord = bl(self_in_dispatchConcretize, offset2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CallFull: /* begin concretizeCallFull */ jumpTarget1 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); if ((addressIsInInstructions(jumpTarget1)) || (jumpTarget1 == (methodLabel()))) { jumpTarget1 = ((AbstractInstruction *) ((jumpTarget1->address))); } assert(jumpTarget1 != 0); jumpTarget = jumpTarget1; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord1 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1; instrOffset = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[instrOffset / 4] = ((((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((1 & 1)) << 5)))) | ConcreteIPReg)); assert(instrOffset == (literalLoadInstructionBytes(self_in_dispatchConcretize))); (self_in_dispatchConcretize->machineCodeSize) = instrOffset + 4; return; case JumpR: /* begin concretizeJumpR */ /* bx reg */ reg = ((self_in_dispatchConcretize->operands))[0]; aWord2 = (((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((0 & 1)) << 5)))) | reg); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord2; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpFull: /* begin concretizeJumpFull */ jumpTarget11 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); if ((addressIsInInstructions(jumpTarget11)) || (jumpTarget11 == (methodLabel()))) { jumpTarget11 = ((AbstractInstruction *) ((jumpTarget11->address))); } assert(jumpTarget11 != 0); jumpTarget2 = jumpTarget11; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord3 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord3; instrOffset1 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[instrOffset1 / 4] = ((((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((0 & 1)) << 5)))) | ConcreteIPReg)); (self_in_dispatchConcretize->machineCodeSize) = instrOffset1 + 4; return; case JumpLong: case Jump: /* begin concretizeConditionalJump: */ jumpTarget12 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget12); if ((addressIsInInstructions(jumpTarget12)) || (jumpTarget12 == (methodLabel()))) { jumpTarget12 = ((AbstractInstruction *) ((jumpTarget12->address))); } assert(jumpTarget12 != 0); jumpTarget3 = jumpTarget12; offset3 = (((int) jumpTarget3)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset3)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset3) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLongZero: case JumpZero: /* begin concretizeConditionalJump: */ jumpTarget13 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget13); if ((addressIsInInstructions(jumpTarget13)) || (jumpTarget13 == (methodLabel()))) { jumpTarget13 = ((AbstractInstruction *) ((jumpTarget13->address))); } assert(jumpTarget13 != 0); jumpTarget4 = jumpTarget13; offset4 = (((int) jumpTarget4)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset4)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(EQ) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset4) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLongNonZero: case JumpNonZero: /* begin concretizeConditionalJump: */ jumpTarget14 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget14); if ((addressIsInInstructions(jumpTarget14)) || (jumpTarget14 == (methodLabel()))) { jumpTarget14 = ((AbstractInstruction *) ((jumpTarget14->address))); } assert(jumpTarget14 != 0); jumpTarget5 = jumpTarget14; offset5 = (((int) jumpTarget5)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset5)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(NE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset5) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNegative: /* begin concretizeConditionalJump: */ jumpTarget15 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget15); if ((addressIsInInstructions(jumpTarget15)) || (jumpTarget15 == (methodLabel()))) { jumpTarget15 = ((AbstractInstruction *) ((jumpTarget15->address))); } assert(jumpTarget15 != 0); jumpTarget6 = jumpTarget15; offset6 = (((int) jumpTarget6)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset6)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(MI) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset6) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNonNegative: /* begin concretizeConditionalJump: */ jumpTarget16 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget16); if ((addressIsInInstructions(jumpTarget16)) || (jumpTarget16 == (methodLabel()))) { jumpTarget16 = ((AbstractInstruction *) ((jumpTarget16->address))); } assert(jumpTarget16 != 0); jumpTarget7 = jumpTarget16; offset7 = (((int) jumpTarget7)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset7)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(PL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset7) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpOverflow: /* begin concretizeConditionalJump: */ jumpTarget17 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget17); if ((addressIsInInstructions(jumpTarget17)) || (jumpTarget17 == (methodLabel()))) { jumpTarget17 = ((AbstractInstruction *) ((jumpTarget17->address))); } assert(jumpTarget17 != 0); jumpTarget8 = jumpTarget17; offset8 = (((int) jumpTarget8)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset8)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(VS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset8) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNoOverflow: /* begin concretizeConditionalJump: */ jumpTarget18 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget18); if ((addressIsInInstructions(jumpTarget18)) || (jumpTarget18 == (methodLabel()))) { jumpTarget18 = ((AbstractInstruction *) ((jumpTarget18->address))); } assert(jumpTarget18 != 0); jumpTarget9 = jumpTarget18; offset9 = (((int) jumpTarget9)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset9)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(VC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset9) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpCarry: case JumpAboveOrEqual: /* begin concretizeConditionalJump: */ jumpTarget19 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget19); if ((addressIsInInstructions(jumpTarget19)) || (jumpTarget19 == (methodLabel()))) { jumpTarget19 = ((AbstractInstruction *) ((jumpTarget19->address))); } assert(jumpTarget19 != 0); jumpTarget10 = jumpTarget19; offset10 = (((int) jumpTarget10)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset10)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(CS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset10) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNoCarry: case JumpBelow: /* begin concretizeConditionalJump: */ jumpTarget110 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget110); if ((addressIsInInstructions(jumpTarget110)) || (jumpTarget110 == (methodLabel()))) { jumpTarget110 = ((AbstractInstruction *) ((jumpTarget110->address))); } assert(jumpTarget110 != 0); jumpTarget20 = jumpTarget110; offset11 = (((int) jumpTarget20)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset11)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(CC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset11) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLess: /* begin concretizeConditionalJump: */ jumpTarget111 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget111); if ((addressIsInInstructions(jumpTarget111)) || (jumpTarget111 == (methodLabel()))) { jumpTarget111 = ((AbstractInstruction *) ((jumpTarget111->address))); } assert(jumpTarget111 != 0); jumpTarget21 = jumpTarget111; offset12 = (((int) jumpTarget21)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset12)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset12) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpGreaterOrEqual: /* begin concretizeConditionalJump: */ jumpTarget112 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget112); if ((addressIsInInstructions(jumpTarget112)) || (jumpTarget112 == (methodLabel()))) { jumpTarget112 = ((AbstractInstruction *) ((jumpTarget112->address))); } assert(jumpTarget112 != 0); jumpTarget22 = jumpTarget112; offset13 = (((int) jumpTarget22)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset13)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(GE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset13) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpGreater: /* begin concretizeConditionalJump: */ jumpTarget113 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget113); if ((addressIsInInstructions(jumpTarget113)) || (jumpTarget113 == (methodLabel()))) { jumpTarget113 = ((AbstractInstruction *) ((jumpTarget113->address))); } assert(jumpTarget113 != 0); jumpTarget23 = jumpTarget113; offset14 = (((int) jumpTarget23)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset14)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(GT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset14) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLessOrEqual: /* begin concretizeConditionalJump: */ jumpTarget114 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget114); if ((addressIsInInstructions(jumpTarget114)) || (jumpTarget114 == (methodLabel()))) { jumpTarget114 = ((AbstractInstruction *) ((jumpTarget114->address))); } assert(jumpTarget114 != 0); jumpTarget24 = jumpTarget114; offset15 = (((int) jumpTarget24)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset15)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset15) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpAbove: /* begin concretizeConditionalJump: */ jumpTarget115 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget115); if ((addressIsInInstructions(jumpTarget115)) || (jumpTarget115 == (methodLabel()))) { jumpTarget115 = ((AbstractInstruction *) ((jumpTarget115->address))); } assert(jumpTarget115 != 0); jumpTarget25 = jumpTarget115; offset16 = (((int) jumpTarget25)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset16)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(HI) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset16) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpBelowOrEqual: /* begin concretizeConditionalJump: */ jumpTarget116 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget116); if ((addressIsInInstructions(jumpTarget116)) || (jumpTarget116 == (methodLabel()))) { jumpTarget116 = ((AbstractInstruction *) ((jumpTarget116->address))); } assert(jumpTarget116 != 0); jumpTarget26 = jumpTarget116; offset17 = (((int) jumpTarget26)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset17)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset17) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpFPEqual: /* begin concretizeFPConditionalJump: */ jumpTarget117 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget117); if ((addressIsInInstructions(jumpTarget117)) || (jumpTarget117 == (methodLabel()))) { jumpTarget117 = ((AbstractInstruction *) ((jumpTarget117->address))); } assert(jumpTarget117 != 0); jumpTarget27 = jumpTarget117; offset18 = (((int) jumpTarget27)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset18)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(EQ) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset18) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPNotEqual: /* begin concretizeFPConditionalJump: */ jumpTarget118 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget118); if ((addressIsInInstructions(jumpTarget118)) || (jumpTarget118 == (methodLabel()))) { jumpTarget118 = ((AbstractInstruction *) ((jumpTarget118->address))); } assert(jumpTarget118 != 0); jumpTarget28 = jumpTarget118; offset19 = (((int) jumpTarget28)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset19)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(NE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset19) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPLess: /* begin concretizeFPConditionalJump: */ jumpTarget119 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget119); if ((addressIsInInstructions(jumpTarget119)) || (jumpTarget119 == (methodLabel()))) { jumpTarget119 = ((AbstractInstruction *) ((jumpTarget119->address))); } assert(jumpTarget119 != 0); jumpTarget29 = jumpTarget119; offset20 = (((int) jumpTarget29)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset20)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(LT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset20) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPGreaterOrEqual: /* begin concretizeFPConditionalJump: */ jumpTarget120 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget120); if ((addressIsInInstructions(jumpTarget120)) || (jumpTarget120 == (methodLabel()))) { jumpTarget120 = ((AbstractInstruction *) ((jumpTarget120->address))); } assert(jumpTarget120 != 0); jumpTarget30 = jumpTarget120; offset21 = (((int) jumpTarget30)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset21)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(GE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset21) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPGreater: /* begin concretizeFPConditionalJump: */ jumpTarget121 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget121); if ((addressIsInInstructions(jumpTarget121)) || (jumpTarget121 == (methodLabel()))) { jumpTarget121 = ((AbstractInstruction *) ((jumpTarget121->address))); } assert(jumpTarget121 != 0); jumpTarget31 = jumpTarget121; offset22 = (((int) jumpTarget31)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset22)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(GT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset22) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPLessOrEqual: /* begin concretizeFPConditionalJump: */ jumpTarget122 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget122); if ((addressIsInInstructions(jumpTarget122)) || (jumpTarget122 == (methodLabel()))) { jumpTarget122 = ((AbstractInstruction *) ((jumpTarget122->address))); } assert(jumpTarget122 != 0); jumpTarget32 = jumpTarget122; offset23 = (((int) jumpTarget32)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset23)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(LE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset23) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPOrdered: /* begin concretizeFPConditionalJump: */ jumpTarget123 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget123); if ((addressIsInInstructions(jumpTarget123)) || (jumpTarget123 == (methodLabel()))) { jumpTarget123 = ((AbstractInstruction *) ((jumpTarget123->address))); } assert(jumpTarget123 != 0); jumpTarget33 = jumpTarget123; offset24 = (((int) jumpTarget33)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset24)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(VC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset24) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPUnordered: /* begin concretizeFPConditionalJump: */ jumpTarget124 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget124); if ((addressIsInInstructions(jumpTarget124)) || (jumpTarget124 == (methodLabel()))) { jumpTarget124 = ((AbstractInstruction *) ((jumpTarget124->address))); } assert(jumpTarget124 != 0); jumpTarget34 = jumpTarget124; offset25 = (((int) jumpTarget34)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset25)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(VS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset25) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case RetN: /* begin concretizeRetN */ offset26 = ((self_in_dispatchConcretize->operands))[0]; if (offset26 == 0) { /* begin machineCodeAt:put: */ aWord4 = movrn(self_in_dispatchConcretize, PC, LR); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord4; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l133; } assert(offset26 < 0xFF); /* begin machineCodeAt:put: */ aWord11 = addrnimmror(self_in_dispatchConcretize, SP, SP, offset26, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord11; /* begin machineCodeAt:put: */ aWord21 = movrn(self_in_dispatchConcretize, PC, LR); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord21; (self_in_dispatchConcretize->machineCodeSize) = 8; l133: /* end concretizeRetN */; return; case Stop: /* begin concretizeStop */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(AL) << 28))) | ((66U << 20) | (7U << 4))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AddCqR: /* begin concretizeNegateableDataOperationCqR: */ val = ((self_in_dispatchConcretize->operands))[0]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen. */ rn = ((self_in_dispatchConcretize->operands))[1]; rd = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value = val; while (1) { if ((value & 0xFF) == value) { negate = val != value; /* begin machineCodeAt:put: */ flagsOrOpcode = (negate ? inverseOpcodeFor(self_in_dispatchConcretize, AddOpcode) : AddOpcode); aWord5 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode) << 21))) | (1U << 20)))) | ((rn << 16) | (((int)((usqInt)(rd) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord5; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l143; goto l136; } for (i = 2; i <= 30; i += 2) { if ((value & (((0xFFU << i) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i)))) == value) { rot = 32 - i; immediate = (((usqInt) value) >> i) | ((((sqInt)((usqInt)(value) << (32 - i)))) & 0xFFFFFFFFU); negate = val != value; /* begin machineCodeAt:put: */ flagsOrOpcode1 = (negate ? inverseOpcodeFor(self_in_dispatchConcretize, AddOpcode) : AddOpcode); aWord5 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode1) << 21))) | (1U << 20)))) | ((rn << 16) | (((int)((usqInt)(rd) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord5; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l143; goto l136; } } if (!((value == val) && (val != 0))) break; value = -val; } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val > 0) { hb = highBit(val); if ((1U << hb) == (val + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord12 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord12; /* begin machineCodeAt:put: */ aWord22 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AddOpcode, rd, rn, ConcreteIPReg, 32 - hb); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord22; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l143; } } /* begin concretizeDataOperationCwR: */ constant = ((self_in_dispatchConcretize->operands))[0]; rn1 = ((self_in_dispatchConcretize->operands))[1]; rd1 = rn1; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord31 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord31; instrOffset2 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord111 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn1 << 16) | (((int)((usqInt)(rd1) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset2 / 4] = aWord111; (self_in_dispatchConcretize->machineCodeSize) = instrOffset2 + 4; goto l143; l136: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; l143: /* end concretizeNegateableDataOperationCqR: */; return; case AndCqR: /* begin concretizeInvertibleDataOperationCqR: */ val2 = ((self_in_dispatchConcretize->operands))[0]; rn18 = ((self_in_dispatchConcretize->operands))[1]; assert(!((((self_in_dispatchConcretize->opcode)) == CmpOpcode))); /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value4 = val2; while (1) { if ((value4 & 0xFF) == value4) { invert2 = val2 != value4; /* begin machineCodeAt:put: */ flagsOrOpcode2 = (invert2 ? inverseOpcodeFor(self_in_dispatchConcretize, AndOpcode) : AndOpcode); aWord65 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode2) << 21))) | (1U << 20)))) | ((rn18 << 16) | (rn18 << 12))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value4) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord65; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l319; } for (i8 = 2; i8 <= 30; i8 += 2) { if ((value4 & (((0xFFU << i8) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i8)))) == value4) { rot8 = 32 - i8; immediate15 = (((usqInt) value4) >> i8) | ((value4 << (32 - i8)) & 0xFFFFFFFFU); invert2 = val2 != value4; /* begin machineCodeAt:put: */ flagsOrOpcode11 = (invert2 ? inverseOpcodeFor(self_in_dispatchConcretize, AndOpcode) : AndOpcode); aWord65 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode11) << 21))) | (1U << 20)))) | ((rn18 << 16) | (rn18 << 12))) | (((((sqInt)((usqInt)((((usqInt) rot8) >> 1)) << 8))) | immediate15) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord65; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l319; } } if (!(value4 == val2)) break; value4 = (val2 < 0 ? -1 - val2 : (unsigned int)~val2); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val2 > 0) { hb2 = highBit(val2); if ((1U << hb2) == (val2 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord131 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord131; /* begin machineCodeAt:put: */ aWord223 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, rn18, rn18, ConcreteIPReg, 32 - hb2); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord223; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l331; } } /* begin concretizeDataOperationCqR: */ val11 = ((self_in_dispatchConcretize->operands))[0]; rn21 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd18 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn21); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val11 & 0xFF) == val11) { /* begin machineCodeAt:put: */ aWord410 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn21 << 16) | (((int)((usqInt)(rd18) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val11) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord410; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l365; } for (i13 = 2; i13 <= 30; i13 += 2) { if ((val11 & (((0xFFU << i13) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i13)))) == val11) { rot11 = 32 - i13; immediate14 = (((usqInt) val11) >> i13) | ((((sqInt)((usqInt)(val11) << (32 - i13)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord410 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn21 << 16) | (((int)((usqInt)(rd18) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot11) >> 1)) << 8))) | immediate14) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord410; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l365; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val11 > 0) { hb11 = highBit(val11); if ((1U << hb11) == (val11 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord1210 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1210; /* begin machineCodeAt:put: */ aWord2110 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, rd18, rn21, ConcreteIPReg, 32 - hb11); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord2110; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l331; } } /* begin concretizeDataOperationCwR: */ constant10 = ((self_in_dispatchConcretize->operands))[0]; rn19 = ((self_in_dispatchConcretize->operands))[1]; rd19 = rn19; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord313 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord313; instrOffset26 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1110 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn19 << 16) | (((int)((usqInt)(rd19) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset26 / 4] = aWord1110; (self_in_dispatchConcretize->machineCodeSize) = instrOffset26 + 4; goto l331; l365: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; goto l331; l319: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l331: /* end concretizeInvertibleDataOperationCqR: */; return; case AndCqRR: /* begin concretizeAndCqRR */ val3 = ((self_in_dispatchConcretize->operands))[0]; srcReg19 = ((self_in_dispatchConcretize->operands))[1]; dstReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value5 = val3; while (1) { if ((value5 & 0xFF) == value5) { invert3 = val3 != value5; /* begin machineCodeAt:put: */ aWord66 = (invert3 ? bicsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, value5, 0) : andsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, value5, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord66; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l339; goto l337; } for (i9 = 2; i9 <= 30; i9 += 2) { if ((value5 & (((0xFFU << i9) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i9)))) == value5) { rot9 = 32 - i9; immediate16 = (((usqInt) value5) >> i9) | ((value5 << (32 - i9)) & 0xFFFFFFFFU); invert3 = val3 != value5; /* begin machineCodeAt:put: */ aWord66 = (invert3 ? bicsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, immediate16, rot9) : andsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, immediate16, rot9)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord66; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l339; goto l337; } } if (!(value5 == val3)) break; value5 = (val3 < 0 ? -1 - val3 : (unsigned int)~val3); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ hb3 = highBit(((self_in_dispatchConcretize->operands))[0]); if ((1U << hb3) == (val3 + 1)) { /* MVN temp reg, 0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord132 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord132; /* begin machineCodeAt:put: */ aWord224 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, dstReg1, srcReg19, ConcreteIPReg, 32 - hb3); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord224; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l339; } else { /* begin concretizeDataOperationCwR: */ constant12 = ((self_in_dispatchConcretize->operands))[0]; rn20 = ((self_in_dispatchConcretize->operands))[1]; rd20 = rn20; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord314 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord314; instrOffset27 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1111 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn20 << 16) | (((int)((usqInt)(rd20) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset27 / 4] = aWord1111; (self_in_dispatchConcretize->machineCodeSize) = instrOffset27 + 4; goto l339; } l337: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l339: /* end concretizeAndCqRR */; return; case CmpCqR: /* begin concretizeNegateableDataOperationCqR: */ val1 = ((self_in_dispatchConcretize->operands))[0]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen. */ rn2 = ((self_in_dispatchConcretize->operands))[1]; rd2 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn2); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value1 = val1; while (1) { if ((value1 & 0xFF) == value1) { negate1 = val1 != value1; /* begin machineCodeAt:put: */ flagsOrOpcode3 = (negate1 ? inverseOpcodeFor(self_in_dispatchConcretize, CmpOpcode) : CmpOpcode); aWord6 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode3) << 21))) | (1U << 20)))) | ((rn2 << 16) | (((int)((usqInt)(rd2) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value1) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord6; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l151; goto l144; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value1 & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value1) { rot1 = 32 - i1; immediate1 = (((usqInt) value1) >> i1) | ((((sqInt)((usqInt)(value1) << (32 - i1)))) & 0xFFFFFFFFU); negate1 = val1 != value1; /* begin machineCodeAt:put: */ flagsOrOpcode4 = (negate1 ? inverseOpcodeFor(self_in_dispatchConcretize, CmpOpcode) : CmpOpcode); aWord6 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode4) << 21))) | (1U << 20)))) | ((rn2 << 16) | (((int)((usqInt)(rd2) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot1) >> 1)) << 8))) | immediate1) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord6; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l151; goto l144; } } if (!((value1 == val1) && (val1 != 0))) break; value1 = -val1; } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val1 > 0) { hb1 = highBit(val1); if ((1U << hb1) == (val1 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord13 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord13; /* begin machineCodeAt:put: */ aWord23 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, CmpOpcode, rd2, rn2, ConcreteIPReg, 32 - hb1); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord23; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l151; } } /* begin concretizeDataOperationCwR: */ constant1 = ((self_in_dispatchConcretize->operands))[0]; rn11 = ((self_in_dispatchConcretize->operands))[1]; rd11 = 0; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord32 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord32; instrOffset3 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord112 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn11 << 16) | (((int)((usqInt)(rd11) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset3 / 4] = aWord112; (self_in_dispatchConcretize->machineCodeSize) = instrOffset3 + 4; goto l151; l144: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; l151: /* end concretizeNegateableDataOperationCqR: */; return; case OrCqR: /* begin concretizeDataOperationCqR: */ val4 = ((self_in_dispatchConcretize->operands))[0]; rn22 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd21 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn22); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val4 & 0xFF) == val4) { /* begin machineCodeAt:put: */ aWord67 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn22 << 16) | (((int)((usqInt)(rd21) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val4) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord67; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l349; goto l347; } for (i10 = 2; i10 <= 30; i10 += 2) { if ((val4 & (((0xFFU << i10) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i10)))) == val4) { rot10 = 32 - i10; immediate17 = (((usqInt) val4) >> i10) | ((((sqInt)((usqInt)(val4) << (32 - i10)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord67 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn22 << 16) | (((int)((usqInt)(rd21) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot10) >> 1)) << 8))) | immediate17) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord67; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l349; goto l347; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val4 > 0) { hb4 = highBit(val4); if ((1U << hb4) == (val4 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord133 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord133; /* begin machineCodeAt:put: */ aWord225 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, OrOpcode, rd21, rn22, ConcreteIPReg, 32 - hb4); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord225; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l349; } } /* begin concretizeDataOperationCwR: */ constant13 = ((self_in_dispatchConcretize->operands))[0]; rn110 = ((self_in_dispatchConcretize->operands))[1]; rd110 = rn110; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord315 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord315; instrOffset28 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1112 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn110 << 16) | (((int)((usqInt)(rd110) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset28 / 4] = aWord1112; (self_in_dispatchConcretize->machineCodeSize) = instrOffset28 + 4; goto l349; l347: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l349: /* end concretizeDataOperationCqR: */; return; case SubCqR: /* begin concretizeSubCqR */ word = ((self_in_dispatchConcretize->operands))[0]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((word & 0xFF) == word) { reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord7 = subsrnimmror(self_in_dispatchConcretize, reg1, reg1, word, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord7; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l152; } for (i11 = 2; i11 <= 30; i11 += 2) { if ((word & (((0xFFU << i11) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i11)))) == word) { rot2 = 32 - i11; immediate2 = (((usqInt) word) >> i11) | ((((sqInt)((usqInt)(word) << (32 - i11)))) & 0xFFFFFFFFU); reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord7 = subsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, rot2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord7; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l152; } } /* before building a full load of a big constant, see if we can do an add of the constant negated */ /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if (((-word) & 0xFF) == (-word)) { immediate2 = -word; reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord14 = addsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord14; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l366; } for (i2 = 2; i2 <= 30; i2 += 2) { if (((-word) & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == (-word)) { rot2 = 32 - i2; immediate2 = (((usqInt) (-word)) >> i2) | ((((sqInt)((usqInt)((-word)) << (32 - i2)))) & 0xFFFFFFFFU); reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord14 = addsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, rot2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord14; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l366; } } /* begin concretizeDataOperationCwR: */ constant2 = ((self_in_dispatchConcretize->operands))[0]; rn3 = ((self_in_dispatchConcretize->operands))[1]; rd3 = rn3; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord24 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord24; instrOffset4 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord113 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn3 << 16) | (((int)((usqInt)(rd3) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset4 / 4] = aWord113; (self_in_dispatchConcretize->machineCodeSize) = instrOffset4 + 4; goto l159; l366: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l152: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l159: /* end concretizeSubCqR */; return; case TstCqR: /* begin concretizeTstCqR */ constant11 = ((self_in_dispatchConcretize->operands))[0]; if ((constant11 & 0xFF) == constant11) { reg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord8 = tstrnimmror(self_in_dispatchConcretize, reg2, reg2, constant11, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord8; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l165; goto l160; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant11 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant11) { rot3 = 32 - i3; immediate3 = (((usqInt) constant11) >> i3) | ((((sqInt)((usqInt)(constant11) << (32 - i3)))) & 0xFFFFFFFFU); reg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord8 = tstrnimmror(self_in_dispatchConcretize, reg2, reg2, immediate3, rot3); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord8; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l165; goto l160; } } /* begin concretizeDataOperationCwR: */ constant3 = ((self_in_dispatchConcretize->operands))[0]; rn4 = ((self_in_dispatchConcretize->operands))[1]; rd4 = rn4; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord25 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord25; instrOffset5 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord15 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(TstOpcode) << 21))) | (1U << 20)))) | ((rn4 << 16) | (((int)((usqInt)(rd4) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset5 / 4] = aWord15; (self_in_dispatchConcretize->machineCodeSize) = instrOffset5 + 4; goto l165; l160: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l165: /* end concretizeTstCqR */; return; case XorCqR: /* begin concretizeInvertibleDataOperationCqR: */ val5 = ((self_in_dispatchConcretize->operands))[0]; rn23 = ((self_in_dispatchConcretize->operands))[1]; assert(!((((self_in_dispatchConcretize->opcode)) == CmpOpcode))); /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value6 = val5; while (1) { if ((value6 & 0xFF) == value6) { invert4 = val5 != value6; /* begin machineCodeAt:put: */ flagsOrOpcode5 = (invert4 ? inverseOpcodeFor(self_in_dispatchConcretize, XorOpcode) : XorOpcode); aWord68 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode5) << 21))) | (1U << 20)))) | ((rn23 << 16) | (rn23 << 12))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value6) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord68; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l351; } for (i15 = 2; i15 <= 30; i15 += 2) { if ((value6 & (((0xFFU << i15) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i15)))) == value6) { rot12 = 32 - i15; immediate19 = (((usqInt) value6) >> i15) | ((value6 << (32 - i15)) & 0xFFFFFFFFU); invert4 = val5 != value6; /* begin machineCodeAt:put: */ flagsOrOpcode12 = (invert4 ? inverseOpcodeFor(self_in_dispatchConcretize, XorOpcode) : XorOpcode); aWord68 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode12) << 21))) | (1U << 20)))) | ((rn23 << 16) | (rn23 << 12))) | (((((sqInt)((usqInt)((((usqInt) rot12) >> 1)) << 8))) | immediate19) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord68; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l351; } } if (!(value6 == val5)) break; value6 = (val5 < 0 ? -1 - val5 : (unsigned int)~val5); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val5 > 0) { hb5 = highBit(val5); if ((1U << hb5) == (val5 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord134 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord134; /* begin machineCodeAt:put: */ aWord226 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, XorOpcode, rn23, rn23, ConcreteIPReg, 32 - hb5); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord226; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l363; } } /* begin concretizeDataOperationCqR: */ val12 = ((self_in_dispatchConcretize->operands))[0]; rn24 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd22 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn24); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val12 & 0xFF) == val12) { /* begin machineCodeAt:put: */ aWord411 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn24 << 16) | (((int)((usqInt)(rd22) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val12) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord411; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l367; } for (i14 = 2; i14 <= 30; i14 += 2) { if ((val12 & (((0xFFU << i14) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i14)))) == val12) { rot13 = 32 - i14; immediate18 = (((usqInt) val12) >> i14) | ((((sqInt)((usqInt)(val12) << (32 - i14)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord411 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn24 << 16) | (((int)((usqInt)(rd22) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot13) >> 1)) << 8))) | immediate18) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord411; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l367; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val12 > 0) { hb12 = highBit(val12); if ((1U << hb12) == (val12 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord1211 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1211; /* begin machineCodeAt:put: */ aWord2111 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, XorOpcode, rd22, rn24, ConcreteIPReg, 32 - hb12); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord2111; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l363; } } /* begin concretizeDataOperationCwR: */ constant14 = ((self_in_dispatchConcretize->operands))[0]; rn111 = ((self_in_dispatchConcretize->operands))[1]; rd111 = rn111; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord316 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord316; instrOffset29 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1113 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn111 << 16) | (((int)((usqInt)(rd111) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset29 / 4] = aWord1113; (self_in_dispatchConcretize->machineCodeSize) = instrOffset29 + 4; goto l363; l367: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; goto l363; l351: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l363: /* end concretizeInvertibleDataOperationCqR: */; return; case AddCwR: /* begin concretizeDataOperationCwR: */ constant4 = ((self_in_dispatchConcretize->operands))[0]; rn5 = ((self_in_dispatchConcretize->operands))[1]; rd5 = rn5; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord9 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord9; instrOffset6 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord16 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn5 << 16) | (((int)((usqInt)(rd5) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset6 / 4] = aWord16; (self_in_dispatchConcretize->machineCodeSize) = instrOffset6 + 4; return; case AndCwR: /* begin concretizeDataOperationCwR: */ constant5 = ((self_in_dispatchConcretize->operands))[0]; rn6 = ((self_in_dispatchConcretize->operands))[1]; rd6 = rn6; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord10 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord10; instrOffset7 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord17 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn6 << 16) | (((int)((usqInt)(rd6) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset7 / 4] = aWord17; (self_in_dispatchConcretize->machineCodeSize) = instrOffset7 + 4; return; case CmpCwR: /* begin concretizeDataOperationCwR: */ constant6 = ((self_in_dispatchConcretize->operands))[0]; rn7 = ((self_in_dispatchConcretize->operands))[1]; rd7 = 0; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord18 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord18; instrOffset8 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord19 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn7 << 16) | (((int)((usqInt)(rd7) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset8 / 4] = aWord19; (self_in_dispatchConcretize->machineCodeSize) = instrOffset8 + 4; return; case OrCwR: /* begin concretizeDataOperationCwR: */ constant7 = ((self_in_dispatchConcretize->operands))[0]; rn8 = ((self_in_dispatchConcretize->operands))[1]; rd8 = rn8; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord20 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord20; instrOffset9 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord110 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn8 << 16) | (((int)((usqInt)(rd8) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset9 / 4] = aWord110; (self_in_dispatchConcretize->machineCodeSize) = instrOffset9 + 4; return; case SubCwR: /* begin concretizeDataOperationCwR: */ constant8 = ((self_in_dispatchConcretize->operands))[0]; rn9 = ((self_in_dispatchConcretize->operands))[1]; rd9 = rn9; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord26 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord26; instrOffset10 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord114 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn9 << 16) | (((int)((usqInt)(rd9) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset10 / 4] = aWord114; (self_in_dispatchConcretize->machineCodeSize) = instrOffset10 + 4; return; case XorCwR: /* begin concretizeDataOperationCwR: */ constant9 = ((self_in_dispatchConcretize->operands))[0]; rn10 = ((self_in_dispatchConcretize->operands))[1]; rd10 = rn10; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord27 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord27; instrOffset11 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord115 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn10 << 16) | (((int)((usqInt)(rd10) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset11 / 4] = aWord115; (self_in_dispatchConcretize->machineCodeSize) = instrOffset11 + 4; return; case AddRR: /* begin concretizeDataOperationRR: */ srcReg1 = ((self_in_dispatchConcretize->operands))[0]; rn12 = ((self_in_dispatchConcretize->operands))[1]; rd12 = rn12; /* begin machineCodeAt:put: */ aWord28 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn12 << 16) | (((int)((usqInt)(rd12) << 12))))) | (srcReg1 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord28; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AndRR: /* begin concretizeDataOperationRR: */ srcReg2 = ((self_in_dispatchConcretize->operands))[0]; rn13 = ((self_in_dispatchConcretize->operands))[1]; rd13 = rn13; /* begin machineCodeAt:put: */ aWord29 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn13 << 16) | (((int)((usqInt)(rd13) << 12))))) | (srcReg2 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord29; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CmpRR: /* begin concretizeDataOperationRR: */ srcReg3 = ((self_in_dispatchConcretize->operands))[0]; rn14 = ((self_in_dispatchConcretize->operands))[1]; rd14 = 0; /* begin machineCodeAt:put: */ aWord30 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn14 << 16) | (((int)((usqInt)(rd14) << 12))))) | (srcReg3 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord30; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case OrRR: /* begin concretizeDataOperationRR: */ srcReg4 = ((self_in_dispatchConcretize->operands))[0]; rn15 = ((self_in_dispatchConcretize->operands))[1]; rd15 = rn15; /* begin machineCodeAt:put: */ aWord33 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn15 << 16) | (((int)((usqInt)(rd15) << 12))))) | (srcReg4 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord33; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SubRR: /* begin concretizeDataOperationRR: */ srcReg5 = ((self_in_dispatchConcretize->operands))[0]; rn16 = ((self_in_dispatchConcretize->operands))[1]; rd16 = rn16; /* begin machineCodeAt:put: */ aWord34 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn16 << 16) | (((int)((usqInt)(rd16) << 12))))) | (srcReg5 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord34; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case XorRR: /* begin concretizeDataOperationRR: */ srcReg6 = ((self_in_dispatchConcretize->operands))[0]; rn17 = ((self_in_dispatchConcretize->operands))[1]; rd17 = rn17; /* begin machineCodeAt:put: */ aWord35 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn17 << 16) | (((int)((usqInt)(rd17) << 12))))) | (srcReg6 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord35; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AddRdRd: /* begin concretizeAddRdRd */ regRHS = ((self_in_dispatchConcretize->operands))[0]; regLHS = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3996125952U | (regLHS << 16)) | (regLHS << 12)) | regRHS); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CmpRdRd: /* begin concretizeCmpRdRd */ regA = ((self_in_dispatchConcretize->operands))[0]; regB = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = ((4004776768U | (regB << 12)) | regA); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case DivRdRd: /* begin concretizeDivRdRd */ regRHS1 = ((self_in_dispatchConcretize->operands))[0]; regLHS1 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((4001368832U | (regLHS1 << 16)) | (regLHS1 << 12)) | regRHS1); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MulRdRd: /* begin concretizeMulRdRd */ regRHS2 = ((self_in_dispatchConcretize->operands))[0]; regLHS2 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3995077376U | (regLHS2 << 16)) | (regLHS2 << 12)) | regRHS2); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SubRdRd: /* begin concretizeSubRdRd */ regRHS3 = ((self_in_dispatchConcretize->operands))[0]; regLHS3 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3996126016U | (regLHS3 << 16)) | (regLHS3 << 12)) | regRHS3); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SqrtRd: /* begin concretizeSqrtRd */ regLHS4 = ((self_in_dispatchConcretize->operands))[0]; ((self_in_dispatchConcretize->machineCode))[0] = ((4004580288U | (regLHS4 << 12)) | regLHS4); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case NegateR: /* begin concretizeNegateR */ /* RSB destReg, srcReg, #0 */ reg3 = ((self_in_dispatchConcretize->operands))[0]; aWord36 = ((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(RsbOpcode) << 21))) | (0U << 20)))) | ((reg3 << 16) | (reg3 << 12)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord36; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LoadEffectiveAddressMwrR: /* begin concretizeLoadEffectiveAddressMwrR */ offset27 = ((self_in_dispatchConcretize->operands))[0]; srcReg7 = ((self_in_dispatchConcretize->operands))[1]; destReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((offset27 & 0xFF) == offset27) { /* begin machineCodeAt:put: */ aWord37 = addrnimmror(self_in_dispatchConcretize, destReg1, srcReg7, offset27, 0U << 1); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord37; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l204; } for (i4 = 2; i4 <= 30; i4 += 2) { if ((offset27 & (((0xFFU << i4) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i4)))) == offset27) { rot4 = 32 - i4; immediate4 = (((usqInt) offset27) >> i4) | ((offset27 << (32 - i4)) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord37 = addrnimmror(self_in_dispatchConcretize, destReg1, srcReg7, immediate4, ((sqInt)((usqInt)(rot4) << 1))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord37; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l204; } } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord116 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord116; instrOffset12 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord210 = addrnrm(self_in_dispatchConcretize, destReg1, srcReg7, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[16 / 4] = aWord210; (self_in_dispatchConcretize->machineCodeSize) = instrOffset12 + 4; l204: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; (self_in_dispatchConcretize->machineCodeSize); return; case ArithmeticShiftRightCqR: /* begin concretizeArithmeticShiftRightCqR */ distance = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dist -100 srcR */ reg4 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord38 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg4 << 12))) | (((((sqInt)((usqInt)(distance) << 7))) | (64 | reg4)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord38; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftRightCqR: /* begin concretizeLogicalShiftRightCqR */ distance1 = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dist -010 srcR */ reg5 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord39 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg5 << 12))) | (((((sqInt)((usqInt)(distance1) << 7))) | (32 | reg5)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord39; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftLeftCqR: /* begin concretizeLogicalShiftLeftCqR */ distance2 = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dista 000 srcR */ reg6 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord40 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg6 << 12))) | (((((sqInt)((usqInt)(distance2) << 7))) | reg6) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord40; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case ArithmeticShiftRightRR: /* begin concretizeArithmeticShiftRightRR */ distReg = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 destR distR 0101 srcR */ destReg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord41 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg2 << 12))) | (((distReg << 8) | (80 | destReg2)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord41; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftLeftRR: /* begin concretizeLogicalShiftLeftRR */ distReg1 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest dist 0001 srcR */ destReg3 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord42 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg3 << 12))) | (((distReg1 << 8) | (16 | destReg3)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord42; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftRightRR: /* begin concretizeLogicalShiftRightRR */ distReg2 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest dist 0011 srcR */ destReg4 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord43 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg4 << 12))) | (((distReg2 << 8) | (48 | destReg4)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord43; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SMULL: concretizeSMULL(self_in_dispatchConcretize); return; case CMPSMULL: concretizeCMPSMULL(self_in_dispatchConcretize); return; case MSR: concretizeMSR(self_in_dispatchConcretize); return; case PopLDM: concretizePushOrPopMultipleRegisters(self_in_dispatchConcretize, 0); return; case PushSTM: concretizePushOrPopMultipleRegisters(self_in_dispatchConcretize, 1); return; case MoveCqR: /* begin concretizeMoveCqR */ word1 = ((self_in_dispatchConcretize->operands))[0]; reg7 = ((self_in_dispatchConcretize->operands))[1]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((word1 & 0xFF) == word1) { /* begin machineCodeAt:put: */ aWord44 = movimmror(self_in_dispatchConcretize, reg7, word1, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord44; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l224; } for (i12 = 2; i12 <= 30; i12 += 2) { if ((word1 & (((0xFFU << i12) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i12)))) == word1) { rot5 = 32 - i12; immediate5 = (((usqInt) word1) >> i12) | ((((sqInt)((usqInt)(word1) << (32 - i12)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord44 = movimmror(self_in_dispatchConcretize, reg7, immediate5, rot5); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord44; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l224; } } if (word1 < 0) { invVal = -1 - word1; } else { invVal = (unsigned int)~word1; } /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((invVal & 0xFF) == invVal) { /* begin machineCodeAt:put: */ aWord117 = mvnimmror(self_in_dispatchConcretize, reg7, invVal, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord117; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l368; } for (i5 = 2; i5 <= 30; i5 += 2) { if ((invVal & (((0xFFU << i5) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i5)))) == invVal) { rot5 = 32 - i5; immediate5 = (((usqInt) invVal) >> i5) | ((invVal << (32 - i5)) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord117 = mvnimmror(self_in_dispatchConcretize, reg7, immediate5, rot5); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord117; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l368; } } (self_in_dispatchConcretize->machineCodeSize) = loadCwInto(self_in_dispatchConcretize, ((self_in_dispatchConcretize->operands))[1]); goto l226; l368: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l224: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l226: /* end concretizeMoveCqR */; return; case MoveCwR: /* begin concretizeMoveCwR */ (self_in_dispatchConcretize->machineCodeSize) = loadCwInto(self_in_dispatchConcretize, ((self_in_dispatchConcretize->operands))[1]); return; case MoveRR: /* begin concretizeMoveRR */ srcReg8 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest 0000 0000 srcR */ destReg5 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord45 = movrn(self_in_dispatchConcretize, destReg5, srcReg8); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord45; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveAwR: /* begin concretizeMoveAwR */ srcAddr = ((self_in_dispatchConcretize->operands))[0]; destReg6 = ((self_in_dispatchConcretize->operands))[1]; if ((srcAddr != null) && ((srcAddr >= (varBaseAddress())) && ((srcAddr - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord46 = ldrrnplusImm(self_in_dispatchConcretize, destReg6, ConcreteVarBaseReg, srcAddr - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord46; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l233; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord118 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord118; instrOffset13 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord211 = ldrrnplusImm(self_in_dispatchConcretize, destReg6, ConcreteIPReg, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset13 / 4] = aWord211; (self_in_dispatchConcretize->machineCodeSize) = instrOffset13 + 4; l233: /* end concretizeMoveAwR */; return; case MoveRAw: /* begin concretizeMoveRAw */ srcReg9 = ((self_in_dispatchConcretize->operands))[0]; destAddr = ((self_in_dispatchConcretize->operands))[1]; if ((destAddr != null) && ((destAddr >= (varBaseAddress())) && ((destAddr - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord47 = strrnplusImm(self_in_dispatchConcretize, srcReg9, ConcreteVarBaseReg, destAddr - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord47; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l238; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord119 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord119; instrOffset14 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord212 = strrnplusImm(self_in_dispatchConcretize, srcReg9, ConcreteIPReg, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset14 / 4] = aWord212; (self_in_dispatchConcretize->machineCodeSize) = instrOffset14 + 4; l238: /* end concretizeMoveRAw */; return; case MoveAbR: /* begin concretizeMoveAbR */ srcAddr1 = ((self_in_dispatchConcretize->operands))[0]; destReg7 = ((self_in_dispatchConcretize->operands))[1]; if ((srcAddr1 != null) && ((srcAddr1 >= (varBaseAddress())) && ((srcAddr1 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord48 = ldrbrnplusimm(self_in_dispatchConcretize, destReg7, ConcreteVarBaseReg, 1, srcAddr1 - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord48; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l243; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord120 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord120; instrOffset15 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord213 = ldrbrnplusimm(self_in_dispatchConcretize, destReg7, ConcreteIPReg, 1, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset15 / 4] = aWord213; (self_in_dispatchConcretize->machineCodeSize) = instrOffset15 + 4; l243: /* end concretizeMoveAbR */; return; case MoveRAb: /* begin concretizeMoveRAb */ srcReg10 = ((self_in_dispatchConcretize->operands))[0]; destAddr1 = ((self_in_dispatchConcretize->operands))[1]; if ((destAddr1 != null) && ((destAddr1 >= (varBaseAddress())) && ((destAddr1 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord49 = strbrnplusimm(self_in_dispatchConcretize, srcReg10, ConcreteVarBaseReg, 1, destAddr1 - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord49; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l248; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord121 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord121; instrOffset16 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord214 = strbrnplusimm(self_in_dispatchConcretize, srcReg10, ConcreteIPReg, 1, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset16 / 4] = aWord214; (self_in_dispatchConcretize->machineCodeSize) = instrOffset16 + 4; l248: /* end concretizeMoveRAb */; return; case MoveMbrR: /* begin concretizeMoveMbrR */ offset28 = ((self_in_dispatchConcretize->operands))[0]; srcReg11 = ((self_in_dispatchConcretize->operands))[1]; destReg8 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset28)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset28 >= 0) { /* begin machineCodeAt:put: */ aWord50 = ldrbrnplusimm(self_in_dispatchConcretize, destReg8, srcReg11, 1, offset28); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord50; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l255; goto l252; } else { immediate6 = SQABS(offset28); /* begin machineCodeAt:put: */ aWord50 = ldrbrnplusimm(self_in_dispatchConcretize, destReg8, srcReg11, 0, immediate6); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord50; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l255; goto l252; } } else { if ((offset28 != null) && ((offset28 >= (varBaseAddress())) && ((offset28 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord122 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset28 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord122; instrOffset17 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord215 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord215; instrOffset17 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord310 = ldrbrnrm(self_in_dispatchConcretize, destReg8, srcReg11, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset17 / 4] = aWord310; (self_in_dispatchConcretize->machineCodeSize) = instrOffset17 + 4; goto l255; goto l252; } l252: /* end is12BitValue:ifTrue:ifFalse: */; l255: /* end concretizeMoveMbrR */; return; case MoveRMbr: /* begin concretizeMoveRMbr */ srcReg12 = ((self_in_dispatchConcretize->operands))[0]; offset29 = ((self_in_dispatchConcretize->operands))[1]; baseReg = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset29)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset29 >= 0) { /* begin machineCodeAt:put: */ aWord51 = strbrnplusimm(self_in_dispatchConcretize, srcReg12, baseReg, 1, offset29); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord51; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l262; goto l259; } else { immediate7 = SQABS(offset29); /* begin machineCodeAt:put: */ aWord51 = strbrnplusimm(self_in_dispatchConcretize, srcReg12, baseReg, 0, immediate7); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord51; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l262; goto l259; } } else { if ((offset29 != null) && ((offset29 >= (varBaseAddress())) && ((offset29 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord123 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset29 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord123; instrOffset18 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord216 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord216; instrOffset18 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord311 = strbrnrm(self_in_dispatchConcretize, srcReg12, baseReg, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset18 / 4] = aWord311; (self_in_dispatchConcretize->machineCodeSize) = instrOffset18 + 4; goto l262; goto l259; } l259: /* end is12BitValue:ifTrue:ifFalse: */; l262: /* end concretizeMoveRMbr */; return; case MoveRM16r: /* begin concretizeMoveRM16r */ srcReg13 = ((self_in_dispatchConcretize->operands))[0]; offset30 = ((self_in_dispatchConcretize->operands))[1]; baseReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset30)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset30 >= 0) { /* begin machineCodeAt:put: */ aWord52 = strhrnplusimm(self_in_dispatchConcretize, srcReg13, baseReg1, 1, offset30); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord52; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l269; goto l266; } else { immediate8 = SQABS(offset30); /* begin machineCodeAt:put: */ aWord52 = strhrnplusimm(self_in_dispatchConcretize, srcReg13, baseReg1, 0, immediate8); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord52; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l269; goto l266; } } else { if ((offset30 != null) && ((offset30 >= (varBaseAddress())) && ((offset30 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord124 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset30 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord124; instrOffset19 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord217 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord217; instrOffset19 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord312 = strhrnrm(self_in_dispatchConcretize, srcReg13, baseReg1, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset19 / 4] = aWord312; (self_in_dispatchConcretize->machineCodeSize) = instrOffset19 + 4; goto l269; goto l266; } l266: /* end is12BitValue:ifTrue:ifFalse: */; l269: /* end concretizeMoveRM16r */; return; case MoveM16rR: /* begin concretizeMoveM16rR */ offset31 = ((self_in_dispatchConcretize->operands))[0]; srcReg14 = ((self_in_dispatchConcretize->operands))[1]; destReg9 = ((self_in_dispatchConcretize->operands))[2]; /* begin is8BitValue:ifTrue:ifFalse: */ if ((SQABS(offset31)) <= 0xFF) { /* (2 raisedTo: 8)-1 */ if (offset31 >= 0) { /* begin machineCodeAt:put: */ aWord53 = ldrhrnplusimm(self_in_dispatchConcretize, destReg9, srcReg14, 1, offset31); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord53; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l275; } else { immediate9 = SQABS(offset31); /* begin machineCodeAt:put: */ aWord53 = ldrhrnplusimm(self_in_dispatchConcretize, destReg9, srcReg14, 0, immediate9); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord53; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l275; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord125 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord125; instrOffset20 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord218 = ldrhrnrm(self_in_dispatchConcretize, destReg9, srcReg14, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset20 / 4] = aWord218; (self_in_dispatchConcretize->machineCodeSize) = instrOffset20 + 4; goto l275; } l275: /* end concretizeMoveM16rR */; return; case MoveM64rRd: /* begin concretizeMoveM64rRd */ offset = ((self_in_dispatchConcretize->operands))[0]; u = (offset > 0 ? 1 : 0); srcReg = ((self_in_dispatchConcretize->operands))[1]; destReg = ((self_in_dispatchConcretize->operands))[2]; ((self_in_dispatchConcretize->machineCode))[0] = ((((3977251584U | (srcReg << 16)) | (destReg << 12)) | (((int)((usqInt)(u) << 23)))) | (((usqInt) offset) >> 2)); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveMwrR: /* begin concretizeMoveMwrR */ offset32 = ((self_in_dispatchConcretize->operands))[0]; srcReg15 = ((self_in_dispatchConcretize->operands))[1]; destReg10 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset32)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset32 >= 0) { /* begin machineCodeAt:put: */ aWord54 = ldrrnplusimm(self_in_dispatchConcretize, destReg10, srcReg15, 1, offset32); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord54; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l281; goto l276; } else { immediate10 = SQABS(offset32); /* begin machineCodeAt:put: */ aWord54 = ldrrnplusimm(self_in_dispatchConcretize, destReg10, srcReg15, 0, immediate10); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord54; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l281; goto l276; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord126 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord126; instrOffset21 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord219 = ldrrnrm(self_in_dispatchConcretize, destReg10, srcReg15, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset21 / 4] = aWord219; (self_in_dispatchConcretize->machineCodeSize) = instrOffset21 + 4; goto l281; goto l276; } l276: /* end is12BitValue:ifTrue:ifFalse: */; l281: /* end concretizeMoveMwrR */; return; case MoveXbrRR: /* begin concretizeMoveXbrRR */ /* index is number of *bytes* */ index = ((self_in_dispatchConcretize->operands))[0]; base = ((self_in_dispatchConcretize->operands))[1]; /* LDRB dest, [base, +index, LSL #0] */ /* cond 011 1100 1 base dest 00000 00 0 inde */ dest = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord55 = ldrbrnrm(self_in_dispatchConcretize, dest, base, index); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord55; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRXbrR: /* begin concretizeMoveRXbrR */ src = ((self_in_dispatchConcretize->operands))[0]; index1 = ((self_in_dispatchConcretize->operands))[1]; /* str b src, [base, +index, LSL #0] */ /* cond 011 1100 0 base srcR 00000 00 0 index */ base1 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord56 = strbrnrm(self_in_dispatchConcretize, src, base1, index1); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord56; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveXwrRR: /* begin concretizeMoveXwrRR */ index2 = ((self_in_dispatchConcretize->operands))[0]; base2 = ((self_in_dispatchConcretize->operands))[1]; /* LDR dest, [base, +index, LSL #2] */ /* cond 011 1100 1 base dest 00010 00 0 inde bulit by lowest level generator so we can do the lsl #2 on the index register */ dest1 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord57 = memMxrregbasepubwlrmLsl2(self_in_dispatchConcretize, AL, dest1, base2, 1, 1, 0, 0, 1, index2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord57; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRXwrR: /* begin concretizeMoveRXwrR */ src1 = ((self_in_dispatchConcretize->operands))[0]; /* index is number of *words* = 4* bytes */ index3 = ((self_in_dispatchConcretize->operands))[1]; /* str src, [base, +index, LSL #2] */ /* cond 011 1100 0 base srcR 00010 00 0 inde */ base3 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord58 = memMxrregbasepubwlrmLsl2(self_in_dispatchConcretize, AL, src1, base3, 1, 1, 0, 0, 0, index3); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord58; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRMwr: /* begin concretizeMoveRMwr */ srcReg16 = ((self_in_dispatchConcretize->operands))[0]; offset33 = ((self_in_dispatchConcretize->operands))[1]; baseReg2 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset33)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset33 >= 0) { /* begin machineCodeAt:put: */ aWord59 = strrnplusimm(self_in_dispatchConcretize, srcReg16, baseReg2, 1, offset33); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord59; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l295; goto l290; } else { immediate11 = SQABS(offset33); /* begin machineCodeAt:put: */ aWord59 = strrnplusimm(self_in_dispatchConcretize, srcReg16, baseReg2, 0, immediate11); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord59; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l295; goto l290; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord127 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord127; instrOffset22 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord220 = strrnrm(self_in_dispatchConcretize, srcReg16, baseReg2, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset22 / 4] = aWord220; (self_in_dispatchConcretize->machineCodeSize) = instrOffset22 + 4; goto l295; goto l290; } l290: /* end is12BitValue:ifTrue:ifFalse: */; l295: /* end concretizeMoveRMwr */; return; case MoveRdM64r: /* begin concretizeMoveRdM64r */ offset1 = ((self_in_dispatchConcretize->operands))[1]; u1 = (offset1 > 0 ? 1 : 0); dstReg = ((self_in_dispatchConcretize->operands))[2]; fpReg = ((self_in_dispatchConcretize->operands))[0]; ((self_in_dispatchConcretize->machineCode))[0] = ((((3976203008U | (dstReg << 16)) | (fpReg << 12)) | (((int)((usqInt)(u1) << 23)))) | (((usqInt) offset1) >> 2)); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PopR: /* begin concretizePopR */ /* LDR destReg, [SP], #4 */ destReg11 = ((self_in_dispatchConcretize->operands))[0]; aWord60 = popR(self_in_dispatchConcretize, destReg11); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord60; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PushR: /* begin concretizePushR */ /* cond | 010 | 1001 | 0 | -Rn- | -Rd- | 0000 0000 0100 */ /* STR srcReg, [sp, #-4] */ srcReg17 = ((self_in_dispatchConcretize->operands))[0]; aWord61 = pushR(self_in_dispatchConcretize, srcReg17); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord61; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PushCq: /* begin concretizePushCq */ word2 = ((self_in_dispatchConcretize->operands))[0]; /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value2 = word2; while (1) { if ((value2 & 0xFF) == value2) { invert = word2 != value2; /* begin machineCodeAt:put: */ aWord62 = (invert ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, value2, 0) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, value2, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord62; instrOffset23 = 4; goto l303; } for (i6 = 2; i6 <= 30; i6 += 2) { if ((value2 & (((0xFFU << i6) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i6)))) == value2) { rot6 = 32 - i6; immediate12 = (((usqInt) value2) >> i6) | ((value2 << (32 - i6)) & 0xFFFFFFFFU); invert = word2 != value2; /* begin machineCodeAt:put: */ aWord62 = (invert ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate12, rot6) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate12, rot6)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord62; instrOffset23 = 4; goto l303; } } if (!(value2 == word2)) break; value2 = (word2 < 0 ? -1 - word2 : (unsigned int)~word2); } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord128 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord128; instrOffset23 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); l303: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; /* begin machineCodeAt:put: */ aWord221 = pushR(self_in_dispatchConcretize, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset23 / 4] = aWord221; (self_in_dispatchConcretize->machineCodeSize) = instrOffset23 + 4; return; case PushCw: /* begin concretizePushCw */ word3 = ((self_in_dispatchConcretize->operands))[0]; if (((addressIsInInstructions(((AbstractInstruction *) word3))) || ((((AbstractInstruction *) word3)) == (methodLabel()))) || (((((usqInt)word3)) >= ((methodLabel->address))) && ((((usqInt)word3)) < (youngReferrers())))) { instrOffset24 = loadCwInto(self_in_dispatchConcretize, ConcreteIPReg); } else { /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value3 = word3; while (1) { if ((value3 & 0xFF) == value3) { invert1 = word3 != value3; /* begin machineCodeAt:put: */ aWord63 = (invert1 ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, value3, 0) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, value3, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord63; instrOffset24 = 4; goto l308; } for (i7 = 2; i7 <= 30; i7 += 2) { if ((value3 & (((0xFFU << i7) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i7)))) == value3) { rot7 = 32 - i7; immediate13 = (((usqInt) value3) >> i7) | ((value3 << (32 - i7)) & 0xFFFFFFFFU); invert1 = word3 != value3; /* begin machineCodeAt:put: */ aWord63 = (invert1 ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate13, rot7) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate13, rot7)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord63; instrOffset24 = 4; goto l308; } } if (!(value3 == word3)) break; value3 = (word3 < 0 ? -1 - word3 : (unsigned int)~word3); } instrOffset24 = loadCwInto(self_in_dispatchConcretize, ConcreteIPReg); l308: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; } /* begin machineCodeAt:put: */ aWord129 = pushR(self_in_dispatchConcretize, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset24 / 4] = aWord129; (self_in_dispatchConcretize->machineCodeSize) = instrOffset24 + 4; return; case PrefetchAw: /* begin concretizePrefetchAw */ addressOperand = ((self_in_dispatchConcretize->operands))[0]; if ((addressOperand != null) && ((addressOperand >= (varBaseAddress())) && ((addressOperand - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ immediate20 = addressOperand - (varBaseAddress()); aWord64 = ((usqInt) (4115722240U | ((((int)((usqInt)(ConcreteVarBaseReg) << 16))) | ((1U << 23) | immediate20)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord64; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l314; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord130 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord130; instrOffset25 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord222 = 4115722240U | ((((int)((usqInt)(ConcreteIPReg) << 16))) | ((1U << 23) | 0)); ((self_in_dispatchConcretize->machineCode))[instrOffset25 / 4] = aWord222; (self_in_dispatchConcretize->machineCodeSize) = instrOffset25 + 4; l314: /* end concretizePrefetchAw */; return; case ConvertRRd: /* begin concretizeConvertRRd */ srcReg18 = ((self_in_dispatchConcretize->operands))[0]; destReg12 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (fmsrFromto(self_in_dispatchConcretize, srcReg18, 9)); ((self_in_dispatchConcretize->machineCode))[1] = (fsitodFromto(self_in_dispatchConcretize, 9, destReg12)); (self_in_dispatchConcretize->machineCodeSize) = 8; return; default: error("Case not found and no otherwise clause"); } return; } /* FMSR or VMOV instruction to move a value from an ARM reg to an fpu double register ready for conversion FMSR regB, regA - ARM_ARM v5 DDI 01001.pdf pp. C4-68 VMOV regB, regA - ARM_ARM v7 DDi10406 pp. A8-462-3 */ /* the dest reg bits are spread out a little */ /* CogARMCompiler>>#fmsrFrom:to: */ static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB) { sqInt destReg; destReg = (((sqInt)((usqInt)((((usqInt) regB) >> 1)) << 16))) | (((sqInt)((usqInt)((regB & 1)) << 7))); return (3992979984U | (((sqInt)((usqInt)(regA) << 12)))) | destReg; } /* FSITOD or VCVT instruction to move convert an integer value to an fpu double FSITOD regB, regA - ARM_ARM v5 DDI 01001.pdf pp. C4-95 VCVTW. regB, regA - ARM_ARM v7 DDI10406.pdf pp. A8-576-8 */ /* the src reg bits are spread out a little */ /* CogARMCompiler>>#fsitodFrom:to: */ static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB) { sqInt srcReg; srcReg = (((usqInt) regA) >> 1) | (((sqInt)((usqInt)((regA & 1)) << 5))); return (4005039040U | srcReg) | (((sqInt)((usqInt)(regB) << 12))); } /* Answer if CallFull and/or JumpFull are relative and hence need relocating on method compation. If so, they are annotated with IsRelativeCall in methods and relocated in relocateIfCallOrMethodReference:mcpc:delta: */ /* CogARMCompiler>>#fullCallsAreRelative */ static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative) { return 0; } /* Currently no instruction level support for divide on ARM. See also #canDivQuoRem */ /* CogARMCompiler>>#genDivR:R:Quo:Rem: */ static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder) { usqInt divRemFunctionAddr; AbstractInstruction * inst; sqInt rDividend; sqInt rDivisor; sqInt rQuotient; sqInt rRemainder; assert(abstractRegDividend != abstractRegDivisor); assert(abstractRegQuotient != abstractRegRemainder); rDividend = abstractRegDividend; rDivisor = abstractRegDivisor; if (!(rDividend == CArg0Reg)) { /* we need to move the value in rDividend to CArg0Reg. Best to double check if rDivisor is already using it first */ if (rDivisor == CArg0Reg) { /* oh dear; we also need to move rDivisor's value out of the way first.. I'll move it to CArg1Reg and if some nitwit has managed to put rDividend there they deserve the crash */ if (rDividend == CArg1Reg) { error("register choices in genDivR:R:Quo:Rem: made life impossible"); } genoperandoperand(MoveRR, rDivisor, CArg1Reg); rDivisor = CArg1Reg; } genoperandoperand(MoveRR, rDividend, CArg0Reg); } if (!(rDivisor == CArg1Reg)) { genoperandoperand(MoveRR, rDivisor, CArg1Reg); } divRemFunctionAddr = aeabiDivModFunctionAddr(self_in_genDivRRQuoRem); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); CallFullRTregistersToBeSavedMask(((usqInt)divRemFunctionAddr), (1U << CArg2Reg) | (1U << CArg3Reg)); genoperand(PopR, LinkReg); rQuotient = abstractRegQuotient; rRemainder = abstractRegRemainder; if (!(rQuotient == CArg0Reg)) { /* oh good grief, not again */ genoperandoperand(MoveRR, CArg0Reg, rQuotient); if (rQuotient == CArg1Reg) { error("register choices in genDivR:R:Quo:Rem: made life impossible"); } } if (!(rRemainder == CArg1Reg)) { genoperandoperand(MoveRR, CArg1Reg, rRemainder); } return self_in_genDivRRQuoRem; } /* Load the stack pointer register with that of the C stack, effecting a switch to the C stack. Used when machine code calls into the CoInterpreter run-time (e.g. to invoke interpreter primitives). */ /* CogARMCompiler>>#genLoadCStackPointer */ static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer) { sqInt address; /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); return 0; } /* Load the frame and stack pointer registers with those of the C stack, effecting a switch to the C stack. Used when machine code calls into the CoInterpreter run-time (e.g. to invoke interpreter primitives). */ /* CogARMCompiler>>#genLoadCStackPointers */ static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers) { sqInt address; sqInt address1; /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); /* begin MoveAw:R: */ address1 = cFramePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, FPReg)); return 0; } /* Switch back to the Smalltalk stack. Assign SPReg first because typically it is used immediately afterwards. */ /* CogARMCompiler>>#genLoadStackPointers */ static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers) { sqInt address; sqInt address1; /* begin MoveAw:R: */ address = stackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); /* begin MoveAw:R: */ address1 = framePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, FPReg)); return 0; } /* Use SMULL to produce a 64-bit result, explicitly in RISCTempReg,regDest. - ARM_ARM v7 DDI10406 pp. A8-354-5 By comparing RISCTempReg with regDest ASR 31(which effectively makes it 0 or -1) we know that the result being EQ means the hi reg and the top bit of the lo reg are the same - ie no overflow. The condition code can then be forced to oVerflow by use of MSR APSR_nzcvq, #1, lsl 28 */ /* CogARMCompiler>>#genMulR:R: */ static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest) { AbstractInstruction *first; /* result in RISCTempReg,regDest */ first = genoperandoperand(SMULL, regSource, regDest); genoperandoperand(CMPSMULL, RISCTempReg, regDest); genoperand(MSR, 1); return first; } /* 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. */ /* 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 sp -> outerRetpc (send site retpc) linkReg = innerRetpc (PIC abort/miss retpc) to base -> receiver (arg0) (arg1) sp -> outerRetpc (send site retpc) sp -> linkReg/innerRetpc (PIC abort/miss retpc) */ /* CogARMCompiler>>#genPushRegisterArgsForAbortMissNumArgs: */ static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; if (numArgs <= 2 /* numRegArgs */) { assert((numRegArgs()) <= 2); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, SPReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, ReceiverResultReg, 0, SPReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } if (numArgs > 0) { genoperand(PushR, Arg0Reg); if (numArgs > 1) { genoperand(PushR, Arg1Reg); } } genoperand(PushR, TempReg); } genoperand(PushR, LinkReg); return self_in_genPushRegisterArgsForAbortMissNumArgs; } /* Ensure that the register args are pushed before the retpc for arity <= self numRegArgs. */ /* This is easy on a RISC like ARM because the return address is in the link register. 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 NOTA BENE: we do NOT push the return address here, which means it must be dealt with later. */ /* CogARMCompiler>>#genPushRegisterArgsForNumArgs:scratchReg: */ static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored) { if (numArgs <= 2 /* numRegArgs */) { assert((numRegArgs()) <= 2); genoperand(PushR, ReceiverResultReg); if (numArgs > 0) { genoperand(PushR, Arg0Reg); if (numArgs > 1) { genoperand(PushR, Arg1Reg); } } } return self_in_genPushRegisterArgsForNumArgsscratchReg; } /* Save the frame and stack pointer registers to the framePointer and stackPointer variables. Used to save the machine code frame for use by the run-time when calling into the CoInterpreter run-time. */ /* CogARMCompiler>>#genSaveStackPointers */ static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers) { sqInt address; sqInt address1; /* begin MoveR:Aw: */ address = framePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, FPReg, address)); /* begin MoveR:Aw: */ address1 = stackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, SPReg, address1)); return 0; } /* CogARMCompiler>>#genSubstituteReturnAddress: */ static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(retpc, genoperandoperand(MoveCwR, retpc, LR)); } /* Answer the instruction immediately preceding followingAddress. */ /* CogARMCompiler>>#instructionBeforeAddress: */ static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress) { return longAt(followingAddress - 4); } /* is this a BLX <targetReg> instruction? */ /* CogARMCompiler>>#instructionIsBLX: */ static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBLX, instr)) && ((instr & 0xFFFFFF0) == 19922736); } /* is this a BL <offset> instruction? */ /* CogARMCompiler>>#instructionIsBL: */ static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBL, instr)) && ((instr & (15U << 24)) == (11U << 24)); } /* is this a BX <targetReg> instruction? */ /* CogARMCompiler>>#instructionIsBX: */ static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBX, instr)) && ((instr & 0xFFFFFF0) == 19922704); } /* is this a B <offset> instruction? */ /* CogARMCompiler>>#instructionIsB: */ static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsB, instr)) && ((instr & (15U << 24)) == (10U << 24)); } /* is this a CMP instruction? */ /* CogARMCompiler>>#instructionIsCMP: */ static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsCMP, instr)) && (((((usqInt) instr) >> 21) & 0x7F) == CmpOpcode); } /* is this any kind of LDR instruction? c.f. memMxr:reg:base:u:b:l:imm: */ /* CogARMCompiler>>#instructionIsLDR: */ static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsLDR, instr)) && (((((usqInt) instr) >> 20) & 197) == 65); } /* is this an ORR instruction? */ /* CogARMCompiler>>#instructionIsOR: */ static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsOR, instr)) && (((((usqInt) instr) >> 21) & 0x7F) == (16 | OrOpcode)); } /* is this a push -str r??, [sp, #-4] - instruction? */ /* CogARMCompiler>>#instructionIsPush: */ static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsPush, instr)) && ((instr & 268374015) == 86835204); } /* Answer the instruction size at pc.Simple on ARM ;-) */ /* CogARMCompiler>>#instructionSizeAt: */ static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc) { return 4; } /* Several of the opcodes are inverses. Answer the inverse for an opcode if it has one. See Table A3-2 in sec A3.4 Data-processing instructions of the AARM. */ /* CogARMCompiler>>#inverseOpcodeFor: */ static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode) { switch (armOpcode) { case AddOpcode: return SubOpcode; case AndOpcode: return BicOpcode; case BicOpcode: return AndOpcode; case CmpOpcode: return CmpNotOpcode; case MoveOpcode: return MoveNotOpcode; case MoveNotOpcode: return MoveOpcode; case SubOpcode: return AddOpcode; default: error("opcode has no inverse"); return -1; } } /* Assuming mcpc is a send return pc answer if the instruction before it is a call (not a CallFull). */ /* There are two types of calls: BL and/BLX encoding */ /* CogARMCompiler>>#isCallPrecedingReturnPC: */ static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc) { sqInt call; /* begin instructionBeforeAddress: */ call = longAt(mcpc - 4); return (instructionIsBL(self_in_isCallPrecedingReturnPC, call)) || (instructionIsBLX(self_in_isCallPrecedingReturnPC, call)); } /* ARM calls and jumps span +/- 32 mb, more than enough for intra-zone calls and jumps. */ /* CogARMCompiler>>#isInImmediateJumpRange: */ static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand) { return (((((int) operand)) >= -33554432) && ((((int) operand)) <= 0x1FFFFFC)); } /* CogARMCompiler>>#isJumpAt: */ static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc) { int instr; instr = long32At(pc); return (instructionIsB(self_in_isJumpAt, instr)) || (instructionIsBX(self_in_isJumpAt, instr)); } /* add xx, pc, blah or sub xx, pc, blah */ /* CogARMCompiler>>#isPCRelativeValueLoad: */ static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr) { return ((((usqInt) instr) >> 16) == 57999) || ((((usqInt) instr) >> 16) == 57935); } /* Branch/Call ranges. Jump[Cond] can be generated as short as possible. Call/Jump[Cond]Long must be generated in the same number of bytes irrespective of displacement since their targets may be updated, but they need only span 16Mb, the maximum size of the code zone. This allows e.g. ARM to use single-word call and jump instructions for most calls and jumps. CallFull/JumpFull must also be generated in the same number of bytes irrespective of displacement for the same reason, but they must be able to span the full (32-bit or 64-bit) address space because they are used to call code in the C runtime, which may be distant from the code zone */ /* CogARMCompiler>>#jumpLongByteSize */ static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize) { return 4; } /* CogARMCompiler>>#jumpLongConditionalByteSize */ static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize) { /* begin jumpLongByteSize */ return 4; } /* Answer the target address for the long jump immediately preceding mcpc */ /* CogARMCompiler>>#jumpLongTargetBeforeFollowingAddress: */ static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc) { return callTargetFromReturnAddress(self_in_jumpLongTargetBeforeFollowingAddress, mcpc); } /* CogARMCompiler>>#jumpTargetPCAt: */ static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc) { int operand; int word; word = long32At(pc); operand = word & 0xFFFFFF; if (operand & 0x800000) { operand -= 0x1000000; } return ((operand * 4) + pc) + 8; } /* LDRB destReg, [baseReg, 'u' immediate12bitValue] u=0 -> - ARM_ARM v7 DDI10406 pp. A8-128-9 Note that this is a very low level interface that does not check the sign of the immediate, nor validity. See for example #concretizeMoveMbrR */ /* CogARMCompiler>>#ldrb:rn:plus:imm: */ static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrbrnplusimm, AL, destReg, baseReg, u, 1, 1, immediate12bitValue); } /* LDRB destReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-132-3 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldrb:rn:rm: */ static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_ldrbrnrm, AL, destReg, baseReg, 1, 1, 1, 0, 1, offsetReg); } /* LDRH destReg, [baseReg, 'u' immediate8bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-152-3 */ /* CogARMCompiler>>#ldrh:rn:plus:imm: */ static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue) { return memM16xrregbasepuwloffset(self_in_ldrhrnplusimm, AL, destReg, baseReg, 1, u, 0, 1, immediate8bitValue); } /* LDRH destReg, [baseReg, +offsetReg] - ARM_ARM v7 DDI10406 pp. A8-156-7 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldrh:rn:rm: */ static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memM16xrregbasepuwlrm(self_in_ldrhrnrm, AL, destReg, baseReg, 1, 1, 0, 1, offsetReg); } /* LDR destReg, [baseReg, +immediate12bitValue] - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#ldr:rn:plusImm: */ static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrrnplusImm, AL, destReg, baseReg, 1, 0, 1, immediate12bitValue); } /* LDR destReg, [baseReg, immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#ldr:rn:plus:imm: */ static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrrnplusimm, AL, destReg, baseReg, u, 0, 1, immediate12bitValue); } /* LDR destReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-124-5 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldr:rn:rm: */ static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_ldrrnrm, AL, destReg, baseReg, 1, 1, 0, 0, 1, offsetReg); } /* Load the operand into the destination register, answering the size of the instructions generated to do so. */ /* CogARMCompiler>>#loadCwInto: */ static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg) { sqInt aWord; sqInt aWord1; sqInt distance; sqInt i; sqInt immediate; sqInt negate; usqInt operand; sqInt rot; sqInt value; operand = ((self_in_loadCwInto->operands))[0]; if ((addressIsInInstructions(((AbstractInstruction *) operand))) || ((((AbstractInstruction *) operand)) == (methodLabel()))) { operand = ((((AbstractInstruction *) operand))->address); } if (((((usqInt)operand)) >= ((methodLabel->address))) && ((((usqInt)operand)) < (youngReferrers()))) { distance = operand - (((self_in_loadCwInto->address)) + 8); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value = distance; while (1) { if ((value & 0xFF) == value) { negate = distance != value; /* begin machineCodeAt:put: */ aWord = (negate ? subrnimmror(self_in_loadCwInto, destReg, PC, value, 0) : addrnimmror(self_in_loadCwInto, destReg, PC, value, 0)); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord; return 4; goto l2; } for (i = 2; i <= 30; i += 2) { if ((value & (((0xFFU << i) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i)))) == value) { rot = 32 - i; immediate = (((usqInt) value) >> i) | ((((sqInt)((usqInt)(value) << (32 - i)))) & 0xFFFFFFFFU); negate = distance != value; /* begin machineCodeAt:put: */ aWord = (negate ? subrnimmror(self_in_loadCwInto, destReg, PC, immediate, rot) : addrnimmror(self_in_loadCwInto, destReg, PC, immediate, rot)); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord; return 4; goto l2; } } if (!((value == distance) && (distance != 0))) break; value = -distance; } assert(!((isAnInstruction(self_in_loadCwInto, ((AbstractInstruction *) (((self_in_loadCwInto->operands))[0])))))); l2: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_loadCwInto->dependent))->address))); assert((SQABS((((((self_in_loadCwInto->dependent))->address)) - (((self_in_loadCwInto->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord1 = ldrrnplusimm(self_in_loadCwInto, destReg, PC, (((((self_in_loadCwInto->dependent))->address)) >= (((self_in_loadCwInto->address)) + 8) ? 1 : 0), SQABS((((((self_in_loadCwInto->dependent))->address)) - (((self_in_loadCwInto->address)) + 8)))); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord1; return ((self_in_loadCwInto->machineCodeSize) = 4); } /* Answer the byte size of a MoveCwR opcode's corresponding machine code when the argument is a PIC. This is for the self-reference at the end of a closed PIC. On ARM this is a single instruction pc-relative register load. */ /* CogARMCompiler>>#loadPICLiteralByteSize */ static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize) { return 4; } /* Answer the maximum number of bytes of machine code generated for any abstract instruction. e.g. CmpCwR => mov R3, #<addressByte1>, 12 orr R3, R3, #<addressByte2>, 8 orr R3, R3, #<addressByte3>, 4 orr R3, R3, #<addressByte4>, 0 cmp R?, R3 */ /* CogARMCompiler>>#machineCodeBytes */ static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes) { return 20; } /* Answer the maximum number of words of machine code generated for any abstract instruction. e.g. CmpCwR => mov R3, #<addressByte1>, 12 orr R3, R3, #<addressByte2>, 8 orr R3, R3, #<addressByte3>, 4 orr R3, R3, #<addressByte4>, 0 cmp R?, R3 */ /* CogARMCompiler>>#machineCodeWords */ static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords) { return 5; } /* build an ARM [base +/- offset8] half-word memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memM16xr:reg:base:p:u:w:l:offset: */ static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8) { return (((sqInt)((usqInt)(cond) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((1U << 22) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | ((((sqInt)((usqInt)((offset8 & 240)) << 4))) | ((11U << 4) | (offset8 & 15))))))))))); } /* build an ARM [base +/- offsetReg] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memM16xr:reg:base:p:u:w:l:rm: */ static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)(cond) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((0U << 22) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | (176 | offsetReg))))))))); } /* build an ARM [base +/- offset] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:imm: */ static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset) { return (((sqInt)((usqInt)(cond) << 28))) | ((2U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((((sqInt)((usqInt)(byteword) << 22))) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | offset)))))))); } /* build an ARM [base +/- offsetReg lsl #2] memory instruction - see also #memMxr:reg:base:p:u:b:w:l:rm: and keep them correlated properly p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:rmLsl2: */ static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((3U << 25) | ((((sqInt)((usqInt)((postpreoffset & 1)) << 24))) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((weirdstuff & 1)) << 21))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (256 | (offsetReg & 15)))))))))); } /* build an ARM [base +/- offsetReg] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:rm: */ static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((3U << 25) | ((((sqInt)((usqInt)((postpreoffset & 1)) << 24))) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((weirdstuff & 1)) << 21))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (offsetReg & 15))))))))); } /* This is the lowest level build of an ARM [base +/- immediate 12bit offset] memory instruction u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:u:b:l:imm: */ static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((5U << 24) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (immediate12bitValue & 0xFFF))))))); } /* MOVS destReg, srcReg - ARM_ARM v7 DDI10406 pp. A8-196-7 */ /* CogARMCompiler>>#movs:rn: */ static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (srcReg & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. MOV destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-194-5 */ /* CogARMCompiler>>#mov:imm:ror: */ static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* MOV destReg, srcReg - ARM_ARM v7 DDI10406 pp. A8-196-7 */ /* CogARMCompiler>>#mov:rn: */ static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (srcReg & 0xFFF); } /* Generate an MSR CPSR_f, #flags instruction. Note that a) CPSR_f is equivalent to APSR_nzcvq (ARM ARM DDI0406A p A8-209 & A2-14) b) We only have business with the NZCV flags so the generated instruction shifts the flags value <<28 - which is a ROR 4 */ /* CogARMCompiler>>#msr: */ static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags) { return (321449984 + (2U << 8)) + (flags & 15); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. MVN destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-214-5 */ /* CogARMCompiler>>#mvn:imm:ror: */ static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(MoveNotOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* CogARMCompiler>>#numIntRegArgs */ static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs) { return 4; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. ORR destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-228-9 */ /* CogARMCompiler>>#orr:imm:ror: */ static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(destReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* CogARMCompiler>>#padIfPossibleWithStopsFrom:to: */ static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr) { sqInt nullBytes; sqInt p; nullBytes = ((endAddr - startAddr) + 1) % 4; stopsFromto(self_in_padIfPossibleWithStopsFromto, startAddr, endAddr - nullBytes); for (p = ((endAddr - nullBytes) + 1); p <= endAddr; p += 1) { byteAtput(p, 0xFF); } return self_in_padIfPossibleWithStopsFromto; } /* pop word off TOS LDR srcReg, [sp] #4 - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#popR: */ static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg) { return memMxrregbasepubwlimm(self_in_popR, AL, dstReg, SP, 0, 1, 0, 0, 1, 4); } /* CogARMCompiler>>#pushLinkRegisterByteSize */ static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize) { return 4; } /* push word to TOS STR srcReg, [sp, #-4]! - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#pushR: */ static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg) { return memMxrregbasepubwlimm(self_in_pushR, AL, srcReg, SP, 1, 0, 0, 1, 0, 4); } /* CogARMCompiler>>#relocateCallBeforeReturnPC:by: */ static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta) { sqInt distanceDiv4; sqInt instr; assert((delta % 4) == 0); if (delta != 0) { /* begin instructionBeforeAddress: */ instr = longAt(retpc - 4); assert((instructionIsB(self_in_relocateCallBeforeReturnPCby, instr)) || (instructionIsBL(self_in_relocateCallBeforeReturnPCby, instr))); distanceDiv4 = instr & 0xFFFFFF; distanceDiv4 += delta / 4; longAtput(retpc - 4, (instr & 0xFF000000U) | (distanceDiv4 & 0xFFFFFF)); } return self_in_relocateCallBeforeReturnPCby; } /* Rewrite a call instruction to call a different target. This variant is used to link PICs in ceSendMiss et al,. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteCallAt:target: */ static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { return rewriteTransferAttarget(self_in_rewriteCallAttarget, callSiteReturnAddress, callTargetAddress); } /* Rewrite a callFull instruction to jump to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'blx ip' instruction for the actual call. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteCallFullAt:target: */ static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteFullTransferAttargetexpectedInstruction(self_in_rewriteCallFullAttarget, callSiteReturnAddress, callTargetAddress, 3778019132U); } /* Rewrite a full jump instruction to jump to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'bx ip' instruction for the actual jump. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteJumpFullAt:target: */ static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteFullTransferAttargetexpectedInstruction(self_in_rewriteJumpFullAttarget, callSiteReturnAddress, callTargetAddress, 3778019100U); } /* Rewrite a jump instruction to call a different target. This variant is used to reset the jumps in the prototype CPIC to suit each use,. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteJumpLongAt:target: */ static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { return rewriteTransferAttarget(self_in_rewriteJumpLongAttarget, callSiteReturnAddress, callTargetAddress); } /* Rewrite a call/jump instruction to call a different target. This variant is used to link PICs in ceSendMiss et al, and to rewrite call/jumps in CPICs. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* for debug - [cogit disassembleFrom: callSiteReturnAddress - 10 to: callSiteReturnAddress - 1]. */ /* CogARMCompiler>>#rewriteTransferAt:target: */ static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { usqInt callDistance; sqInt instr; if (!(callTargetAddress >= (minCallAddress()))) { error("linking callsite to invalid address"); } /* pc offset */ /* return offset */ callDistance = ((usqInt) (callTargetAddress - ((callSiteReturnAddress + 8) - 4))); assert(isInImmediateJumpRange(self_in_rewriteTransferAttarget, callDistance)); /* begin instructionBeforeAddress: */ instr = longAt(callSiteReturnAddress - 4); assert((instructionIsB(self_in_rewriteTransferAttarget, instr)) || (instructionIsBL(self_in_rewriteTransferAttarget, instr))); longAtput(callSiteReturnAddress - 4, (instr & 0xFF000000U) | ((callDistance / 4) & 0xFFFFFF)); assert((callTargetFromReturnAddress(self_in_rewriteTransferAttarget, callSiteReturnAddress)) == callTargetAddress); return 4; } /* to save Slang from having to be a real compiler (it can't inline switches that return) */ /* Answer if the receiver's opcode sets the condition codes correctly for the given conditional jump opcode. ARM has to check carefully since the V flag is not affected by non-comparison instructions */ /* CogARMCompiler>>#setsConditionCodesFor: */ static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode) { switch ((self_in_setsConditionCodesFor->opcode)) { case ArithmeticShiftRightCqR: case ArithmeticShiftRightRR: case LogicalShiftLeftCqR: case LogicalShiftLeftRR: return shiftSetsConditionCodesFor(self_in_setsConditionCodesFor, aConditionalJumpOpcode); case XorRR: return 1; default: haltmsg("unhandled opcode in setsConditionCodesFor:"); return 0; } } /* check what flags the opcdoe needs setting - ARM doesn't set V when simply MOVing */ /* CogARMCompiler>>#shiftSetsConditionCodesFor: */ static sqInt NoDbgRegParms shiftSetsConditionCodesFor(AbstractInstruction * self_in_shiftSetsConditionCodesFor, sqInt aConditionalJumpOpcode) { switch (aConditionalJumpOpcode) { case JumpNegative: case JumpZero: case JumpLess: return 1; default: haltmsg("unhandled opcode in setsConditionCodesFor:"); return 0; } } /* Return a minimum amount of headroom for each stack page (in bytes). In a JIT the stack has to have room for interrupt handlers which will run on the stack. According to ARM architecture v5 reference manual chapter A2.6, the basic interrupt procedure does not push anything onto the stack. It uses SPSR_err and R14_err to preserve state. Afterwards, it calls an interrupt procedure. So leave some room. */ /* CogARMCompiler>>#stackPageInterruptHeadroomBytes */ static sqInt NoDbgRegParms stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes) { return 128; } /* CogARMCompiler>>#stopsFrom:to: */ static AbstractInstruction * NoDbgRegParms stopsFromto(AbstractInstruction * self_in_stopsFromto, sqInt startAddr, sqInt endAddr) { sqInt addr; assert((((endAddr - startAddr) + 1) % 4) == 0); for (addr = startAddr; addr <= endAddr; addr += 4) { longAtput(addr, (((int)((usqInt)(AL) << 28))) | ((66U << 20) | (7U << 4))); } return self_in_stopsFromto; } /* STRB destReg, [baseReg, 'u' immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-388-9 */ /* CogARMCompiler>>#strb:rn:plus:imm: */ static sqInt NoDbgRegParms strbrnplusimm(AbstractInstruction * self_in_strbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strbrnplusimm, AL, destReg, baseReg, u, 1, 0, immediate12bitValue); } /* STRB srcReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-390-1 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#strb:rn:rm: */ static sqInt NoDbgRegParms strbrnrm(AbstractInstruction * self_in_strbrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_strbrnrm, AL, srcReg, baseReg, 1, 1, 1, 0, 0, offsetReg); } /* STRH destReg, [baseReg, 'u' immediate8bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-408-9 */ /* CogARMCompiler>>#strh:rn:plus:imm: */ static sqInt NoDbgRegParms strhrnplusimm(AbstractInstruction * self_in_strhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue) { return memM16xrregbasepuwloffset(self_in_strhrnplusimm, AL, destReg, baseReg, 1, u, 0, 0, immediate8bitValue); } /* STRH srcReg, [baseReg, +offsetReg] - ARM_ARM v7 DDI10406 pp. A8-410-1 */ /* CogARMCompiler>>#strh:rn:rm: */ static sqInt NoDbgRegParms strhrnrm(AbstractInstruction * self_in_strhrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memM16xrregbasepuwlrm(self_in_strhrnrm, AL, srcReg, baseReg, 1, 1, 0, 0, offsetReg); } /* STR srcReg, [baseReg, +immediate12bitValue] - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#str:rn:plusImm: */ static sqInt NoDbgRegParms strrnplusImm(AbstractInstruction * self_in_strrnplusImm, sqInt srcReg, sqInt baseReg, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strrnplusImm, AL, srcReg, baseReg, 1, 0, 0, immediate12bitValue); } /* STR destReg, [baseReg, 'u' immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#str:rn:plus:imm: */ static sqInt NoDbgRegParms strrnplusimm(AbstractInstruction * self_in_strrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strrnplusimm, AL, destReg, baseReg, u, 0, 0, immediate12bitValue); } /* STR srcReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-384-5 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#str:rn:rm: */ static sqInt NoDbgRegParms strrnrm(AbstractInstruction * self_in_strrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_strrnrm, AL, srcReg, baseReg, 1, 1, 0, 0, 0, offsetReg); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc SUBS destReg, srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-418-9 */ /* CogARMCompiler>>#subs:rn:imm:ror: */ static sqInt NoDbgRegParms subsrnimmror(AbstractInstruction * self_in_subsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc SUB destReg, srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-418-9 */ /* CogARMCompiler>>#sub:rn:imm:ror: */ static sqInt NoDbgRegParms subrnimmror(AbstractInstruction * self_in_subrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc */ /* also note that TST has no destReg TST srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-452-3 */ /* CogARMCompiler>>#tst:rn:imm:ror: */ static sqInt NoDbgRegParms tstrnimmror(AbstractInstruction * self_in_tstrnimmror, sqInt ignored, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(TstOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (0U << 12))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Answer if Call and JumpLong are relative and hence need to take the caller's relocation delta into account during code compaction, rather than just the callee's delta. */ /* CogARMCompiler>>#zoneCallsAreRelative */ static sqInt NoDbgRegParms zoneCallsAreRelative(AbstractInstruction * self_in_zoneCallsAreRelative) { return 1; } /* CogBlockMethod>>#cmHomeMethod */ static CogMethod * NoDbgRegParms cmHomeMethod(CogBlockMethod * self_in_cmHomeMethod) { return ((self_in_cmHomeMethod->cpicHasMNUCaseOrCMIsFullBlock) ? ((CogMethod *) self_in_cmHomeMethod) : ((CogMethod *) ((((usqInt)self_in_cmHomeMethod)) - ((self_in_cmHomeMethod->homeOffset))))); } /* CogBytecodeDescriptor>>#isBranch */ static sqInt NoDbgRegParms isBranch(BytecodeDescriptor * self_in_isBranch) { return (((self_in_isBranch->spanFunction)) != null) && (!((self_in_isBranch->isBlockCreation))); } /* Cogit>>#AddCq:R: */ static AbstractInstruction * NoDbgRegParms gAddCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* Cogit>>#AndCq:R: */ static AbstractInstruction * NoDbgRegParms gAndCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* Cogit>>#AndCq:R:R: */ static AbstractInstruction * NoDbgRegParms gAndCqRR(sqInt quickConstant, sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *first; /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(AndCqRR, quickConstant, srcReg, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } return anInstruction2; if (srcReg == destReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } first = genoperandoperand(MoveRR, srcReg, destReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return first; } /* Cogit>>#abortOffset */ sqInt abortOffset(void) { return missOffset; } /* Cogit>>#addCleanBlockStarts */ static void addCleanBlockStarts(void) { sqInt i; sqInt iLimiT; sqInt lit; sqInt startPCOrNil; for (i = 1, iLimiT = (literalCountOf(methodObj)); i <= iLimiT; i += 1) { lit = fetchPointerofObject(i, methodObj); startPCOrNil = startPCOrNilOfLiteralin(lit, methodObj); if (!(startPCOrNil == null)) { maxLitIndex = ((maxLitIndex < i) ? i : maxLitIndex); addBlockStartAtnumArgsnumCopiedspan(startPCOrNil - 1, argumentCountOfClosure(lit), copiedValueCountOfClosure(lit), spanForCleanBlockStartingAt(startPCOrNil - 1)); } } } /* Perform an integrity/leak check using the heapMap. Set a bit at each cog method's header. */ /* Cogit>>#addCogMethodsToHeapMap */ void addCogMethodsToHeapMap(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { heapMapAtWordPut(cogMethod, 1); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* Cogit>>#addressIsInCurrentCompilation: */ static sqInt NoDbgRegParms addressIsInCurrentCompilation(sqInt address) { return ((((usqInt)address)) >= ((methodLabel->address))) && ((((usqInt)address)) < (youngReferrers())); } /* Cogit>>#addressIsInFixups: */ static sqInt NoDbgRegParms addressIsInFixups(BytecodeFixup *address) { return (BytecodeFixup *)address >= fixups && (BytecodeFixup *)address < (fixups + numAbstractOpcodes); } /* Cogit>>#addressIsInInstructions: */ static sqInt NoDbgRegParms addressIsInInstructions(AbstractInstruction *address) { return !((usqInt)(address) & BytesPerWord-1) \ && (address) >= &abstractOpcodes[0] \ && (address) < &abstractOpcodes[opcodeIndex]; } /* calculate the end of the n'th case statement - which is complicated because we have case 1 right at the top of our CPIC and then build up from the last one. Yes I know this sounds strange, but trust me - I'm an Engineer, we do things backwards all the emit */ /* Cogit>>#addressOfEndOfCase:inCPIC: */ static sqInt NoDbgRegParms addressOfEndOfCaseinCPIC(sqInt n, CogMethod *cPIC) { assert((n >= 1) && (n <= MaxCPICCases)); return (n == 1 ? (((sqInt)cPIC)) + firstCPICCaseOffset : ((((sqInt)cPIC)) + firstCPICCaseOffset) + (((MaxCPICCases + 1) - n) * cPICCaseSize)); } /* Cogit>>#alignUptoRoutineBoundary: */ static sqInt NoDbgRegParms alignUptoRoutineBoundary(sqInt anAddress) { return (((anAddress + 7) | 7) - 7); } /* Check that all methods have valid selectors, and that all linked sends are to valid targets and have valid cache tags */ /* Cogit>>#allMachineCodeObjectReferencesValid */ static sqInt allMachineCodeObjectReferencesValid(void) { CogMethod *cogMethod; sqInt ok; ok = 1; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if (!(asserta(checkValidOopReference((cogMethod->selector))))) { ok = 0; } if (!(asserta((cogMethodDoesntLookKosher(cogMethod)) == 0))) { ok = 0; } } if ((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)) { if (!(asserta((mapForperformUntilarg(cogMethod, checkIfValidOopRefAndTargetpccogMethod, ((sqInt)cogMethod))) == 0))) { ok = 0; } } if (((cogMethod->cmType)) == CMClosedPIC) { if (!(asserta(noTargetsFreeInClosedPIC(cogMethod)))) { ok = 0; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return ok; } /* Cogit>>#allMethodsHaveCorrectHeader */ static sqInt allMethodsHaveCorrectHeader(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { if (!(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod()))) { return 0; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return 1; } /* Cogit>>#annotateAbsolutePCRef: */ static AbstractInstruction * NoDbgRegParms annotateAbsolutePCRef(AbstractInstruction *abstractInstruction) { (abstractInstruction->annotation = IsAbsPCReference); return abstractInstruction; } /* Cogit>>#annotateBytecode: */ static AbstractInstruction * NoDbgRegParms annotateBytecode(AbstractInstruction *abstractInstruction) { (abstractInstruction->annotation = HasBytecodePC); return abstractInstruction; } /* Cogit>>#annotate:objRef: */ static AbstractInstruction * NoDbgRegParms annotateobjRef(AbstractInstruction *abstractInstruction, sqInt anOop) { if (shouldAnnotateObjectReference(anOop)) { if (isYoungObject(anOop)) { hasYoungReferent = 1; } (abstractInstruction->annotation = IsObjectReference); } return abstractInstruction; } /* Cogit>>#assertSaneJumpTarget: */ static void NoDbgRegParms assertSaneJumpTarget(AbstractInstruction *jumpTarget) { assert((closedPICSize == null) || ((openPICSize == null) || ((addressIsInInstructions(jumpTarget)) || ((((((usqInt)jumpTarget)) >= codeBase) && ((((usqInt)jumpTarget)) <= ((((sqInt)(limitZony()))) + (((closedPICSize < openPICSize) ? openPICSize : closedPICSize))))))))); } /* Evaluate binaryFunction with the block start mcpc and supplied arg for each entry in the block dispatch. If the function answers non-zero answer the value it answered. Used to update back-references to the home method in compaction. */ /* Cogit>>#blockDispatchTargetsFor:perform:arg: */ static sqInt NoDbgRegParms blockDispatchTargetsForperformarg(CogMethod *cogMethod, usqInt (*binaryFunction)(sqInt mcpc, sqInt arg), sqInt arg) { sqInt blockEntry; sqInt end; sqInt pc; sqInt result; usqInt targetpc; if (((cogMethod->blockEntryOffset)) == 0) { return null; } blockEntry = ((cogMethod->blockEntryOffset)) + (((sqInt)cogMethod)); pc = blockEntry; end = (mapEndFor(cogMethod)) - 1; while (pc < end) { if (isJumpAt(backEnd, pc)) { targetpc = jumpTargetPCAt(backEnd, pc); if (targetpc < blockEntry) { result = binaryFunction(targetpc, arg); if (result != 0) { return result; } } } pc += 4 /* instructionSizeAt: */; } return 0; } /* Answer the zero-relative bytecode pc matching the machine code pc argument in cogMethod, given the start of the bytecodes for cogMethod's block or method object. */ /* Cogit>>#bytecodePCFor:startBcpc:in: */ sqInt bytecodePCForstartBcpcin(sqInt mcpc, sqInt startbcpc, CogBlockMethod *cogMethod) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc1; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt targetPC; latestContinuation = 0; /* begin mapFor:bcpc:performUntil:arg: */ assert(((cogMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc1 = (((usqInt)cogMethod)) + ((cogMethod->stackCheckOffset)); result = findIsBackwardBranchMcpcBcpcMatchingMcpc(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc1)), startbcpc, (((void *)mcpc))); if (result != 0) { return result; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogMethod->startpc))); homeMethod = cmHomeMethod(cogMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc1 += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { return 0; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { return 0; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = findIsBackwardBranchMcpcBcpcMatchingMcpc(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc1)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)mcpc))); if (result != 0) { return result; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc1 += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* Cogit>>#CallFullRT:registersToBeSavedMask: */ static AbstractInstruction * NoDbgRegParms CallFullRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved) { sqInt callerSavedRegsToBeSaved; AbstractInstruction *lastInst; callerSavedRegsToBeSaved = CallerSavedRegisterMask & registersToBeSaved; /* begin genPushRegisterMask: */ if (callerSavedRegsToBeSaved == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, callerSavedRegsToBeSaved); } /* begin gen:literal: */ lastInst = checkLiteralforInstruction(callTarget, genoperand(CallFull, callTarget)); /* begin genPopRegisterMask: */ return (callerSavedRegsToBeSaved == 0 ? genoperandoperand(Label, (labelCounter += 1), bytecodePC) : genoperand(PopLDM, callerSavedRegsToBeSaved)); } /* Cogit>>#CallRT:registersToBeSavedMask: */ static AbstractInstruction * NoDbgRegParms CallRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved) { AbstractInstruction *abstractInstruction; sqInt callerSavedRegsToBeSaved; AbstractInstruction *lastInst; callerSavedRegsToBeSaved = CallerSavedRegisterMask & registersToBeSaved; /* begin genPushRegisterMask: */ if (callerSavedRegsToBeSaved == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, callerSavedRegsToBeSaved); } /* begin CallRT: */ abstractInstruction = genoperand(Call, callTarget); (abstractInstruction->annotation = IsRelativeCall); lastInst = abstractInstruction; /* begin genPopRegisterMask: */ return (callerSavedRegsToBeSaved == 0 ? genoperandoperand(Label, (labelCounter += 1), bytecodePC) : genoperand(PopLDM, callerSavedRegsToBeSaved)); } /* Cogit>>#Call: */ static AbstractInstruction * NoDbgRegParms gCall(sqInt callTarget) { return genoperand(Call, callTarget); } /* Cogit>>#CmpCq:R: */ static AbstractInstruction * NoDbgRegParms gCmpCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* This is a static version of ceCallCogCodePopReceiverReg for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#callCogCodePopReceiver */ void callCogCodePopReceiver(void) { realCECallCogCodePopReceiverReg(); error("what??"); } /* This is a static version of ceCallCogCodePopReceiverAndClassRegs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#callCogCodePopReceiverAndClassRegs */ void callCogCodePopReceiverAndClassRegs(void) { realCECallCogCodePopReceiverAndClassRegs(); } /* Code entry closed PIC miss. A send has fallen through a closed (finite) polymorphic inline cache. Either extend it or patch the send site to an open PIC. The stack looks like: receiver args sp=> sender return address */ /* Cogit>>#ceCPICMiss:receiver: */ sqInt ceCPICMissreceiver(CogMethod *cPIC, sqInt receiver) { sqInt cacheTag; sqInt errorSelectorOrNil; sqInt methodOrSelectorIndex; sqInt newTargetMethodOrNil; sqInt outerReturn; sqInt result; sqInt selector; if (isOopForwarded(receiver)) { return ceSendFromInLineCacheMiss(cPIC); } outerReturn = stackTop(); assert(!(((inlineCacheTagAt(backEnd, outerReturn)) == (picAbortDiscriminatorValue())))); if (((cPIC->cPICNumCases)) < MaxCPICCases) { /* begin lookup:for:methodAndErrorSelectorInto: */ selector = (cPIC->selector); methodOrSelectorIndex = lookupOrdinaryreceiver(selector, receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { if (!(isOopCompiledMethod(methodOrSelectorIndex))) { newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorCannotInterpret; goto l1; } if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, selector); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = null; goto l1; } if (methodOrSelectorIndex == SelectorDoesNotUnderstand) { methodOrSelectorIndex = lookupMNUreceiver(splObj(SelectorDoesNotUnderstand), receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { assert(isOopCompiledMethod(methodOrSelectorIndex)); if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, splObj(SelectorDoesNotUnderstand)); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = methodOrSelectorIndex; l1: /* end lookup:for:methodAndErrorSelectorInto: */; } else { newTargetMethodOrNil = (errorSelectorOrNil = null); } assert(outerReturn == (stackTop())); cacheTag = inlineCacheTagForInstance(receiver); if ((((cPIC->cPICNumCases)) >= MaxCPICCases) || (((errorSelectorOrNil != null) && (errorSelectorOrNil != SelectorDoesNotUnderstand)) || ((newTargetMethodOrNil == null) || (isYoung(newTargetMethodOrNil))))) { result = patchToOpenPICFornumArgsreceiver((cPIC->selector), (cPIC->cmNumArgs), receiver); assert(!result); return ceSendFromInLineCacheMiss(cPIC); } cogExtendPICCaseNMethodtagisMNUCase(cPIC, newTargetMethodOrNil, cacheTag, errorSelectorOrNil == SelectorDoesNotUnderstand); executeCogPICfromLinkedSendWithReceiverandCacheTag(cPIC, receiver, longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))); return null; } /* Cogit>>#ceFree: */ void ceFree(void *pointer) { free(pointer); } /* Cogit>>#ceMalloc: */ void* ceMalloc(size_t size) { return malloc(size); } /* An in-line cache check in a method has failed. The failing entry check has jumped to the ceMethodAbort abort call at the start of the method which has called this routine. If possible allocate a closed PIC for the current and existing classes. The stack looks like: receiver args sender return address sp=> ceMethodAbort call return address So we can find the method that did the failing entry check at ceMethodAbort call return address - missOffset and we can find the send site from the outer return address. */ /* Cogit>>#ceSICMiss: */ sqInt ceSICMiss(sqInt receiver) { sqInt cacheTag; sqInt entryPoint; sqInt errorSelectorOrNil; sqInt extent; usqInt innerReturn; sqInt methodOrSelectorIndex; sqInt newTargetMethodOrNil; usqInt outerReturn; CogMethod *pic; sqInt result; sqInt selector; CogMethod *targetMethod; /* Whether we can relink to a PIC or not we need to pop off the inner return and identify the target method. */ innerReturn = ((usqInt)(popStack())); targetMethod = ((CogMethod *) (innerReturn - missOffset)); if (isOopForwarded(receiver)) { return ceSendFromInLineCacheMiss(targetMethod); } outerReturn = ((usqInt)(stackTop())); assert(((outerReturn >= methodZoneBase) && (outerReturn <= (freeStart())))); entryPoint = callTargetFromReturnAddress(backEnd, outerReturn); assert(((targetMethod->selector)) != (nilObject())); assert(((((sqInt)targetMethod)) + cmEntryOffset) == entryPoint); /* begin lookup:for:methodAndErrorSelectorInto: */ selector = (targetMethod->selector); methodOrSelectorIndex = lookupOrdinaryreceiver(selector, receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { if (!(isOopCompiledMethod(methodOrSelectorIndex))) { newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorCannotInterpret; goto l1; } if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, selector); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = null; goto l1; } if (methodOrSelectorIndex == SelectorDoesNotUnderstand) { methodOrSelectorIndex = lookupMNUreceiver(splObj(SelectorDoesNotUnderstand), receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { assert(isOopCompiledMethod(methodOrSelectorIndex)); if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, splObj(SelectorDoesNotUnderstand)); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = methodOrSelectorIndex; l1: /* end lookup:for:methodAndErrorSelectorInto: */; assert(outerReturn == (stackTop())); cacheTag = inlineCacheTagForInstance(receiver); if (((errorSelectorOrNil != null) && (errorSelectorOrNil != SelectorDoesNotUnderstand)) || (((longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))) == 0 /* picAbortDiscriminatorValue */) || ((newTargetMethodOrNil == null) || (isYoung(newTargetMethodOrNil))))) { result = patchToOpenPICFornumArgsreceiver((targetMethod->selector), (targetMethod->cmNumArgs), receiver); assert(!result); return ceSendFromInLineCacheMiss(targetMethod); } pic = openPICWithSelector((targetMethod->selector)); if ((pic == null) || (!1)) { /* otherwise attempt to create a closed PIC for the two cases. */ pic = cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase((targetMethod->selector), (targetMethod->cmNumArgs), targetMethod, newTargetMethodOrNil, cacheTag, errorSelectorOrNil == SelectorDoesNotUnderstand); if ((((((sqInt)pic)) >= MaxNegativeErrorCode) && ((((sqInt)pic)) <= -1))) { /* For some reason the PIC couldn't be generated, most likely a lack of code memory. Continue as if this is an unlinked send. */ if ((((sqInt)pic)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return ceSendFromInLineCacheMiss(targetMethod); } flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); } extent = (((pic->cmType)) == CMOpenPIC ? rewriteInlineCacheAttagtarget(backEnd, outerReturn, inlineCacheValueForSelectorinat((targetMethod->selector), mframeHomeMethodExport(), outerReturn), (((sqInt)pic)) + cmEntryOffset) : rewriteCallAttarget(backEnd, outerReturn, (((sqInt)pic)) + cmEntryOffset)); flushICacheFromto(processor, (((usqInt)outerReturn)) - extent, ((usqInt)outerReturn)); executeCogPICfromLinkedSendWithReceiverandCacheTag(pic, receiver, longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))); return null; } /* Cogit>>#checkAssertsEnabledInCogit */ void checkAssertsEnabledInCogit(void) { sqInt assertsAreEnabledInCogit; assertsAreEnabledInCogit = 0; assert(assertsAreEnabledInCogit); } /* Check for a valid object reference, if any, at a map entry. Answer a code unique to each error for debugging. */ /* Cogit>>#checkIfValidOopRefAndTarget:pc:cogMethod: */ static sqInt NoDbgRegParms checkIfValidOopRefAndTargetpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt entryPoint; sqInt entryPoint1; sqInt literal; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj; CogMethod *targetMethod1; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (!(asserta(checkValidOopReference(literal)))) { return 1; } if ((couldBeObject(literal)) && (isReallyYoungObject(literal))) { if (!(asserta(((((CogMethod *) cogMethod))->cmRefersToYoung)))) { return 2; } } } if (annotation >= IsSendCall) { if (!(asserta((((((CogMethod *) cogMethod))->cmType)) == CMMethod))) { return 3; } /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj = entryPointTagIsSelector(entryPoint1); entryPoint = entryPoint1; if (tagCouldBeObj) { if (couldBeObject(cacheTag1)) { if (!(asserta(checkValidOopReference(cacheTag1)))) { return 4; } } else { if (!(asserta(validInlineCacheTag(cacheTag1)))) { return 5; } } if ((couldBeObject(cacheTag1)) && (isReallyYoungObject(cacheTag1))) { if (!(asserta(((((CogMethod *) cogMethod))->cmRefersToYoung)))) { return 6; } } } else { if (!(asserta(validInlineCacheTag(cacheTag1)))) { return 9; } } if (entryPoint > methodZoneBase) { /* It's a linked send; find which kind. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (!(asserta((((targetMethod1->cmType)) == CMMethod) || ((((targetMethod1->cmType)) == CMClosedPIC) || (((targetMethod1->cmType)) == CMOpenPIC))))) { return 10; } } } return 0; } /* Check for a valid object reference, if any, at a map entry. Answer a code unique to each error for debugging. */ /* Cogit>>#checkIfValidOopRef:pc:cogMethod: */ static sqInt NoDbgRegParms checkIfValidOopRefpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt entryPoint; sqInt literal; sqInt offset; sqInt offset1; sqInt selectorOrCacheTag; sqInt *sendTable; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (!(checkValidOopReference(literal))) { print("object ref leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint <= methodZoneBase) { offset = entryPoint; } else { /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable = superSendTrampolines; } } } offset = offset1; } selectorOrCacheTag = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); if ((entryPoint > methodZoneBase) && ((offset != cmNoCheckEntryOffset) && ((((((CogMethod *) (entryPoint - offset)))->cmType)) != CMOpenPIC))) { /* linked non-super send, cacheTag is a cacheTag */ if (!(validInlineCacheTag(selectorOrCacheTag))) { print("cache tag leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } else { /* unlinked send or super send; cacheTag is a selector unless 64-bit, in which case it is an index. */ if (!(checkValidOopReference(selectorOrCacheTag))) { print("selector leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } } return 0; } /* Answer if all references to objects in machine-code are valid. */ /* Cogit>>#checkIntegrityOfObjectReferencesInCode: */ sqInt checkIntegrityOfObjectReferencesInCode(sqInt gcModes) { CogMethod *cogMethod; sqInt count; sqInt ok; cogMethod = ((CogMethod *) methodZoneBase); ok = 1; while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if ((cogMethod->cmRefersToYoung)) { if (((count = occurrencesInYoungReferrers(cogMethod))) != 1) { print("young referrer CM "); printHex(((sqInt)cogMethod)); if (count == 0) { print(" is not in youngReferrers"); cr(); } else { print(" is in youngReferrers "); printNum(count); print(" times!"); cr(); } ok = 0; } } if (!(checkValidOopReference((cogMethod->selector)))) { print("object leak in CM "); printHex(((sqInt)cogMethod)); print(" selector"); cr(); ok = 0; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); if (!(checkValidObjectReference((cogMethod->methodObject)))) { print("object leak in CM "); printHex(((sqInt)cogMethod)); print(" methodObject"); cr(); ok = 0; } if (!(isOopCompiledMethod((cogMethod->methodObject)))) { print("non-method in CM "); printHex(((sqInt)cogMethod)); print(" methodObject"); cr(); ok = 0; } if ((mapForperformUntilarg(cogMethod, checkIfValidOopRefpccogMethod, ((sqInt)cogMethod))) != 0) { ok = 0; } if (((isYoungObject((cogMethod->methodObject))) || (isYoung((cogMethod->selector)))) && (!((cogMethod->cmRefersToYoung)))) { print("CM "); printHex(((sqInt)cogMethod)); print(" refers to young but not marked as such"); cr(); ok = 0; } } else { if (((cogMethod->cmType)) == CMClosedPIC) { if (!(checkValidObjectReferencesInClosedPIC(cogMethod))) { ok = 0; } } else { if (((cogMethod->cmType)) == CMOpenPIC) { if ((mapForperformUntilarg(cogMethod, checkIfValidOopRefpccogMethod, ((sqInt)cogMethod))) != 0) { ok = 0; } } } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return ok; } /* Cogit>>#checkMaybeObjRefInClosedPIC: */ static sqInt NoDbgRegParms checkMaybeObjRefInClosedPIC(sqInt maybeObject) { if (maybeObject == 0) { return 1; } if (!(couldBeObject(maybeObject))) { return 1; } return checkValidObjectReference(maybeObject); } /* Cogit>>#checkValidObjectReferencesInClosedPIC: */ static sqInt NoDbgRegParms checkValidObjectReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt ok; sqInt pc; ok = 1; /* first we check the obj ref at the beginning of the CPIC */ pc = (((sqInt)cPIC)) + firstCPICCaseOffset; if (!(checkMaybeObjRefInClosedPIC(literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */)))) { print("object leak in CPIC "); printHex(((sqInt)cPIC)); print(" @ "); printHex(pc - 4 /* jumpLongByteSize */); cr(); ok = 0; } /* For each case we check any object reference at the end address - sizeof(conditional instruction) and then increment the end address by case size */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (!(checkMaybeObjRefInClosedPIC(literalBeforeFollowingAddress(backEnd, (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)))) { print("object leak in CPIC "); printHex(((sqInt)cPIC)); print(" @ "); printHex(pc - (jumpLongConditionalByteSize(backEnd))); cr(); ok = 0; } pc += cPICCaseSize; } return ok; } /* i.e. this should never be called, so keep it out of the main path. */ /* Cogit>>#cleanUpFailingCogCodeConstituents: */ static sqInt NoDbgRegParms NeverInline cleanUpFailingCogCodeConstituents(CogMethod *cogMethodArg) { CogMethod *cogMethod; cogMethod = cogMethodArg; while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMClosedPIC) { (cogMethod->methodObject = 0); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } popRemappableOop(); return null; } /* Answer if the ClosedPIC refers to any unmarked objects or freed/freeable target methods, applying markAndTraceOrFreeCogMethod:firstVisit: to those targets to determine if freed/freeable. */ /* Cogit>>#closedPICRefersToUnmarkedObject: */ static sqInt NoDbgRegParms closedPICRefersToUnmarkedObject(CogMethod *cPIC) { sqInt i; sqInt object; sqInt pc; if (!((isImmediate((cPIC->selector))) || (isMarked((cPIC->selector))))) { return 1; } pc = addressOfEndOfCaseinCPIC(1, cPIC); if (couldBeObject((object = literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */)))) { if (!(isMarked(object))) { return 1; } } if (markAndTraceOrFreePICTargetin(jumpLongTargetBeforeFollowingAddress(backEnd, pc), cPIC)) { return 1; } for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (couldBeObject((object = literalBeforeFollowingAddress(backEnd, (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)))) { if (!(isMarked(object))) { return 1; } } if (markAndTraceOrFreePICTargetin(jumpLongTargetBeforeFollowingAddress(backEnd, pc), cPIC)) { return 1; } } return 0; } /* Cogit>>#codeEntryFor: */ char * codeEntryFor(char *address) { sqInt i; for (i = 0; i <= (trampolineTableIndex - 3); i += 2) { if (((address >= (trampolineAddresses[i + 1])) && (address <= ((trampolineAddresses[i + 3]) - 1)))) { return trampolineAddresses[i + 1]; } } return null; } /* Cogit>>#codeEntryNameFor: */ char * codeEntryNameFor(char *address) { sqInt i; for (i = 0; i <= (trampolineTableIndex - 3); i += 2) { if (((address >= (trampolineAddresses[i + 1])) && (address <= ((trampolineAddresses[i + 3]) - 1)))) { return trampolineAddresses[i]; } } return null; } /* Cogit>>#cogCodeBase */ sqInt cogCodeBase(void) { return codeBase; } /* Answer the contents of the code zone as an array of pair-wise element, address in ascending address order. Answer a string for a runtime routine or abstract label (beginning, end, etc), a CompiledMethod for a CMMethod, or a selector (presumably a Symbol) for a PIC. If withDetails is true - answer machine-code to bytecode pc mapping information for methods - answer class, target pair information for closed PIC N.B. Since the class tag for the first case of a closed PIC is stored at the send site, it must be collected by scanning methods (see collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method:). Since closed PICs are never shared they always come after the method that references them, so we don't need an extra pass to collect the first case class tags, which are (temporarily) assigned to each closed PIC's methodObject field. But we do need to reset the methodObject fields to zero. This is done in createPICData:, unless memory runs out, in which case it is done by cleanUpFailingCogCodeConstituents:. */ /* Cogit>>#cogCodeConstituents: */ sqInt cogCodeConstituents(sqInt withDetails) { CogMethod *cogMethod; sqInt constituents; sqInt count; sqInt i; sqInt label; sqInt profileData; sqInt value; /* + 3 for start, freeStart and end */ count = (trampolineTableIndex / 2) + 3; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { count += 1; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } constituents = instantiateClassindexableSize(classArray(), count * 2); if (!(constituents)) { return constituents; } pushRemappableOop(constituents); if ((((label = stringForCString("CogCode"))) == null) || (((value = positive32BitIntegerFor(codeBase))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(0, constituents, label); storePointerUncheckedofObjectwithValue(1, constituents, value); for (i = 0; i < trampolineTableIndex; i += 2) { if ((((label = stringForCString(trampolineAddresses[i]))) == null) || (((value = positive32BitIntegerFor(((usqInt)(trampolineAddresses[i + 1]))))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(2 + i, constituents, label); storePointerUncheckedofObjectwithValue(3 + i, constituents, value); } count = trampolineTableIndex + 2; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { profileData = (((cogMethod->cmType)) == CMMethod ? (cogMethod->methodObject) : (withDetails && (((cogMethod->cmType)) == CMClosedPIC) ? createCPICData(cogMethod) : (cogMethod->selector))); if (!(profileData)) { return cleanUpFailingCogCodeConstituents(cogMethod); } storePointerUncheckedofObjectwithValue(count, constituents, profileData); if (withDetails) { value = collectCogMethodConstituent(cogMethod); } else { value = positive32BitIntegerFor(((usqInt)cogMethod)); } if (!(value)) { return cleanUpFailingCogCodeConstituents(cogMethod); } storePointerUncheckedofObjectwithValue(count + 1, constituents, value); count += 2; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if ((((label = stringForCString("CCFree"))) == null) || (((value = positive32BitIntegerFor(mzFreeStart))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(count, constituents, label); storePointerUncheckedofObjectwithValue(count + 1, constituents, value); if ((((label = stringForCString("CCEnd"))) == null) || (((value = positive32BitIntegerFor(limitAddress))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(count + 2, constituents, label); storePointerUncheckedofObjectwithValue(count + 3, constituents, value); constituents = popRemappableOop(); beRootIfOld(constituents); return constituents; } /* Extend the cPIC with the supplied case. If caseNMethod is cogged dispatch direct to its unchecked entry-point. If caseNMethod is not cogged, jump to the fast interpreter dispatch, and if isMNUCase then dispatch to fast MNU invocation and mark the cPIC as having the MNU case for cache flushing. */ /* Cogit>>#cogExtendPIC:CaseNMethod:tag:isMNUCase: */ static sqInt NoDbgRegParms cogExtendPICCaseNMethodtagisMNUCase(CogMethod *cPIC, sqInt caseNMethod, sqInt caseNTag, sqInt isMNUCase) { sqInt address; usqInt addressFollowingJump; sqInt operand; sqInt target; compilationBreakpointisMNUCase((cPIC->selector), numBytesOf((cPIC->selector)), isMNUCase); assert(!(inlineCacheTagIsYoung(caseNTag))); assert((caseNMethod != null) && (!(isYoung(caseNMethod)))); if ((!isMNUCase) && (methodHasCogMethod(caseNMethod))) { /* this isn't an MNU and we have an already cogged method to jump to */ operand = 0; target = (((sqInt)(cogMethodOf(caseNMethod)))) + cmNoCheckEntryOffset; } else { operand = caseNMethod; if (isMNUCase) { /* this is an MNU so tag the CPIC header and setup a jump to the MNUAbort */ /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) cPIC))->cpicHasMNUCaseOrCMIsFullBlock) = 1; target = (((sqInt)cPIC)) + (sizeof(CogMethod)); } else { /* setup a jump to the interpretAborth so we can cog the target method */ target = (((sqInt)cPIC)) + (picInterpretAbortOffset()); } } address = addressOfEndOfCaseinCPIC(((cPIC->cPICNumCases)) + 1, cPIC); rewriteCPICCaseAttagobjReftarget(address, caseNTag, operand, target); /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, address - cPICCaseSize); flushICacheFromto(processor, ((usqInt)cPIC), (((usqInt)cPIC)) + closedPICSize); (cPIC->cPICNumCases = ((cPIC->cPICNumCases)) + 1); return 0; } /* Attempt to produce a machine code method for the bytecode method object aMethodObj. N.B. If there is no code memory available do *NOT* attempt to reclaim the method zone. Certain clients (e.g. ceSICMiss:) depend on the zone remaining constant across method generation. */ /* Cogit>>#cogFullBlockMethod:numCopied: */ CogMethod * cogFullBlockMethodnumCopied(sqInt aMethodObj, sqInt numCopied) { CogMethod *cogMethod; /* inline exclude: */ assert(!((methodHasCogMethod(aMethodObj)))); assert(isOopCompiledMethod(ultimateLiteralOf(aMethodObj))); if (aMethodObj == breakMethod) { haltmsg("Compilation of breakMethod"); } if (methodUsesAlternateBytecodeSet(aMethodObj)) { if ((numElementsIn(generatorTable)) <= 256) { return null; } bytecodeSetOffset = 256; } else { bytecodeSetOffset = 0; } ensureNoForwardedLiteralsIn(aMethodObj); methodObj = aMethodObj; methodHeader = methodHeaderOf(aMethodObj); receiverTags = receiverTagBitsForMethod(methodObj); cogMethod = compileCogFullBlockMethod(numCopied); if ((((((sqInt)cogMethod)) >= MaxNegativeErrorCode) && ((((sqInt)cogMethod)) <= -1))) { if ((((sqInt)cogMethod)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return null; } return cogMethod; } /* Cogit>>#cogitPostGCAction: */ void cogitPostGCAction(sqInt gcMode) { # if SPURVM if (gcMode == GCModeBecome) { followForwardedLiteralsInOpenPICList(); } # endif /* SPURVM */ assert(allMethodsHaveCorrectHeader()); assert(((gcMode & (GCModeFull + GCModeNewSpace)) == 0) || (kosherYoungReferrers())); } /* Check that the header fields onf a non-free method are consistent with the type. Answer 0 if it is ok, otherwise answer a code for the error. */ /* Cogit>>#cogMethodDoesntLookKosher: */ sqInt cogMethodDoesntLookKosher(CogMethod *cogMethod) { if (((((cogMethod->blockSize)) & (BytesPerWord - 1)) != 0) || ((((cogMethod->blockSize)) < (sizeof(CogMethod))) || (((cogMethod->blockSize)) >= 32768))) { return 1; } if (((cogMethod->cmType)) == CMFree) { return 2; } if (((cogMethod->cmType)) == CMMethod) { if (!((((cogMethod->methodHeader)) & 1))) { return 11; } if (!(couldBeObject((cogMethod->methodObject)))) { return 12; } if ((((cogMethod->stackCheckOffset)) > 0) && (((cogMethod->stackCheckOffset)) < cmNoCheckEntryOffset)) { return 13; } return 0; } if (((cogMethod->cmType)) == CMOpenPIC) { if (((cogMethod->blockSize)) != openPICSize) { return 21; } if (((cogMethod->methodHeader)) != 0) { return 22; } if (((cogMethod->objectHeader)) >= 0) { if (!((((cogMethod->methodObject)) == 0) || (compactionInProgress || (((cogMethod->methodObject)) == (((usqInt)(methodFor((cogMethod->methodObject))))))))) { return 23; } } if (((cogMethod->stackCheckOffset)) != 0) { return 24; } return 0; } if (((cogMethod->cmType)) == CMClosedPIC) { if (((cogMethod->blockSize)) != closedPICSize) { return 0x1F; } if (!(((((cogMethod->cPICNumCases)) >= 1) && (((cogMethod->cPICNumCases)) <= MaxCPICCases)))) { return 32; } if (((cogMethod->methodHeader)) != 0) { return 33; } if (((cogMethod->methodObject)) != 0) { return 34; } return 0; } return 9; } /* Attempt to create a one-case PIC for an MNU. The tag for the case is at the send site and so doesn't need to be generated. */ /* Cogit>>#cogMNUPICSelector:receiver:methodOperand:numArgs: */ CogMethod * cogMNUPICSelectorreceivermethodOperandnumArgs(sqInt selector, sqInt rcvr, sqInt methodOperand, sqInt numArgs) { CogMethod *pic; usqInt startAddress; if ((isYoung(selector)) || ((inlineCacheTagForInstance(rcvr)) == 0 /* picAbortDiscriminatorValue */)) { return 0; } compilationBreakpointisMNUCase(selector, numBytesOf(selector), 1); assert(endCPICCase0 != null); startAddress = allocate(closedPICSize); if (startAddress == 0) { callForCogCompiledCodeCompaction(); return 0; } memcpy(((CogMethod *) startAddress), ((CogMethod *) cPICPrototype), closedPICSize); configureMNUCPICmethodOperandnumArgsdelta(((CogMethod *) startAddress), methodOperand, numArgs, startAddress - cPICPrototype); /* begin fillInCPICHeader:numArgs:numCases:hasMNUCase:selector: */ pic = ((CogMethod *) startAddress); assert(!(isYoung(selector))); (pic->cmType = CMClosedPIC); (pic->objectHeader = 0); (pic->blockSize = closedPICSize); (pic->methodObject = 0); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); (pic->cmRefersToYoung = 0); (pic->cmUsageCount = initialClosedPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = 1; (pic->cPICNumCases = 1); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMClosedPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert(((pic->cPICNumCases)) == 1); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(closedPICSize == (roundUpLength(closedPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Create an Open PIC. Temporarily create a direct call of ceSendFromOpenPIC:. Should become a probe of the first-level method lookup cache followed by a call of ceSendFromOpenPIC: if the probe fails. */ /* Cogit>>#cogOpenPICSelector:numArgs: */ static CogMethod * NoDbgRegParms cogOpenPICSelectornumArgs(sqInt selector, sqInt numArgs) { sqInt codeSize; sqInt end; sqInt fixupSize; sqInt mapSize; sqInt opcodeSize; CogMethod *pic; usqInt startAddress; compilationBreakpointisMNUCase(selector, numBytesOf(selector), 0); startAddress = allocate(openPICSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } (methodLabel->address = startAddress); (methodLabel->dependent = null); /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 100; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; compileOpenPICnumArgs(selector, numArgs); computeMaximumSizes(); concretizeAt(methodLabel, startAddress); codeSize = generateInstructionsAt(startAddress + (sizeof(CogMethod))); mapSize = generateMapAtstart((startAddress + openPICSize) - 1, startAddress + cmNoCheckEntryOffset); assert((((entry->address)) - startAddress) == cmEntryOffset); assert(((roundUpLength((sizeof(CogMethod)) + codeSize)) + (roundUpLength(mapSize))) <= openPICSize); end = outputInstructionsAt(startAddress + (sizeof(CogMethod))); /* begin fillInOPICHeader:numArgs:selector: */ pic = ((CogMethod *) startAddress); (pic->cmType = CMOpenPIC); (pic->objectHeader = 0); (pic->blockSize = openPICSize); addToOpenPICList(pic); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); if ((pic->cmRefersToYoung = isYoung(selector))) { addToYoungReferrers(pic); } (pic->cmUsageCount = initialOpenPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = 0; (pic->cPICNumCases = 0); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMOpenPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(openPICSize == (roundUpLength(openPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + openPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Attempt to create a two-case PIC for case0CogMethod and case1Method,case1Tag. The tag for case0CogMethod is at the send site and so doesn't need to be generated. case1Method may be any of - a Cog method; link to its unchecked entry-point - a CompiledMethod; link to ceInterpretMethodFromPIC: - a CompiledMethod; link to ceMNUFromPICMNUMethod:receiver: */ /* Cogit>>#cogPICSelector:numArgs:Case0Method:Case1Method:tag:isMNUCase: */ static CogMethod * NoDbgRegParms cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase(sqInt selector, sqInt numArgs, CogMethod *case0CogMethod, sqInt case1MethodOrNil, sqInt case1Tag, sqInt isMNUCase) { CogMethod *pic; usqInt startAddress; if (isYoung(selector)) { return ((CogMethod *) YoungSelectorInPIC); } compilationBreakpointisMNUCase(selector, numBytesOf(selector), isMNUCase); startAddress = allocate(closedPICSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } memcpy(((CogMethod *) startAddress), ((CogMethod *) cPICPrototype), closedPICSize); configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(((CogMethod *) startAddress), case0CogMethod, case1MethodOrNil, case1Tag, isMNUCase, numArgs, startAddress - cPICPrototype); /* begin fillInCPICHeader:numArgs:numCases:hasMNUCase:selector: */ pic = ((CogMethod *) startAddress); assert(!(isYoung(selector))); (pic->cmType = CMClosedPIC); (pic->objectHeader = 0); (pic->blockSize = closedPICSize); (pic->methodObject = 0); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); (pic->cmRefersToYoung = 0); (pic->cmUsageCount = initialClosedPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = isMNUCase; (pic->cPICNumCases = 2); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMClosedPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert(((pic->cPICNumCases)) == 2); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(closedPICSize == (roundUpLength(closedPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Attempt to produce a machine code method for the bytecode method object aMethodObj. N.B. If there is no code memory available do *NOT* attempt to reclaim the method zone. Certain clients (e.g. ceSICMiss:) depend on the zone remaining constant across method generation. */ /* Cogit>>#cog:selector: */ CogMethod * cogselector(sqInt aMethodObj, sqInt aSelectorOop) { CogMethod *cogMethod; sqInt selector; /* inline exclude:selector: */ assert(!((methodHasCogMethod(aMethodObj)))); assert(!((isOopCompiledMethod(ultimateLiteralOf(aMethodObj))))); /* coInterpreter stringOf: selector */ selector = (aSelectorOop == (nilObject()) ? maybeSelectorOfMethod(aMethodObj) : aSelectorOop); if (!(selector == null)) { compilationBreakpointisMNUCase(selector, lengthOf(selector), 0); } if (aMethodObj == breakMethod) { haltmsg("Compilation of breakMethod"); } if (methodUsesAlternateBytecodeSet(aMethodObj)) { if ((numElementsIn(generatorTable)) <= 256) { return null; } bytecodeSetOffset = 256; } else { bytecodeSetOffset = 0; } ensureNoForwardedLiteralsIn(aMethodObj); methodObj = aMethodObj; methodHeader = methodHeaderOf(aMethodObj); receiverTags = receiverTagBitsForMethod(methodObj); cogMethod = compileCogMethod(aSelectorOop); if ((((((sqInt)cogMethod)) >= MaxNegativeErrorCode) && ((((sqInt)cogMethod)) <= -1))) { if ((((sqInt)cogMethod)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return null; } return cogMethod; } /* Cogit>>#collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method: */ static sqInt NoDbgRegParms collectCogConstituentForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg) { sqInt address; sqInt annotation; sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; if (!(descriptor)) { return 0; } if (!((descriptor->isMapped))) { return 0; } address = positive32BitIntegerFor(mcpc); if (!(address)) { return PrimErrNoMemory; } storePointerUncheckedofObjectwithValue(cogConstituentIndex, topRemappableOop(), address); storePointerUncheckedofObjectwithValue(cogConstituentIndex + 1, topRemappableOop(), (((usqInt)bcpc << 1) | 1)); /* Collect any first case classTags for closed PICs. */ cogConstituentIndex += 2; if (((isBackwardBranchAndAnnotation & 1) == 0) && (((((usqInt) isBackwardBranchAndAnnotation) >> 1) >= IsSendCall) || (0))) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* send is linked */ /* begin targetMethodAndSendTableFor:annotation:into: */ annotation = ((usqInt) isBackwardBranchAndAnnotation) >> 1; /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmType)) == CMClosedPIC) { (targetMethod1->methodObject = classForInlineCacheTag(longAt(pcRelativeAddressAt(backEnd, ((usqInt)(mcpc - 8)))))); } } } return 0; } /* Answer a description of the mapping between machine code pointers and bytecode pointers for the Cog Method. First value is the address of the cog method. Following values are pairs of machine code pc and bytecode pc */ /* Cogit>>#collectCogMethodConstituent: */ static sqInt NoDbgRegParms collectCogMethodConstituent(CogMethod *cogMethod) { sqInt address; sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; sqInt cm; CogBlockMethod *cogBlockMethod; sqInt data; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; sqInt errCode; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt nSlots; sqInt result; sqInt startbcpc; sqInt targetPC; latestContinuation = 0; if (!(((cogMethod->cmType)) == CMMethod)) { return positive32BitIntegerFor(((usqInt)cogMethod)); } cogBlockMethod = ((CogBlockMethod *) cogMethod); if (((cogBlockMethod->stackCheckOffset)) == 0) { /* isFrameless ? */ return positive32BitIntegerFor(((usqInt)cogMethod)); } cm = (cogMethod->methodObject); /* +1 for first address */ nSlots = ((((byteSizeOf(cm)) - (startPCOfMethod(cm))) * 2) + (minSlotsForShortening())) + 1; data = instantiateClassindexableSize(splObj(ClassArray), nSlots); if (!(data)) { return null; } pushRemappableOop(data); address = positive32BitIntegerFor(((usqInt)cogMethod)); if (!(address)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(0, topRemappableOop(), address); cogConstituentIndex = 1; /* begin mapFor:bcpc:performUntil:arg: */ startbcpc = startPCOfMethod((cogMethod->methodObject)); assert(((cogBlockMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogBlockMethod)) + ((cogBlockMethod->stackCheckOffset)); result = collectCogConstituentForAnnotationMcpcBcpcMethod(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc)), startbcpc, (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogBlockMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogBlockMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogBlockMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogBlockMethod->startpc))); homeMethod = cmHomeMethod(cogBlockMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogBlockMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { errCode = 0; goto l7; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { errCode = 0; goto l7; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = collectCogConstituentForAnnotationMcpcBcpcMethod(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } errCode = 0; l7: /* end mapFor:bcpc:performUntil:arg: */; if (errCode != 0) { popRemappableOop(); return null; } if (cogConstituentIndex < nSlots) { shortentoIndexableSize(topRemappableOop(), cogConstituentIndex); } return popRemappableOop(); } /* Cogit>>#compactCogCompiledCode */ void compactCogCompiledCode(void) { assert(noCogMethodsMaximallyMarked()); markActiveMethodsAndReferents(); freeOlderMethodsForCompaction(); compactPICsWithFreedTargets(); planCompaction(); updateStackZoneReferencesToCompiledCodePreCompaction(); relocateMethodsPreCompaction(); compactCompiledCode(); assert(allMethodsHaveCorrectHeader()); assert(kosherYoungReferrers()); stopsFromto(backEnd, freeStart(), (youngReferrers()) - 1); flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(youngReferrers()))); } /* Cogit>>#compactPICsWithFreedTargets */ static void compactPICsWithFreedTargets(void) { CogMethod *cogMethod; sqInt count; cogMethod = ((CogMethod *) methodZoneBase); count = 0; while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICCompactAndIsNowEmpty(cogMethod))) { (cogMethod->cmType = CMFree); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); count += 1; } assert(count == (numMethods())); } /* The start of a CogMethod has a call to a run-time abort routine that either handles an in-line cache failure or a stack overflow. The routine selects the path depending on ReceiverResultReg; if zero it takes the stack overflow path; if nonzero the in-line cache miss path. Neither of these paths returns. The abort routine must be called; In the callee the method is located by adding the relevant offset to the return address of the call. N.B. This code must match that in compilePICAbort: so that the offset of the return address of the call is the same in methods and closed PICs. */ /* Cogit>>#compileAbort */ static AbstractInstruction * compileAbort(void) { AbstractInstruction *anInstruction; sqInt callTarget; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } stackOverflowCall = anInstruction; /* If there is a link register it must be saved (pushed onto the stack) before it is smashed by the abort call, and hence needs to be manually handled here */ sendMiss = genoperand(PushR, LinkReg); /* begin Call: */ callTarget = methodAbortTrampolineFor(methodOrBlockNumArgs); return genoperand(Call, callTarget); } /* Cogit>>#compileBlockDispatchFrom:to: */ static sqInt NoDbgRegParms compileBlockDispatchFromto(sqInt lowBlockStartIndex, sqInt highBlockStartIndex) { AbstractInstruction *anInstruction; BlockStart *blockStart; sqInt halfWay; AbstractInstruction *jmp; sqInt literal; if (lowBlockStartIndex == highBlockStartIndex) { blockStart = blockStartAt(lowBlockStartIndex); genoperand(Jump, ((sqInt)((blockStart->entryLabel)))); return null; } halfWay = (highBlockStartIndex + lowBlockStartIndex) / 2; assert(((halfWay >= lowBlockStartIndex) && (halfWay <= highBlockStartIndex))); /* N.B. FLAGS := TempReg - startpc */ blockStart = blockStartAt(halfWay); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)(((blockStart->startpc)) + 1) << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)(((blockStart->startpc)) + 1) << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } if (lowBlockStartIndex == halfWay) { genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)((blockStart->entryLabel)))); compileBlockDispatchFromto(halfWay + 1, highBlockStartIndex); return null; } if ((halfWay + 1) == highBlockStartIndex) { blockStart = blockStartAt(highBlockStartIndex); genConditionalBranchoperand(JumpGreater, ((sqInt)((blockStart->entryLabel)))); return compileBlockDispatchFromto(lowBlockStartIndex, halfWay); } jmp = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); compileBlockDispatchFromto(lowBlockStartIndex, halfWay); if (halfWay == highBlockStartIndex) { blockStart = blockStartAt(highBlockStartIndex); jmpTarget(jmp, (blockStart->entryLabel)); } else { jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); compileBlockDispatchFromto(halfWay + 1, highBlockStartIndex); } return 0; } /* Compile a block's entry. This looks like a dummy CogBlockMethod header (for frame parsing) followed by either a frame build, if a frame is required, or nothing. The CogMethodHeader's objectHeader field is a back pointer to the method, but this can't be filled in until code generation. */ /* Cogit>>#compileBlockEntry: */ static void NoDbgRegParms compileBlockEntry(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; sqInt alignment; /* begin AlignmentNops: */ alignment = blockAlignment(); genoperand(AlignmentNops, alignment); (blockStart->fakeHeader = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); switch (sizeof(CogBlockMethod)) { case 8: genoperand(Fill32, 0); genoperand(Fill32, 0); break; case 12: genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); break; case 16: genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); break; default: error("Case not found and no otherwise clause"); } (blockStart->entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (needsFrame) { compileBlockFrameBuild(blockStart); if (recordBlockTrace()) { /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceBlockActivationTrampoline); (abstractInstruction->annotation = IsRelativeCall); } } else { compileBlockFramelessEntry(blockStart); } } /* Generate a call to aRoutine with up to 4 arguments. If resultRegOrNone is not NoReg assign the C result to resultRegOrNone. If saveRegs, save all registers. Hack: a negative arg value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#compileCallFor:numArgs:arg:arg:arg:arg:resultReg:regsToSave: */ static void NoDbgRegParms compileCallFornumArgsargargargargresultRegregsToSave(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt resultRegOrNone, sqInt regMask) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; const int cStackAlignment = STACK_ALIGN_BYTES; sqInt delta; sqInt numRegsPushed; sqInt operand1; usqInt regMaskCopy; sqInt regsToSave; sqInt wordsPushedModAlignment; regsToSave = (resultRegOrNone == NoReg ? regMask : ((regMask | (1U << resultRegOrNone)) - (1U << resultRegOrNone))); if (cStackAlignment > BytesPerWord) { /* begin genAlignCStackSavingRegisters:numArgs:wordAlignment: */ regMaskCopy = ((usqInt)regsToSave); numRegsPushed = 0; while (regMaskCopy != 0) { numRegsPushed += regMaskCopy & 1; regMaskCopy = ((usqInt) regMaskCopy >> 1); } if ((numRegsPushed == 0) && (4 /* numIntRegArgs */ >= numArgs)) { goto l4; } wordsPushedModAlignment = (numRegsPushed + numArgs) % (cStackAlignment / BytesPerWord); if (wordsPushedModAlignment != 0) { delta = (cStackAlignment / BytesPerWord) - wordsPushedModAlignment; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, delta * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(delta * BytesPerWord)); } } l4: /* end genAlignCStackSavingRegisters:numArgs:wordAlignment: */; } /* begin genSaveRegs: */ if (regsToSave == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, regsToSave); } /* begin genMarshallNArgs:arg:arg:arg:arg: */ if (numArgs == 0) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst0 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, -2 - regOrConst0, CArg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(-2 - regOrConst0)); } } else { genoperandoperand(MoveRR, regOrConst0, CArg0Reg); } if (numArgs == 1) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst1 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, -2 - regOrConst1, CArg1Reg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(-2 - regOrConst1)); } } else { genoperandoperand(MoveRR, regOrConst1, CArg1Reg); } if (numArgs == 2) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst2 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(MoveCqR, -2 - regOrConst2, CArg2Reg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(-2 - regOrConst2)); } } else { genoperandoperand(MoveRR, regOrConst2, CArg2Reg); } if (numArgs == 3) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst3 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, -2 - regOrConst3, CArg3Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(-2 - regOrConst3)); } } else { genoperandoperand(MoveRR, regOrConst3, CArg3Reg); } ((AbstractInstruction *) backEnd); l7: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ operand1 = ((usqInt)aRoutine); checkLiteralforInstruction(operand1, genoperand(CallFull, operand1)); if (resultRegOrNone != NoReg) { genWriteCResultIntoReg(backEnd, resultRegOrNone); } /* begin genRemoveNArgsFromStack: */ assert(numArgs <= 4); /* begin genRestoreRegs: */ if (regsToSave == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PopLDM, regsToSave); } } /* Compile the cache tag computation and the first comparison. Answer the address of that comparison. */ /* Cogit>>#compileCPICEntry */ static AbstractInstruction * compileCPICEntry(void) { entry = genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, TempReg, 1); /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* Compile the abstract instructions for the entire full block method. */ /* Cogit>>#compileEntireFullBlockMethod: */ static sqInt NoDbgRegParms compileEntireFullBlockMethod(sqInt numCopied) { sqInt result; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compileFullBlockEntry(); compileFullBlockMethodFrameBuild(numCopied); if (((result = compileMethodBody())) < 0) { return result; } assert(blockCount == 0); return 0; } /* The entry code to a method checks that the class of the current receiver matches that in the inline cache. Other non-obvious elements are that its alignment must be different from the alignment of the noCheckEntry so that the method map machinery can distinguish normal and super sends (super sends bind to the noCheckEntry). */ /* Cogit>>#compileEntry */ static void compileEntry(void) { AbstractInstruction *abstractInstruction; AbstractInstruction * inst; entry = genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, TempReg, 1); /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); genConditionalBranchoperand(JumpNonZero, ((sqInt)sendMiss)); noCheckEntry = genoperandoperand(Label, (labelCounter += 1), bytecodePC); if (compileSendTrace()) { /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceLinkedSendTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); } } /* Compile the abstract instructions for the entire method, including blocks. */ /* Abort for stack overflow on full block activation (no inline cache miss possible). The flag is SendNumArgsReg. */ /* Cogit>>#compileFullBlockEntry */ static sqInt compileFullBlockEntry(void) { sqInt alignment; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt callTarget; AbstractInstruction * jumpNoContextSwitch; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } stackOverflowCall = anInstruction; /* begin PushR: */ genoperand(PushR, LinkReg); /* begin Call: */ callTarget = methodAbortTrampolineFor(methodOrBlockNumArgs); genoperand(Call, callTarget); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } fullBlockNoContextSwitchEntry = anInstruction1; jumpNoContextSwitch = genoperand(Jump, ((sqInt)0)); /* begin AlignmentNops: */ alignment = ((BytesPerWord < 8) ? 8 : BytesPerWord); genoperand(AlignmentNops, alignment); fullBlockEntry = genoperandoperand(MoveRR, ReceiverResultReg, SendNumArgsReg); jmpTarget(jumpNoContextSwitch, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Compile the top-level method body. */ /* Cogit>>#compileMethodBody */ static sqInt compileMethodBody(void) { if (endPC < initialPC) { return 0; } return compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); } /* The start of a PIC has a call to a run-time abort routine that either handles a dispatch to an interpreted method or a dispatch of an MNU case. The routine selects the path by testing ClassReg, which holds the inline cache tag; if equal to the picAbortDiscriminatorValue (zero) it takes the MNU path; if nonzero the dispatch to interpreter path. Neither of these paths returns. The abort routine must be called; In the callee the PIC is located by adding the relevant offset to the return address of the call. N.B. This code must match that in compileAbort so that the offset of the return address of the call is the same in methods and closed PICs. */ /* Cogit>>#compilePICAbort: */ static sqInt NoDbgRegParms compilePICAbort(sqInt numArgs) { AbstractInstruction *anInstruction; sqInt callTarget; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0 /* picAbortDiscriminatorValue */, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0 /* picAbortDiscriminatorValue */)); } picMNUAbort = anInstruction; /* If there is a link register it must be saved (pushed onto the stack) before it is smashed by the abort call, and hence needs to be manually handled here */ picInterpretAbort = genoperand(PushR, LinkReg); /* begin Call: */ callTarget = picAbortTrampolineFor(numArgs); genoperand(Call, callTarget); return 0; } /* Generate a trampoline with up to four arguments. Generate either a call or a jump to aRoutine as requested by callJumpBar. If generating a call and resultRegOrNone is not NoReg pass the C result back in resultRegOrNone. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#compileTrampolineFor:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg: */ static void NoDbgRegParms compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone) { genSmalltalkToCStackSwitch(pushLinkReg); compileCallFornumArgsargargargargresultRegregsToSave(aRoutine, numArgs, regOrConst0, regOrConst1, regOrConst2, regOrConst3, resultRegOrNone, regMask); genLoadStackPointers(backEnd); if (pushLinkReg && (1)) { genoperand(PopR, PCReg); } else { genoperand(RetN, 0); } } /* Generate the entry code for a method to determine cmEntryOffset and cmNoCheckEntryOffset. We need cmNoCheckEntryOffset up front to be able to generate the map starting from cmNoCheckEntryOffset */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#computeEntryOffsets */ static void computeEntryOffsets(void) { sqInt fixupSize; sqInt opcodeSize; AbstractInstruction *sendMissCall; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 24; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; methodOrBlockNumArgs = 0; sendMissCall = compileAbort(); compileEntry(); computeMaximumSizes(); generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); cmEntryOffset = ((entry->address)) - methodZoneBase; cmNoCheckEntryOffset = ((noCheckEntry->address)) - methodZoneBase; missOffset = (((sendMissCall->address)) + ((sendMissCall->machineCodeSize))) - methodZoneBase; entryPointMask = BytesPerWord - 1; while ((cmEntryOffset & entryPointMask) == (cmNoCheckEntryOffset & entryPointMask)) { entryPointMask = (entryPointMask + entryPointMask) + 1; } if (entryPointMask >= (roundUpLength(1))) { error("cannot differentiate checked and unchecked entry-points with current cog method alignment"); } checkedEntryAlignment = cmEntryOffset & entryPointMask; uncheckedEntryAlignment = cmNoCheckEntryOffset & entryPointMask; assert(checkedEntryAlignment != uncheckedEntryAlignment); } /* Generate the entry code for a method to determine cmEntryOffset and cmNoCheckEntryOffset. We need cmNoCheckEntryOffset up front to be able to generate the map starting from cmNoCheckEntryOffset */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#computeFullBlockEntryOffsets */ static void computeFullBlockEntryOffsets(void) { sqInt fixupSize; sqInt opcodeSize; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 24; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; methodOrBlockNumArgs = 0; compileFullBlockEntry(); computeMaximumSizes(); generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); cbEntryOffset = ((fullBlockEntry->address)) - methodZoneBase; cbNoSwitchEntryOffset = ((fullBlockNoContextSwitchEntry->address)) - methodZoneBase; } /* This pass assigns maximum sizes to all abstract instructions and eliminates jump fixups. It hence assigns the maximum address an instruction will occur at which allows the next pass to conservatively size jumps. */ /* Cogit>>#computeMaximumSizes */ static void computeMaximumSizes(void) { AbstractInstruction *abstractInstruction; sqInt i; sqInt relativeAddress; dumpLiterals(0); relativeAddress = 0; for (i = 0; i < opcodeIndex; i += 1) { abstractInstruction = abstractInstructionAt(i); (abstractInstruction->address = relativeAddress); (abstractInstruction->maxSize = computeMaximumSize(abstractInstruction)); relativeAddress += (abstractInstruction->maxSize); } } /* Configure a copy of the prototype CPIC for a two-case PIC for case0CogMethod and case1Method case1Tag. The tag for case0CogMethod is at the send site and so doesn't need to be generated. case1Method may be any of - a Cog method; jump to its unchecked entry-point - a CompiledMethod; jump to the ceInterpretFromPIC trampoline - nil; call ceMNUFromPIC addDelta is the address change from the prototype to the new CPIC location, needed because the loading of the CPIC label at the end may use a literal instead of a pc relative load. */ /* self disassembleFrom: cPIC asInteger + (self sizeof: CogMethod) to: cPIC asInteger + closedPICSize */ /* Cogit>>#configureCPIC:Case0:Case1Method:tag:isMNUCase:numArgs:delta: */ static sqInt NoDbgRegParms configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(CogMethod *cPIC, CogMethod *case0CogMethod, sqInt case1Method, sqInt case1Tag, sqInt isMNUCase, sqInt numArgs, sqInt addrDelta) { sqInt caseEndAddress; sqInt operand; sqInt targetEntry; assert(case1Method != null); rewriteCallAttarget(backEnd, (((sqInt)cPIC)) + missOffset, picAbortTrampolineFor(numArgs)); assert(!(inlineCacheTagIsYoung(case1Tag))); if ((!isMNUCase) && (methodHasCogMethod(case1Method))) { operand = 0; targetEntry = (((sqInt)(cogMethodOf(case1Method)))) + cmNoCheckEntryOffset; } else { /* We do not scavenge PICs, hence we cannot cache the MNU method if it is in new space. */ operand = ((case1Method == null) || (isYoungObject(case1Method)) ? 0 : case1Method); targetEntry = (case1Method == null ? (((sqInt)cPIC)) + (sizeof(CogMethod)) : (((sqInt)cPIC)) + (picInterpretAbortOffset())); } rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + firstCPICCaseOffset, (((sqInt)case0CogMethod)) + cmNoCheckEntryOffset); /* update the cpic case */ caseEndAddress = addressOfEndOfCaseinCPIC(2, cPIC); rewriteCPICCaseAttagobjReftarget(caseEndAddress, case1Tag, operand, ((sqInt)((isMNUCase ? (((sqInt)cPIC)) + (sizeof(CogMethod)) : targetEntry)))); relocateMethodReferenceBeforeAddressby(backEnd, ((((sqInt)cPIC)) + cPICEndOfCodeOffset) - 4 /* jumpLongByteSize */, addrDelta); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, cPICMissTrampolineFor(numArgs)); return 0; } /* Configure a copy of the prototype CPIC for a one-case MNU CPIC that calls ceMNUFromPIC for case0Tag The tag for case0 is at the send site and so doesn't need to be generated. addDelta is the address change from the prototype to the new CPIC location, needed because the loading of the CPIC label at the end may be a literal instead of a pc-relative load. */ /* adjust the jump at missOffset, the ceAbortXArgs */ /* Cogit>>#configureMNUCPIC:methodOperand:numArgs:delta: */ static sqInt NoDbgRegParms configureMNUCPICmethodOperandnumArgsdelta(CogMethod *cPIC, sqInt methodOperand, sqInt numArgs, sqInt addrDelta) { usqInt addressFollowingJump; int operand; sqInt target; rewriteCallAttarget(backEnd, (((sqInt)cPIC)) + missOffset, picAbortTrampolineFor(numArgs)); /* set the jump to the case0 method */ operand = ((methodOperand == null) || (isYoungObject(methodOperand)) ? 0 : methodOperand); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + firstCPICCaseOffset, (((sqInt)cPIC)) + (sizeof(CogMethod))); storeLiteralbeforeFollowingAddress(backEnd, operand, ((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, cPICMissTrampolineFor(numArgs)); relocateMethodReferenceBeforeAddressby(backEnd, ((((sqInt)cPIC)) + cPICEndOfCodeOffset) - 4 /* jumpLongByteSize */, addrDelta); /* begin rewriteCPIC:caseJumpTo: */ target = addressOfEndOfCaseinCPIC(2, cPIC); /* begin rewriteCPICJumpAt:target: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, target); return 0; } /* Scan the CPIC for target methods that have been freed and eliminate them. Since the first entry cannot be eliminated, answer that the PIC should be freed if the first entry is to a free target. Answer if the PIC is now empty or should be freed. */ /* Cogit>>#cPICCompactAndIsNowEmpty: */ static sqInt NoDbgRegParms cPICCompactAndIsNowEmpty(CogMethod *cPIC) { usqInt addressFollowingJump; usqInt addressFollowingJump1; sqInt entryPoint; sqInt followingAddress; sqInt i; sqInt methods[MaxCPICCases]; sqInt pc; int tags[MaxCPICCases]; CogMethod *targetMethod; sqInt targets[MaxCPICCases]; sqInt used; sqInt valid; used = 0; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } /* Collect all target triples except for triples whose entry-point is a freed method */ valid = 1; if (!(((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint))))) { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); if (((targetMethod->cmType)) == CMFree) { if (i == 1) { return 1; } valid = 0; } } if (valid) { tags[used] = ((i > 1 ? (/* begin literal32BeforeFollowingAddress: */ (followingAddress = pc - (jumpLongConditionalByteSize(backEnd))), literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), followingAddress)) : 0)); targets[used] = entryPoint; methods[used] = (literalBeforeFollowingAddress(backEnd, pc - ((i == 1 ? /* begin jumpLongByteSize */ 4 : (jumpLongConditionalByteSize(backEnd)) + 8 /* cmpC32RTempByteSize */)))); used += 1; } } if (used == ((cPIC->cPICNumCases))) { return 0; } if (used == 0) { return 1; } (cPIC->cPICNumCases = used); if (used == 1) { pc = addressOfEndOfCaseinCPIC(2, cPIC); /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, pc); return 0; } for (i = 1; i < used; i += 1) { pc = addressOfEndOfCaseinCPIC(i + 1, cPIC); rewriteCPICCaseAttagobjReftarget(pc, tags[i], methods[i], targets[i]); } /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump1 = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump1, pc - cPICCaseSize); return 0; } /* The first case in a CPIC doesn't have a class reference so we need only step over actually usd subsequent cases. */ /* Cogit>>#cPICHasForwardedClass: */ static sqInt NoDbgRegParms cPICHasForwardedClass(CogMethod *cPIC) { sqInt classIndex; sqInt i; sqInt pc; /* start by finding the address of the topmost case, the cPICNumCases'th one */ pc = (addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC)) - (jumpLongConditionalByteSize(backEnd)); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { /* begin literal32BeforeFollowingAddress: */ classIndex = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (isForwardedClassIndex(classIndex)) { return 1; } pc += cPICCaseSize; } return 0; } /* scan the CPIC for target methods that have been freed. */ /* Cogit>>#cPICHasFreedTargets: */ static sqInt NoDbgRegParms cPICHasFreedTargets(CogMethod *cPIC) { sqInt entryPoint; sqInt i; sqInt pc; CogMethod *targetMethod; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (!(((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint))))) { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); if (((targetMethod->cmType)) == CMFree) { return 1; } } } return 0; } /* Whimsey; we want 16rCA5E10 + cPICPrototypeCaseOffset to be somewhere in the middle of the zone. */ /* Cogit>>#cPICPrototypeCaseOffset */ static sqInt cPICPrototypeCaseOffset(void) { return ((methodZoneBase + (youngReferrers())) / 2) - 13262352; } /* Are any of the jumps from this CPIC to targetMethod? */ /* Cogit>>#cPIC:HasTarget: */ static sqInt NoDbgRegParms cPICHasTarget(CogMethod *cPIC, CogMethod *targetMethod) { sqInt i; sqInt pc; sqInt target; target = (((usqInt)targetMethod)) + cmNoCheckEntryOffset; /* Since this is a fast test doing simple compares we don't need to care that some cases have nonsense addresses in there. Just zip on through. */ /* First jump is unconditional; subsequent ones are conditional */ pc = (((sqInt)cPIC)) + firstCPICCaseOffset; if (target == (jumpLongTargetBeforeFollowingAddress(backEnd, pc))) { return 1; } for (i = 2; i <= MaxCPICCases; i += 1) { pc += cPICCaseSize; if (target == (jumpLongTargetBeforeFollowingAddress(backEnd, pc))) { return 1; } } return 0; } /* Answer an Array of the PIC's selector, followed by class and targetMethod/doesNotUnderstand: for each entry in the PIC. */ /* Cogit>>#createCPICData: */ static sqInt NoDbgRegParms createCPICData(CogMethod *cPIC) { sqInt class; sqInt entryPoint; sqInt i; sqInt pc; sqInt picData; sqInt target; CogMethod *targetMethod; assert((((cPIC->methodObject)) == 0) || (addressCouldBeOop((cPIC->methodObject)))); picData = instantiateClassindexableSize(classArray(), (((cPIC->cPICNumCases)) * 2) + 1); if (!(picData)) { return picData; } storePointerUncheckedofObjectwithValue(0, picData, (cPIC->selector)); for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { /* first case may have been collected and stored here by collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method: */ class = (cPIC->methodObject); if (class == 0) { class = nilObject(); } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { class = classForInlineCacheTag(literal32BeforeFollowingAddress(backEnd, pc - (jumpLongConditionalByteSize(backEnd)))); /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { target = splObj(SelectorDoesNotUnderstand); } else { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert(((targetMethod->cmType)) == CMMethod); target = (targetMethod->methodObject); } storePointerUncheckedofObjectwithValue((i * 2) - 1, picData, class); storePointerUncheckedofObjectwithValue(i * 2, picData, target); } beRootIfOld(picData); (cPIC->methodObject = 0); return picData; } /* Division is a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#DivR:R:Quo:Rem: */ static AbstractInstruction * NoDbgRegParms gDivRRQuoRem(sqInt rDivisor, sqInt rDividend, sqInt rQuotient, sqInt rRemainder) { genDivRRQuoRem(backEnd, rDivisor, rDividend, rQuotient, rRemainder); return abstractInstructionAt(opcodeIndex - 1); } /* Return the default number of bytes to allocate for native code at startup. The actual value can be set via vmParameterAt: and/or a preference in the ini file. */ /* Cogit>>#defaultCogCodeSize */ sqInt defaultCogCodeSize(void) { return 1024 * 1280; } /* Answer the number of bytecodes to skip to get to the first bytecode past the primitive call and any store of the error code. */ /* Cogit>>#deltaToSkipPrimAndErrorStoreIn:header: */ static sqInt NoDbgRegParms deltaToSkipPrimAndErrorStoreInheader(sqInt aMethodObj, sqInt aMethodHeader) { return (((primitiveIndexOfMethodheader(aMethodObj, aMethodHeader)) > 0) && ((longStoreBytecodeForHeader(aMethodHeader)) == (fetchByteofObject((startPCOfMethod(aMethodObj)) + (sizeOfCallPrimitiveBytecode(aMethodHeader)), aMethodObj))) ? (sizeOfCallPrimitiveBytecode(aMethodHeader)) + (sizeOfLongStoreTempBytecode(aMethodHeader)) : 0); } /* Cogit>>#endPCOf: */ static sqInt NoDbgRegParms endPCOf(sqInt aMethod) { sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt end; sqInt latestContinuation; sqInt nExts; sqInt pc; sqInt prim; sqInt targetPC; pc = (latestContinuation = startPCOfMethod(aMethod)); if (((prim = primitiveIndexOf(aMethod))) > 0) { if (isQuickPrimitiveIndex(prim)) { return pc - 1; } } /* begin bytecodeSetOffsetFor: */ bsOffset = # if MULTIPLEBYTECODESETS (methodUsesAlternateBytecodeSet(aMethod) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; nExts = 0; end = numBytesOf(aMethod); while (pc <= end) { byte = fetchByteofObject(pc, aMethod); descriptor = generatorAt(byte + bsOffset); if (((descriptor->isReturn)) && (pc >= latestContinuation)) { end = pc; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { distance = ((descriptor->spanFunction))(descriptor, pc, nExts, aMethod); targetPC = (pc + ((descriptor->numBytes))) + distance; latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); if ((descriptor->isBlockCreation)) { pc += distance; } } else { latestContinuation = latestContinuation; } nExts = ((descriptor->isExtension) ? nExts + 1 : 0); pc += (descriptor->numBytes); } return end; } /* This is a static version of ceEnterCogCodePopReceiverReg for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#enterCogCodePopReceiver */ void enterCogCodePopReceiver(void) { realCEEnterCogCodePopReceiverReg(); error("what??"); } /* Answer if the entryPoint's tag is expected to be a selector reference, as opposed to a class tag. */ /* Cogit>>#entryPointTagIsSelector: */ static sqInt NoDbgRegParms entryPointTagIsSelector(sqInt entryPoint) { return (entryPoint < methodZoneBase) || (((entryPoint & entryPointMask) == uncheckedEntryAlignment) || (((entryPoint & entryPointMask) == checkedEntryAlignment) && ((((((CogMethod *) (entryPoint - cmEntryOffset)))->cmType)) == CMOpenPIC))); } /* Use asserts to check if the ClosedPICPrototype is as expected from compileClosedPICPrototype, and can be updated as required via rewriteCPICCaseAt:tag:objRef:target:. If all asserts pass, answer 0, otherwise answer a bit mask identifying all the errors. */ /* self disassembleFrom: methodZoneBase + (self sizeof: CogMethod) to: methodZoneBase + closedPICSize */ /* Cogit>>#expectedClosedPICPrototype: */ static sqInt NoDbgRegParms expectedClosedPICPrototype(CogMethod *cPIC) { sqInt classTag; sqInt classTagPC; sqInt entryPoint; sqInt errors; sqInt i; sqInt methodObjPC; sqInt object; sqInt pc; errors = 0; /* First jump is unconditional; subsequent ones are conditional */ pc = (((usqInt)cPIC)) + firstCPICCaseOffset; object = literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */); if (!(asserta(object == (firstPrototypeMethodOop())))) { errors = 1; } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); if (!(asserta(entryPoint == ((cPICPrototypeCaseOffset()) + 13262352)))) { errors += 2; } for (i = 1; i < MaxCPICCases; i += 1) { /* verify information in case is as expected. */ pc += cPICCaseSize; methodObjPC = (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */; object = literalBeforeFollowingAddress(backEnd, methodObjPC); if (!(asserta(object == ((subsequentPrototypeMethodOop()) + i)))) { errors = errors | 4; } classTagPC = pc - (jumpLongConditionalByteSize(backEnd)); /* begin literal32BeforeFollowingAddress: */ classTag = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), classTagPC); if (!(asserta(classTag == (3133021973U + i)))) { errors = errors | 8; } /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (!(asserta(entryPoint == (((cPICPrototypeCaseOffset()) + 13262352) + (i * 16))))) { errors = errors | 16; } rewriteCPICCaseAttagobjReftarget(pc, classTag ^ 1515870810, object ^ 2779096485U, entryPoint ^ 5614160); object = literalBeforeFollowingAddress(backEnd, methodObjPC); if (!(asserta(object == (((subsequentPrototypeMethodOop()) + i) ^ 2779096485U)))) { errors = errors | 32; } /* begin literal32BeforeFollowingAddress: */ classTag = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), classTagPC); if (!(asserta(classTag == ((3133021973U + i) ^ 1515870810)))) { errors = errors | 64; } /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (!(asserta(entryPoint == ((((cPICPrototypeCaseOffset()) + 13262352) + (i * 16)) ^ 5614160)))) { errors = errors | 128; } rewriteCPICCaseAttagobjReftarget(pc, classTag ^ 1515870810, object ^ 2779096485U, entryPoint ^ 5614160); } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, (pc + cPICEndSize) - (endSizeOffset())); if (!(asserta(entryPoint == (cPICMissTrampolineFor(0))))) { errors += 256; } return errors; } /* 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev * 256 + Ext A) */ /* Cogit>>#extABytecode */ static sqInt extABytecode(void) { extA = (((usqInt) extA << 8)) + byte1; return 0; } /* 225 11100001 sbbbbbbb Extend B (Ext B = Ext B prev * 256 + Ext B) */ /* Cogit>>#extBBytecode */ static sqInt extBBytecode(void) { extB = ((numExtB == 0) && (byte1 > 0x7F) ? byte1 - 256 : (((usqInt) extB << 8)) + byte1); numExtB += 1; return 0; } /* Fill in the block headers now we know the exact layout of the code. */ /* Cogit>>#fillInBlockHeadersAt: */ static sqInt NoDbgRegParms fillInBlockHeadersAt(sqInt startAddress) { CogBlockMethod *blockHeader; BlockStart *blockStart; sqInt i; if (!(needsFrame && (blockCount > 0))) { return null; } if (blockNoContextSwitchOffset == null) { blockNoContextSwitchOffset = ((blockEntryLabel->address)) - ((blockEntryNoContextSwitch->address)); } else { assert(blockNoContextSwitchOffset == (((blockEntryLabel->address)) - ((blockEntryNoContextSwitch->address)))); } for (i = 0; i < blockCount; i += 1) { blockStart = blockStartAt(i); blockHeader = ((CogBlockMethod *) ((((blockStart->fakeHeader))->address))); (blockHeader->homeOffset = ((((blockStart->fakeHeader))->address)) - startAddress); (blockHeader->startpc = (blockStart->startpc)); (blockHeader->cmType = CMBlock); (blockHeader->cmNumArgs = (blockStart->numArgs)); (blockHeader->cbUsesInstVars = (blockStart->hasInstVarRef)); (blockHeader->stackCheckOffset = (((blockStart->stackCheckLabel)) == null ? 0 : ((((blockStart->stackCheckLabel))->address)) - ((((blockStart->fakeHeader))->address)))); } return 0; } /* Cogit>>#fillInMethodHeader:size:selector: */ static CogMethod * NoDbgRegParms fillInMethodHeadersizeselector(CogMethod *method, sqInt size, sqInt selector) { CogMethod *originalMethod; sqInt rawHeader; (method->cmType = CMMethod); (method->objectHeader = nullHeaderForMachineCodeMethod()); (method->blockSize = size); (method->methodObject = methodObj); /* If the method has already been cogged (e.g. Newspeak accessors) then leave the original method attached to its cog method, but get the right header. */ rawHeader = rawHeaderOf(methodObj); if (isCogMethodReference(rawHeader)) { originalMethod = ((CogMethod *) rawHeader); assert(((originalMethod->blockSize)) == size); assert(methodHeader == ((originalMethod->methodHeader))); } else { rawHeaderOfput(methodObj, ((sqInt)method)); } (method->methodHeader = methodHeader); (method->selector = selector); (method->cmNumArgs = argumentCountOfMethodHeader(methodHeader)); if ((method->cmRefersToYoung = hasYoungReferent)) { addToYoungReferrers(method); } (method->cmUsageCount = initialMethodUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) method))->cpicHasMNUCaseOrCMIsFullBlock) = 0; (method->cmUsesPenultimateLit = maxLitIndex >= ((literalCountOfMethodHeader(methodHeader)) - 2)); (method->blockEntryOffset = (blockEntryLabel != null ? ((blockEntryLabel->address)) - (((sqInt)method)) : 0)); if (needsFrame) { if (!((((stackCheckLabel->address)) - (((sqInt)method))) <= MaxStackCheckOffset)) { error("too much code for stack check offset"); } } (method->stackCheckOffset = (needsFrame ? ((stackCheckLabel->address)) - (((sqInt)method)) : 0)); assert((callTargetFromReturnAddress(backEnd, (((sqInt)method)) + missOffset)) == (methodAbortTrampolineFor((method->cmNumArgs)))); assert(size == (roundUpLength(size))); flushICacheFromto(processor, ((usqInt)method), (((usqInt)method)) + size); /* begin maybeEnableSingleStep */ return method; } /* Cogit>>#findBackwardBranch:IsBackwardBranch:Mcpc:Bcpc:MatchingBcpc: */ static sqInt NoDbgRegParms findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetBcpc) { return ((isBackwardBranchAndAnnotation & 1) && ((((sqInt)targetBcpc)) == bcpc) ? ((sqInt)mcpc) : 0); } /* Cogit>>#findBlockMethodWithEntry:startBcpc: */ static usqInt NoDbgRegParms findBlockMethodWithEntrystartBcpc(sqInt blockEntryMcpc, sqInt startBcpc) { CogBlockMethod *cogBlockMethod; cogBlockMethod = ((CogBlockMethod *) (blockEntryMcpc - (sizeof(CogBlockMethod)))); if (((cogBlockMethod->startpc)) == startBcpc) { return ((usqInt)cogBlockMethod); } return 0; } /* Cogit>>#findMapLocationForMcpc:inMethod: */ static sqInt NoDbgRegParms findMapLocationForMcpcinMethod(usqInt targetMcpc, CogMethod *cogMethod) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; if (mcpc == targetMcpc) { return map; } while (((mapByte = byteAt(map))) != MapEnd) { annotation = ((usqInt) mapByte) >> AnnotationShift; if (annotation != IsAnnotationExtension) { mcpc += 4 /* codeGranularity */ * ((annotation == IsDisplacementX2N ? ((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift)) : mapByte & DisplacementMask)); } if (mcpc >= targetMcpc) { assert(mcpc == targetMcpc); if (annotation == IsDisplacementX2N) { map -= 1; mapByte = byteAt(map); annotation = ((usqInt) mapByte) >> AnnotationShift; assert(annotation > IsAnnotationExtension); } return map; } map -= 1; } return 0; } /* Find the CMMethod or CMBlock that has zero-relative startbcpc as its first bytecode pc. As this is for cannot resume processing and/or conversion to machine-code on backward branch, it doesn't have to be fast. Enumerate block returns and map to bytecode pcs. */ /* Cogit>>#findMethodForStartBcpc:inHomeMethod: */ CogBlockMethod * findMethodForStartBcpcinHomeMethod(sqInt startbcpc, CogMethod *cogMethod) { assert(((cogMethod->cmType)) == CMMethod); if (startbcpc == (startPCOfMethodHeader((cogMethod->methodHeader)))) { return ((CogBlockMethod *) cogMethod); } assert(((cogMethod->blockEntryOffset)) != 0); return ((CogBlockMethod *) (blockDispatchTargetsForperformarg(cogMethod, findBlockMethodWithEntrystartBcpc, startbcpc))); } /* Machine code addresses map to the following bytecode for all bytecodes except backward branches, where they map to the backward branch itself. This is so that loops continue, rather than terminate prematurely. */ /* Cogit>>#find:IsBackwardBranch:Mcpc:Bcpc:MatchingMcpc: */ static sqInt NoDbgRegParms findIsBackwardBranchMcpcBcpcMatchingMcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetMcpc) { return (targetMcpc == mcpc ? ((descriptor == null) || (isBackwardBranchAndAnnotation & 1) ? bcpc : bcpc + ((descriptor->numBytes))) : 0); } /* Cogit>>#firstMappedPCFor: */ static sqInt NoDbgRegParms firstMappedPCFor(CogMethod *cogMethod) { return ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); } /* Answer a fake value for the first method oop in the PIC prototype. Since we use MoveUniqueCw:R: it must not be confused with a method-relative address. */ /* Cogit>>#firstPrototypeMethodOop */ static sqInt firstPrototypeMethodOop(void) { return (((((usqInt)99282957)) >= ((methodLabel->address))) && ((((usqInt)99282957)) < (youngReferrers())) ? 212332557 : 99282957); } /* Cogit>>#fixupAt: */ static BytecodeFixup * NoDbgRegParms fixupAt(sqInt fixupPC) { return fixupAtIndex(fixupPC - initialPC); } /* Cogit>>#followForwardedLiteralsIn: */ void followForwardedLiteralsIn(CogMethod *cogMethod) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; assert((((cogMethod->cmType)) != CMMethod) || (!(isForwarded((cogMethod->methodObject))))); if (shouldRemapOop((cogMethod->selector))) { (cogMethod->selector = remapObj((cogMethod->selector))); if (isYoung((cogMethod->selector))) { ensureInYoungReferrers(cogMethod); } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#followForwardedMethods */ void followForwardedMethods(void) { CogMethod *cogMethod; sqInt freedPIC; freedPIC = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { if (isForwarded((cogMethod->methodObject))) { (cogMethod->methodObject = followForwarded((cogMethod->methodObject))); if (isYoungObject((cogMethod->methodObject))) { ensureInYoungReferrers(cogMethod); } } } if (((cogMethod->cmType)) == CMClosedPIC) { if (followMethodReferencesInClosedPIC(cogMethod)) { freedPIC = 1; freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedPIC) { unlinkSendsToFree(); } } /* Follow a potential object reference from a closed PIC. This may be a method reference or null. Answer if the followed literal is young. 'mcpc' refers to the jump/branch instruction at the end of each cpic case */ /* Cogit>>#followMaybeObjRefInClosedPICAt: */ static sqInt NoDbgRegParms followMaybeObjRefInClosedPICAt(sqInt mcpc) { sqInt object; sqInt subject; object = literalBeforeFollowingAddress(backEnd, mcpc); if (!(couldBeObject(object))) { return 0; } if (!(isForwarded(object))) { return isYoungObject(object); } subject = followForwarded(object); storeLiteralbeforeFollowingAddress(backEnd, subject, mcpc); codeModified = 1; return isYoungObject(subject); } /* Remap all object references in the closed PIC. Answer if any references are young. Set codeModified if any modifications are made. */ /* Cogit>>#followMethodReferencesInClosedPIC: */ static sqInt NoDbgRegParms followMethodReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt pc; sqInt refersToYoung; /* first we check the potential method oop load at the beginning of the CPIC */ pc = addressOfEndOfCaseinCPIC(1, cPIC); /* We find the end address of the cPICNumCases'th case and can then just step forward by the case size thereafter */ refersToYoung = followMaybeObjRefInClosedPICAt(pc - 4 /* jumpLongByteSize */); /* Next we check the potential potential method oop load for each case. */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (followMaybeObjRefInClosedPICAt((pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)) { refersToYoung = 1; } pc += cPICCaseSize; } return refersToYoung; } /* Free machine-code methods whose compiled methods are unmarked and open PICs whose selectors are not marked, and closed PICs that refer to unmarked objects. */ /* Cogit>>#freeUnmarkedMachineCode */ void freeUnmarkedMachineCode(void) { CogMethod *cogMethod; sqInt freedMethod; freedMethod = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (!(isMarked((cogMethod->methodObject))))) { freedMethod = 1; freeMethod(cogMethod); } if ((((cogMethod->cmType)) == CMOpenPIC) && ((!(isImmediate((cogMethod->selector)))) && (!(isMarked((cogMethod->selector)))))) { freedMethod = 1; freeMethod(cogMethod); } if ((((cogMethod->cmType)) == CMClosedPIC) && (closedPICRefersToUnmarkedObject(cogMethod))) { freedMethod = 1; freeMethod(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedMethod) { unlinkSendsToFree(); } } /* Call ceSendMustBeBooleanTo: via the relevant trampoline. */ /* Cogit>>#genCallMustBeBooleanFor: */ static AbstractInstruction * NoDbgRegParms genCallMustBeBooleanFor(sqInt boolean) { AbstractInstruction *abstractInstruction; sqInt callTarget; /* begin CallRT: */ callTarget = (boolean == (falseObject()) ? ceSendMustBeBooleanAddFalseTrampoline : ceSendMustBeBooleanAddTrueTrampoline); /* begin annotateCall: */ abstractInstruction = genoperand(Call, callTarget); (abstractInstruction->annotation = IsRelativeCall); return abstractInstruction; } /* Cogit>>#genCheckForInterruptsTrampoline */ static sqInt genCheckForInterruptsTrampoline(void) { sqInt address; zeroOpcodeIndex(); /* begin MoveR:Aw: */ address = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, LinkReg, address)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceCheckForInterrupts, "ceCheckForInterruptsTrampoline", 0, null, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Cogit>>#genConditionalBranch:operand: */ static AbstractInstruction * NoDbgRegParms genConditionalBranchoperand(sqInt opcode, sqInt operandOne) { AbstractInstruction *branch; /* begin noteFollowingConditionalBranch: */ branch = genoperand(opcode, operandOne); return branch; } /* 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. BEFORE AFTER (stacks grow down) whatever stackPointer -> whatever target address => reg1 = reg1val, etc reg1val pc = target address reg2val stackPointer -> reg3val */ /* Cogit>>#genEnilopmartFor:and:and:forCall:called: */ static void (*genEnilopmartForandandforCallcalled(sqInt regArg1, sqInt regArg2OrNone, sqInt regArg3OrNone, sqInt forCall, char *trampolineName))(void) { AbstractInstruction *anInstruction; sqInt endAddress; sqInt enilopmart; sqInt quickConstant; sqInt size; zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } genLoadStackPointers(backEnd); if (regArg3OrNone != NoReg) { genoperand(PopR, regArg3OrNone); } if (regArg2OrNone != NoReg) { genoperand(PopR, regArg2OrNone); } genoperand(PopR, regArg1); genEnilopmartReturn(forCall); computeMaximumSizes(); size = generateInstructionsAt(methodZoneBase); endAddress = outputInstructionsAt(methodZoneBase); assert((methodZoneBase + size) == endAddress); enilopmart = methodZoneBase; methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(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. At the point the enilopmart enters machine code via a return instruction, any argument registers have been loaded with their values and the stack, if for call, looks like ret pc stackPointer -> target address and if not for call, looks like whatever stackPointer -> target address If forCall and running on a CISC, ret pc must be left on the stack. If forCall and running on a RISC, ret pc must be popped into LinkReg. In either case, target address must be removed from the stack and jumped/returned to. */ /* Cogit>>#genEnilopmartReturn: */ static void NoDbgRegParms genEnilopmartReturn(sqInt forCall) { if (forCall) { genoperand(PopR, RISCTempReg); genoperand(PopR, LinkReg); genoperand(JumpR, RISCTempReg); } else { genoperand(PopR, PCReg); } } /* Generate the routine that writes the current values of the C frame and stack pointers into variables. These are used to establish the C stack in trampolines back into the C run-time. This is a presumptuous quick hack for x86. It is presumptuous for two reasons. Firstly the system's frame and stack pointers may differ from those we use in generated code, e.g. on register-rich RISCs. Secondly the ABI may not support a simple frameless call as written here (for example 128-bit stack alignment on Mac OS X). */ /* Cogit>>#generateCaptureCStackPointers: */ static void NoDbgRegParms generateCaptureCStackPointers(sqInt captureFramePointer) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt fixupSize; sqInt opcodeSize; sqInt quickConstant; sqInt quickConstant1; sqInt startAddress; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 32; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; /* Must happen first; value may be used in accessing any of the following addresses */ startAddress = methodZoneBase; /* begin PushR: */ genoperand(PushR, VarBaseReg); /* begin MoveCq:R: */ quickConstant1 = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant1, VarBaseReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } if (captureFramePointer) { /* begin MoveR:Aw: */ address = cFramePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, FPReg, address)); } genoperandoperand(MoveRR, SPReg, TempReg); /* begin AddCq:R: */ quickConstant = 0 /* leafCallStackPointerDelta */ + BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin MoveR:Aw: */ address1 = cStackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin PopR: */ genoperand(PopR, VarBaseReg); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); flushICacheFromto(processor, ((usqInt)startAddress), ((usqInt)methodZoneBase)); recordGeneratedRunTimeaddress("ceCaptureCStackPointers", startAddress); ceCaptureCStackPointers = ((void (*)(void)) startAddress); } /* Generate the prototype ClosedPIC to determine how much space as full PIC takes. When we first allocate a closed PIC it only has one or two cases and we want to grow it. So we have to determine how big a full one is before hand. */ /* Cogit>>#generateClosedPICPrototype */ static void generateClosedPICPrototype(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; CogMethod *cPIC; AbstractInstruction * cPICEndOfCodeLabel; sqInt endAddress; AbstractInstruction * endCPICCase1; sqInt fixupSize; sqInt h; AbstractInstruction *jumpNext; sqInt jumpTarget; sqInt jumpTarget1; sqInt jumpTarget2; sqInt numArgs; sqInt opcode; sqInt opcodeSize; sqInt operandOne; sqInt wordConstant; sqInt wordConstant1; /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = MaxCPICCases * 9; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; (methodLabel->address = methodZoneBase); (methodLabel->dependent = null); /* begin compileClosedPICPrototype */ compilePICAbort((numArgs = 0)); /* At the end of the entry code we need to jump to the first case code, which is actually the last chunk. On each entension we must update this jump to move back one case. */ jumpNext = compileCPICEntry(); /* begin MoveUniqueCw:R: */ wordConstant1 = firstPrototypeMethodOop(); /* begin uniqueLiteral:forInstruction: */ anInstruction1 = genoperandoperand(MoveCwR, wordConstant1, SendNumArgsReg); assert(usesOutOfLineLiteral(anInstruction1)); (anInstruction1->dependent = allocateLiteral(wordConstant1)); /* begin JumpLong: */ jumpTarget1 = (((methodZoneBase + (youngReferrers())) / 2) - 13262352) + 13262352; genoperand(JumpLong, jumpTarget1); endCPICCase0 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); for (h = 1; h < MaxCPICCases; h += 1) { if (h == (MaxCPICCases - 1)) { jmpTarget(jumpNext, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin MoveUniqueCw:R: */ wordConstant = (subsequentPrototypeMethodOop()) + h; /* begin uniqueLiteral:forInstruction: */ anInstruction = genoperandoperand(MoveCwR, wordConstant, SendNumArgsReg); assert(usesOutOfLineLiteral(anInstruction)); (anInstruction->dependent = allocateLiteral(wordConstant)); /* begin gen:literal:operand: */ opcode = CmpCwR; checkLiteralforInstruction(3133021973U + h, genoperandoperand(opcode, 3133021973U + h, TempReg)); /* begin JumpLongZero: */ jumpTarget = ((((methodZoneBase + (youngReferrers())) / 2) - 13262352) + 13262352) + (h * 16); genConditionalBranchoperand(JumpLongZero, ((sqInt)jumpTarget)); if (h == 1) { endCPICCase1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } } /* begin gen:literal:operand: */ operandOne = (methodLabel->address); checkLiteralforInstruction(operandOne, genoperandoperand(MoveCwR, operandOne, ClassReg)); /* begin JumpLong: */ jumpTarget2 = cPICMissTrampolineFor(numArgs); genoperand(JumpLong, jumpTarget2); cPICEndOfCodeLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); dumpLiterals(0); computeMaximumSizes(); cPIC = ((CogMethod *) methodZoneBase); closedPICSize = (sizeof(CogMethod)) + (generateInstructionsAt(methodZoneBase + (sizeof(CogMethod)))); endAddress = outputInstructionsAt(methodZoneBase + (sizeof(CogMethod))); assert((methodZoneBase + closedPICSize) == endAddress); firstCPICCaseOffset = ((endCPICCase0->address)) - methodZoneBase; cPICEndOfCodeOffset = ((cPICEndOfCodeLabel->address)) - methodZoneBase; cPICCaseSize = ((endCPICCase1->address)) - ((endCPICCase0->address)); cPICEndSize = closedPICSize - (((MaxCPICCases - 1) * cPICCaseSize) + firstCPICCaseOffset); closedPICSize = roundUpLength(closedPICSize); assert(((picInterpretAbort->address)) == (((methodLabel->address)) + (picInterpretAbortOffset()))); assert((expectedClosedPICPrototype(cPIC)) == 0); storeLiteralbeforeFollowingAddress(backEnd, 0, ((endCPICCase0->address)) - 4 /* jumpLongByteSize */); methodZoneBase = alignUptoRoutineBoundary(endAddress); cPICPrototype = cPIC; } /* We handle jump sizing simply. First we make a pass that asks each instruction to compute its maximum size. Then we make a pass that sizes jumps based on the maxmimum sizes. Then we make a pass that fixes up jumps. When fixing up a jump the jump is not allowed to choose a smaller offset but must stick to the size set in the second pass. */ /* Cogit>>#generateCogFullBlock */ static CogMethod * generateCogFullBlock(void) { sqInt codeSize; usqIntptr_t headerSize; sqInt mapSize; CogMethod *method; sqInt result; usqInt startAddress; sqInt totalSize; headerSize = sizeof(CogMethod); (methodLabel->address = freeStart()); computeMaximumSizes(); concretizeAt(methodLabel, freeStart()); codeSize = generateInstructionsAt(((methodLabel->address)) + headerSize); mapSize = generateMapAtstart(null, ((methodLabel->address)) + cbNoSwitchEntryOffset); totalSize = roundUpLength((headerSize + codeSize) + mapSize); if (totalSize > MaxMethodSize) { return ((CogMethod *) MethodTooBig); } startAddress = allocate(totalSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } assert((startAddress + cbEntryOffset) == ((fullBlockEntry->address))); assert((startAddress + cbNoSwitchEntryOffset) == ((fullBlockNoContextSwitchEntry->address))); result = outputInstructionsAt(startAddress + headerSize); assert(((startAddress + headerSize) + codeSize) == result); padIfPossibleWithStopsFromto(backEnd, result, ((startAddress + totalSize) - mapSize) - 1); generateMapAtstart((startAddress + totalSize) - 1, startAddress + cbNoSwitchEntryOffset); flag("TOCHECK"); method = fillInMethodHeadersizeselector(((CogMethod *) startAddress), totalSize, nilObject()); (method->cpicHasMNUCaseOrCMIsFullBlock = 1); if (!(postCompileHook == null)) { postCompileHook(method); postCompileHook = null; } return method; } /* We handle jump sizing simply. First we make a pass that asks each instruction to compute its maximum size. Then we make a pass that sizes jumps based on the maxmimum sizes. Then we make a pass that fixes up jumps. When fixing up a jump the jump is not allowed to choose a smaller offset but must stick to the size set in the second pass. */ /* Cogit>>#generateCogMethod: */ static CogMethod * NoDbgRegParms generateCogMethod(sqInt selector) { sqInt codeSize; usqIntptr_t headerSize; sqInt mapSize; CogMethod *method; sqInt result; usqInt startAddress; sqInt totalSize; headerSize = sizeof(CogMethod); (methodLabel->address = freeStart()); computeMaximumSizes(); concretizeAt(methodLabel, freeStart()); codeSize = generateInstructionsAt(((methodLabel->address)) + headerSize); mapSize = generateMapAtstart(null, ((methodLabel->address)) + cmNoCheckEntryOffset); totalSize = roundUpLength((headerSize + codeSize) + mapSize); if (totalSize > MaxMethodSize) { return ((CogMethod *) MethodTooBig); } startAddress = allocate(totalSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } assert((startAddress + cmEntryOffset) == ((entry->address))); assert((startAddress + cmNoCheckEntryOffset) == ((noCheckEntry->address))); result = outputInstructionsAt(startAddress + headerSize); assert(((startAddress + headerSize) + codeSize) == result); padIfPossibleWithStopsFromto(backEnd, result, ((startAddress + totalSize) - mapSize) - 1); generateMapAtstart((startAddress + totalSize) - 1, startAddress + cmNoCheckEntryOffset); fillInBlockHeadersAt(startAddress); method = fillInMethodHeadersizeselector(((CogMethod *) startAddress), totalSize, selector); if (!(postCompileHook == null)) { postCompileHook(method); postCompileHook = null; } return method; } /* Generate the method map at addressrNull (or compute it if addressOrNull is null). Answer the length of the map in byes. Each entry in the map is in two parts. In the least signficant bits are a displacement of how far from the start or previous entry, unless it is an IsAnnotationExtension byte, in which case those bits are the extension. In the most signficant bits are the type of annotation at the point reached. A null byte ends the map. */ /* Cogit>>#generateMapAt:start: */ static sqInt NoDbgRegParms generateMapAtstart(usqInt addressOrNull, usqInt startAddress) { unsigned char annotation; sqInt delta; sqInt i; AbstractInstruction *instruction; sqInt length; usqInt location; sqInt mapEntry; sqInt maxDelta; usqInt mcpc; length = 0; location = startAddress; for (i = 0; i < opcodeIndex; i += 1) { instruction = abstractInstructionAt(i); annotation = (instruction->annotation); if (!(annotation == null)) { /* begin assertValidAnnotation:for: */ assert((annotation != (getIsObjectReference())) || (((instruction->opcode)) == Literal)); mcpc = (((instruction->opcode)) == Literal ? (instruction->address) : ((instruction->address)) + ((instruction->machineCodeSize))); while (((delta = (mcpc - location) / 4 /* codeGranularity */)) > DisplacementMask) { maxDelta = (((((delta < MaxX2NDisplacement) ? delta : MaxX2NDisplacement)) | DisplacementMask) - DisplacementMask); assert((((usqInt) maxDelta) >> AnnotationShift) <= DisplacementMask); if (!(addressOrNull == null)) { /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, (((usqInt) maxDelta) >> AnnotationShift) + DisplacementX2N); } location += maxDelta * 4 /* codeGranularity */; length += 1; } if (!(addressOrNull == null)) { mapEntry = delta + (((sqInt)((usqInt)((((annotation < IsSendCall) ? annotation : IsSendCall))) << AnnotationShift))); /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, mapEntry); } location += delta * 4 /* codeGranularity */; length += 1; if (annotation > IsSendCall) { /* Add the necessary IsAnnotationExtension */ if (!(addressOrNull == null)) { mapEntry = (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift))) + (annotation - IsSendCall); /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, mapEntry); } length += 1; } } } if (!(addressOrNull == null)) { /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, MapEnd); } return length + 1; } /* Generate the prototype ClosedPIC to determine how much space as full PIC takes. When we first allocate a closed PIC it only has one or two cases and we want to grow it. So we have to determine how big a full one is before hand. */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#generateOpenPICPrototype */ static void generateOpenPICPrototype(void) { sqInt codeSize; sqInt fixupSize; sqInt mapSize; sqInt opcodeSize; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 100; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; (methodLabel->address = methodZoneBase); (methodLabel->dependent = null); compileOpenPICnumArgs(specialSelector(0), 2 /* numRegArgs */); computeMaximumSizes(); concretizeAt(methodLabel, methodZoneBase); codeSize = generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); mapSize = generateMapAtstart(null, methodZoneBase + cmNoCheckEntryOffset); openPICSize = (roundUpLength((sizeof(CogMethod)) + codeSize)) + (roundUpLength(mapSize)); } /* Generate the run-time entries at the base of the native code zone and update the base. */ /* Cogit>>#generateRunTimeTrampolines */ static void generateRunTimeTrampolines(void) { ceSendMustBeBooleanAddFalseTrampoline = genMustBeBooleanTrampolineForcalled(falseObject(), "ceSendMustBeBooleanAddFalseTrampoline"); ceSendMustBeBooleanAddTrueTrampoline = genMustBeBooleanTrampolineForcalled(trueObject(), "ceSendMustBeBooleanAddTrueTrampoline"); ceNonLocalReturnTrampoline = genNonLocalReturnTrampoline(); /* Neither of the context inst var access trampolines save registers. Their operation could cause arbitrary update of stack frames, so the assumption is that callers flush the stack before calling the context inst var access trampolines, and that everything except the result is dead afterwards. */ ceCheckForInterruptTrampoline = genCheckForInterruptsTrampoline(); ceFetchContextInstVarTrampoline = genTrampolineForcalledargargresult(ceContextinstVar, "ceFetchContextInstVarTrampoline", ReceiverResultReg, SendNumArgsReg, SendNumArgsReg); ceStoreContextInstVarTrampoline = genTrampolineForcalledargargargresult(ceContextinstVarvalue, "ceStoreContextInstVarTrampoline", ReceiverResultReg, SendNumArgsReg, ClassReg, ReceiverResultReg); /* These two are unusual; they are reached by return instructions. */ ceCannotResumeTrampoline = genTrampolineForcalled(ceCannotResume, "ceCannotResumeTrampoline"); ceBaseFrameReturnTrampoline = genReturnTrampolineForcalledarg(ceBaseFrameReturn, "ceBaseFrameReturnTrampoline", ReceiverResultReg); ceReturnToInterpreterTrampoline = genReturnTrampolineForcalledarg(ceReturnToInterpreter, "ceReturnToInterpreterTrampoline", ReceiverResultReg); ceMallocTrampoline = genTrampolineForcalledargresult(ceMalloc, "ceMallocTrampoline", ReceiverResultReg, TempReg); ceFreeTrampoline = genTrampolineForcalledarg(ceFree, "ceFreeTrampoline", ReceiverResultReg); } /* Generate a routine ceCaptureCStackPointers that will capture the C stack pointer, and, if it is in use, the C frame pointer. These are used in trampolines to call run-time routines in the interpreter from machine-code. */ /* Cogit>>#generateStackPointerCapture */ static void generateStackPointerCapture(void) { sqInt oldMethodZoneBase; sqInt oldTrampolineTableIndex; /* For the benefit of the following assert, assume the minimum at first. */ cFramePointerInUse = 0; assertCStackWellAligned(); oldMethodZoneBase = methodZoneBase; oldTrampolineTableIndex = trampolineTableIndex; generateCaptureCStackPointers(1); ceCaptureCStackPointers(); if (!((cFramePointerInUse = isCFramePointerInUse()))) { methodZoneBase = oldMethodZoneBase; trampolineTableIndex = oldTrampolineTableIndex; generateCaptureCStackPointers(0); } assertCStackWellAligned(); } /* Generate the run-time entries and exits at the base of the native code zone and update the base. Read the class-side method trampolines for documentation on the various trampolines */ /* Cogit>>#generateTrampolines */ static void generateTrampolines(void) { sqInt fixupSize; sqInt methodZoneStart; sqInt opcodeSize; methodZoneStart = methodZoneBase; (methodLabel->address = methodZoneStart); /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 80; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; hasYoungReferent = 0; generateSendTrampolines(); generateMissAbortTrampolines(); generateObjectRepresentationTrampolines(); generateRunTimeTrampolines(); generateEnilopmarts(); generateTracingTrampolines(); recordGeneratedRunTimeaddress("methodZoneBase", methodZoneBase); flushICacheFromto(processor, ((usqInt)methodZoneStart), ((usqInt)methodZoneBase)); } /* Cogit>>#generatorForPC: */ static BytecodeDescriptor * NoDbgRegParms generatorForPC(sqInt pc) { return generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); } /* Generate a routine that answers the stack pointer immedately after a leaf call, used for checking stack pointer alignment. */ /* Cogit>>#genGetLeafCallStackPointer */ static void genGetLeafCallStackPointer(void) { sqInt fixupSize; sqInt opcodeSize; sqInt startAddress; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 4; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; startAddress = methodZoneBase; /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, R0); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceGetFP", startAddress); ceGetFP = ((usqIntptr_t (*)(void)) startAddress); startAddress = methodZoneBase; zeroOpcodeIndex(); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, R0); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceGetSP", startAddress); ceGetSP = ((usqIntptr_t (*)(void)) startAddress); } /* Generate the abort for a PIC. This abort performs either a call of ceInterpretMethodFromPIC:receiver: to handle invoking an uncogged target or a call of ceMNUFromPICMNUMethod:receiver: to handle an MNU dispatch in a closed PIC. It distinguishes the two by testing ClassReg. If the register is zero then this is an MNU. This poses a problem in 32-bit Spur, where zero is the cache tag for immediate characters (tag pattern 2r10) because SmallIntegers have tag patterns 2r11 and 2r01, so anding with 1 reduces these to 0 & 1. We solve the ambiguity by patching send sites with a 0 cache tag to open PICs instead of closed PICs. */ /* Cogit>>#genInnerPICAbortTrampoline: */ static sqInt NoDbgRegParms genInnerPICAbortTrampoline(char *name) { AbstractInstruction *anInstruction; AbstractInstruction *jumpMNUCase; /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, 0 /* picAbortDiscriminatorValue */, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0 /* picAbortDiscriminatorValue */)); } jumpMNUCase = genConditionalBranchoperand(JumpZero, ((sqInt)0)); compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceInterpretMethodFromPICreceiver, 2, SendNumArgsReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 0, NoReg); jmpTarget(jumpMNUCase, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceMNUFromPICMNUMethodreceiver, name, 2, SendNumArgsReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Cogit>>#genLoadCStackPointersForPrimCall */ static sqInt genLoadCStackPointersForPrimCall(void) { sqInt address; sqInt address1; sqInt address2; AbstractInstruction *anInstruction; if (debugPrimCallStackOffset == 0) { /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); } else { /* begin MoveAw:R: */ address1 = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, debugPrimCallStackOffset, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(debugPrimCallStackOffset)); } genoperandoperand(MoveRR, TempReg, SPReg); } if (cFramePointerInUse) { /* begin MoveAw:R: */ address2 = cFramePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address2, genoperandoperand(MoveAwR, address2, FPReg)); } return 0; } /* The in-line cache for a send is implemented as a constant load into ClassReg. We always use a 32-bit load, even in 64-bits. In the initial (unlinked) state the in-line cache is notionally loaded with the selector. But since in 64-bits an arbitrary selector oop won't fit in a 32-bit constant load, we instead load the cache with the selector's index, either into the literal frame of the current method, or into the special selector array. Negative values are 1-relative indices into the special selector array. When a send is linked, the load of the selector, or selector index, is overwritten with a load of the receiver's class, or class tag. Hence, the 64-bit VM is currently constrained to use class indices as cache tags. If out-of-line literals are used, distinct caches /must not/ share acche locations, for if they do, send cacheing will be confused by the sharing. Hence we use the MoveUniqueC32:R: instruction that will not share literal locations. */ /* Cogit>>#genLoadInlineCacheWithSelector: */ static void NoDbgRegParms genLoadInlineCacheWithSelector(sqInt selectorIndex) { AbstractInstruction *anInstruction; sqInt cacheValue; sqInt opcode; sqInt selector; assert((selectorIndex < 0 ? (((-selectorIndex) >= 1) && ((-selectorIndex) <= (numSpecialSelectors()))) : ((selectorIndex >= 0) && (selectorIndex <= ((literalCountOf(methodObj)) - 1))))); selector = (selectorIndex < 0 ? specialSelector(-1 - selectorIndex) : getLiteral(selectorIndex)); assert(addressCouldBeOop(selector)); if (isYoung(selector)) { hasYoungReferent = 1; } cacheValue = selector; /* begin gen:uniqueLiteral:operand: */ opcode = MoveCwR; /* begin uniqueLiteral:forInstruction: */ anInstruction = genoperandoperand(opcode, cacheValue, ClassReg); assert(usesOutOfLineLiteral(anInstruction)); (anInstruction->dependent = allocateLiteral(cacheValue)); } /* Cogit>>#genNonLocalReturnTrampoline */ static sqInt genNonLocalReturnTrampoline(void) { sqInt address; zeroOpcodeIndex(); /* begin MoveR:Aw: */ address = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, LinkReg, address)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceNonLocalReturn, "ceNonLocalReturnTrampoline", 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Generate a trampoline for a routine used as a return address, that has one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genReturnTrampolineFor:called:arg: */ static sqInt NoDbgRegParms genReturnTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 0); } /* If the client requires, then on an ARM-like RISC processor, the return address needs to be pushed to the stack so that the interpreter sees the same stack layout as on CISC. */ /* Cogit>>#genSmalltalkToCStackSwitch: */ static sqInt NoDbgRegParms genSmalltalkToCStackSwitch(sqInt pushLinkReg) { if (pushLinkReg) { genoperand(PushR, LinkReg); } genSaveStackPointers(backEnd); if (cFramePointerInUse) { genLoadCStackPointers(backEnd); } else { genLoadCStackPointer(backEnd); } return 0; } /* Generate a trampoline with no arguments */ /* Cogit>>#genTrampolineFor:called: */ static sqInt NoDbgRegParms genTrampolineForcalled(void *aRoutine, char *aString) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 0, null, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 0); } /* Generate a trampoline with one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg: */ static sqInt NoDbgRegParms genTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 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. */ /* Cogit>>#genTrampolineFor:called:arg:arg:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 3, regOrConst0, regOrConst1, regOrConst2, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with two arguments. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:arg:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledargargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 2, regOrConst0, regOrConst1, null, null, regMask, 1, NoReg, 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. */ /* Cogit>>#genTrampolineFor:called:arg:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 2, regOrConst0, regOrConst1, null, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, regMask, 1, NoReg, 0); } /* Generate a trampoline with one argument that answers a result. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with up to four arguments. Generate either a call or a jump to aRoutineOrNil as requested by callJumpBar. If generating a call and resultRegOrNone is not NoReg pass the C result back in resultRegOrNone. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg:appendOpcodes: */ static sqInt NoDbgRegParms genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(void *aRoutine, char *trampolineName, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone, sqInt appendBoolean) { sqInt startAddress; startAddress = methodZoneBase; if (!appendBoolean) { zeroOpcodeIndex(); } compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(aRoutine, numArgs, regOrConst0, regOrConst1, regOrConst2, regOrConst3, regMask, pushLinkReg, resultRegOrNone); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress(trampolineName, startAddress); recordRunTimeObjectReferences(); return startAddress; } /* Generate a trampoline with no arguments */ /* Cogit>>#genTrampolineFor:called:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledregsToSave(void *aRoutine, char *aString, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 0, null, null, null, null, regMask, 1, NoReg, 0); } /* <Integer> */ /* Cogit>>#gen: */ static AbstractInstruction * NoDbgRegParms gen(sqInt opcode) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand: */ static AbstractInstruction * NoDbgRegParms genoperand(sqInt opcode, sqInt operand) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operand; return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand:operand: */ static AbstractInstruction * NoDbgRegParms genoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operandOne; ((abstractInstruction->operands))[1] = operandTwo; return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand:operand:operand: */ static AbstractInstruction * NoDbgRegParms genoperandoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo, sqInt operandThree) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operandOne; ((abstractInstruction->operands))[1] = operandTwo; ((abstractInstruction->operands))[2] = operandThree; return abstractInstruction; } /* Cogit>>#getLiteral: */ static sqInt NoDbgRegParms getLiteral(sqInt litIndex) { if (maxLitIndex < litIndex) { maxLitIndex = litIndex; } return literalofMethod(litIndex, methodObj); } /* Access for the literal manager. */ /* Cogit>>#getOpcodeIndex */ static sqInt getOpcodeIndex(void) { return opcodeIndex; } /* Cogit>>#incrementUsageOfTargetIfLinkedSend:mcpc:ignored: */ static sqInt NoDbgRegParms incrementUsageOfTargetIfLinkedSendmcpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; if (annotation >= IsSendCall) { assert(annotation != IsNSSendCall); entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmUsageCount)) < (CMMaxUsageCount / 2)) { (targetMethod1->cmUsageCount = ((targetMethod1->cmUsageCount)) + 1); } } } return 0; } /* Answer the value to put in an inline-cache that is being loaded with the selector. Usually this is simply the selector, but in 64-bits the cache is only 32-bits wide and so the cache is loaded with the index of the selector. */ /* Cogit>>#indexForSelector:in:at: */ static sqInt NoDbgRegParms indexForSelectorinat(sqInt selector, CogMethod *cogMethod, sqInt mcpc) { sqInt i; sqInt iLimiT; sqInt methodOop; assert(((((usqInt)mcpc)) > (((usqInt)cogMethod))) && (mcpc < ((((usqInt)cogMethod)) + ((cogMethod->blockSize))))); for (i = 0; i < NumSpecialSelectors; i += 1) { if (selector == (specialSelector(i))) { return -1 - i; } } /* Then search the method's literal frame... open code fetchPointer:ofObject: for speed... */ methodOop = (cogMethod->methodObject); for (i = LiteralStart, iLimiT = (literalCountOfMethodHeader((cogMethod->methodHeader))); i <= iLimiT; i += 1) { if ((longAt(((i * BytesPerOop) + BaseHeaderSize) + methodOop)) == selector) { assert(selector == (literalofMethod(i - 1, methodOop))); return i - 1; } } error("could not find selector in method when unlinking send site"); return 0; } /* Answer a usage count that reflects likely long-term usage. */ /* Cogit>>#initialClosedPICUsageCount */ static sqInt initialClosedPICUsageCount(void) { return CMMaxUsageCount / 2; } /* Cogit>>#initializeBackend */ static void initializeBackend(void) { AbstractInstruction *existingInst; sqInt i; sqInt iLimiT; AbstractInstruction *newInst; AbstractInstruction *newLiterals; (methodLabel->machineCodeSize = 0); (methodLabel->opcode = Label); ((methodLabel->operands))[0] = 0; ((methodLabel->operands))[1] = 0; assert(((registerMaskFor(VarBaseReg)) & CallerSavedRegisterMask) == 0); /* begin allocateLiterals: */ if (4 > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(4, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i = 0; i < nextLiteralIndex; i += 1) { existingInst = literalInstructionAt(i); newInst = (&(newLiterals[i])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i = 0, iLimiT = (opcodeIndex - 1); i <= iLimiT; i += 1) { existingInst = abstractInstructionAt(i); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = 4; } /* begin resetLiterals */ /* an impossibly high value */ firstOpcodeIndex = 1U << 16; nextLiteralIndex = (lastDumpedLiteralIndex = 0); } /* Cogit>>#initializeCodeZoneFrom:upTo: */ void initializeCodeZoneFromupTo(sqInt startAddress, sqInt endAddress) { sqInt fixupSize; sqInt numberOfAbstractOpcodes; sqInt opcodeSize; sqInt startAddress1; initializeBackend(); stopsFromto(backEnd, startAddress, endAddress - 1); sqMakeMemoryExecutableFromTo(startAddress, endAddress); codeBase = (methodZoneBase = startAddress); minValidCallAddress = (((((codeBase < (interpretAddress())) ? codeBase : (interpretAddress()))) < (primitiveFailAddress())) ? (((codeBase < (interpretAddress())) ? codeBase : (interpretAddress()))) : (primitiveFailAddress())); manageFromto(methodZoneBase, endAddress); /* begin maybeGenerateCheckFeatures */ /* begin maybeGenerateICacheFlush */ /* begin generateVMOwnerLockFunctions */ # if COGMTVM /* begin allocateOpcodes:bytecodes: */ numberOfAbstractOpcodes = numLowLevelLockOpcodes(backEnd); numAbstractOpcodes = numberOfAbstractOpcodes; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; zeroOpcodeIndex(); startAddress1 = methodZoneBase; generateLowLevelTryLock(backEnd, vmOwnerLockAddress()); outputInstructionsForGeneratedRuntimeAt(startAddress1); recordGeneratedRunTimeaddress("ceTryLockVMOwner", startAddress1); ceTryLockVMOwner = ((usqIntptr_t (*)(void)) startAddress1); zeroOpcodeIndex(); initialPC = 0; endPC = numAbstractOpcodes - 1; startAddress1 = methodZoneBase; generateLowLevelUnlock(backEnd, vmOwnerLockAddress()); outputInstructionsForGeneratedRuntimeAt(startAddress1); recordGeneratedRunTimeaddress("ceUnlockVMOwner", startAddress1); ceUnlockVMOwner = ((void (*)(void)) startAddress1); # endif /* COGMTVM */ genGetLeafCallStackPointer(); generateStackPointerCapture(); generateTrampolines(); computeEntryOffsets(); computeFullBlockEntryOffsets(); generateClosedPICPrototype(); manageFromto(methodZoneBase, endAddress); generateOpenPICPrototype(); } /* Answer a usage count that reflects likely long-term usage. Answer 1 for non-primitives or quick primitives (inst var accessors), 2 for methods with interpreter primitives, and 3 for compiled primitives. */ /* Cogit>>#initialMethodUsageCount */ static sqInt initialMethodUsageCount(void) { if ((primitiveIndex == 1) || (isQuickPrimitiveIndex(primitiveIndex))) { return 1; } if (!(primitiveGeneratorOrNil())) { return 2; } return 3; } /* Answer a usage count that reflects likely long-term usage. */ /* Cogit>>#initialOpenPICUsageCount */ static sqInt initialOpenPICUsageCount(void) { return CMMaxUsageCount - 1; } /* Answer the value to put in an inline-cache that is being loaded with the selector. Usually this is simply the selector, but in 64-bits the cache is only 32-bits wide and so the cache is loaded with the index of the selector. */ /* Cogit>>#inlineCacheValueForSelector:in:at: */ static sqInt NoDbgRegParms inlineCacheValueForSelectorinat(sqInt selector, CogMethod *aCogMethod, sqInt mcpc) { return selector; } /* Cogit>>#inverseBranchFor: */ static sqInt NoDbgRegParms 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; } /* See Cogit class>>initializeAnnotationConstants */ /* Cogit>>#isPCMappedAnnotation: */ static sqInt NoDbgRegParms isPCMappedAnnotation(sqInt annotation) { return annotation >= HasBytecodePC; } /* Cogit>>#isPCWithinMethodZone: */ sqInt isPCWithinMethodZone(void *address) { return (((((usqInt)address)) >= methodZoneBase) && ((((usqInt)address)) <= (freeStart()))); } /* Answer if the instruction preceding retpc is a call instruction. */ /* Cogit>>#isSendReturnPC: */ sqInt isSendReturnPC(sqInt retpc) { sqInt target; if (!(isCallPrecedingReturnPC(backEnd, retpc))) { return 0; } target = callTargetFromReturnAddress(backEnd, retpc); return (((target >= firstSend) && (target <= lastSend))) || (((target >= methodZoneBase) && (target <= (freeStart())))); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPEqual(void *jumpTarget) { /* begin genJumpFPEqual: */ return genoperand(JumpFPEqual, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPGreaterOrEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPGreaterOrEqual(void *jumpTarget) { /* begin genJumpFPGreaterOrEqual: */ return genoperand(JumpFPGreaterOrEqual, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPGreater: */ static AbstractInstruction * NoDbgRegParms gJumpFPGreater(void *jumpTarget) { /* begin genJumpFPGreater: */ return genoperand(JumpFPGreater, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPNotEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPNotEqual(void *jumpTarget) { /* begin genJumpFPNotEqual: */ return genoperand(JumpFPNotEqual, ((sqInt)jumpTarget)); } /* Cogit>>#LogicalShiftLeftCq:R: */ static AbstractInstruction * NoDbgRegParms gLogicalShiftLeftCqR(sqInt quickConstant, sqInt reg) { return genoperandoperand(LogicalShiftLeftCqR, quickConstant, reg); } /* Cogit>>#lastOpcode */ static AbstractInstruction * lastOpcode(void) { assert(opcodeIndex > 0); return abstractInstructionAt(opcodeIndex - 1); } /* Cogit>>#linkSendAt:in:to:offset:receiver: */ void linkSendAtintooffsetreceiver(sqInt callSiteReturnAddress, CogMethod *sendingMethod, CogMethod *targetMethod, sqInt theEntryOffset, sqInt receiver) { sqInt address; sqInt extent; sqInt inlineCacheTag; assert((theEntryOffset == cmEntryOffset) || (theEntryOffset == cmNoCheckEntryOffset)); assert(((callSiteReturnAddress >= methodZoneBase) && (callSiteReturnAddress <= (freeStart())))); inlineCacheTag = (theEntryOffset == cmNoCheckEntryOffset ? (targetMethod->selector) : inlineCacheTagForInstance(receiver)); address = (((sqInt)targetMethod)) + theEntryOffset; extent = rewriteInlineCacheAttagtarget(backEnd, callSiteReturnAddress, inlineCacheTag, address); flushICacheFromto(processor, (((usqInt)callSiteReturnAddress)) - extent, ((usqInt)callSiteReturnAddress)); } /* Cogit>>#loadBytesAndGetDescriptor */ static BytecodeDescriptor * loadBytesAndGetDescriptor(void) { BytecodeDescriptor *descriptor; byte0 = (fetchByteofObject(bytecodePC, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); loadSubsequentBytesForDescriptorat(descriptor, bytecodePC); return descriptor; } /* Cogit>>#loadSubsequentBytesForDescriptor:at: */ static void NoDbgRegParms loadSubsequentBytesForDescriptorat(BytecodeDescriptor *descriptor, sqInt pc) { if (((descriptor->numBytes)) > 1) { byte1 = fetchByteofObject(pc + 1, methodObj); if (((descriptor->numBytes)) > 2) { byte2 = fetchByteofObject(pc + 2, methodObj); if (((descriptor->numBytes)) > 3) { byte3 = fetchByteofObject(pc + 3, methodObj); if (((descriptor->numBytes)) > 4) { notYetImplemented(); } } } } } /* Cogit>>#MoveAw:R: */ static AbstractInstruction * NoDbgRegParms gMoveAwR(sqInt address, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, reg)); } /* Cogit>>#MoveCw:R: */ static AbstractInstruction * NoDbgRegParms gMoveCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, reg)); } /* Answer the address of the null byte at the end of the method map. */ /* Cogit>>#mapEndFor: */ static sqInt NoDbgRegParms mapEndFor(CogMethod *cogMethod) { usqInt end; end = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while ((byteAt(end)) != MapEnd) { end -= 1; assert(end > (firstMappedPCFor(cogMethod))); } return end; } /* Unlinking/GC/Disassembly support */ /* Cogit>>#mapFor:performUntil:arg: */ static sqInt NoDbgRegParms mapForperformUntilarg(CogMethod *cogMethod, sqInt (*functionSymbol)(sqInt annotation, char *mcpc, sqInt arg), sqInt arg) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; /* begin firstMappedPCFor: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = functionSymbol(annotation, (((char *) mcpc)), arg); if (result != 0) { return result; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* Remap all object references in the closed PIC. Answer if any references are young. Set codeModified if any modifications are made. */ /* Cogit>>#mapObjectReferencesInClosedPIC: */ static sqInt NoDbgRegParms mapObjectReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt pc; sqInt refersToYoung; /* first we check the potential method oop load at the beginning of the CPIC */ pc = addressOfEndOfCaseinCPIC(1, cPIC); /* We find the end address of the cPICNumCases'th case and can then just step forward by the case size thereafter */ refersToYoung = remapMaybeObjRefInClosedPICAt(pc - 4 /* jumpLongByteSize */); /* Next we check the potential class ref in the compare instruction, and the potential method oop load for each case. */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (remapMaybeObjRefInClosedPICAt((pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)) { refersToYoung = 1; } pc += cPICCaseSize; } return refersToYoung; } /* Update all references to objects in the generated runtime. */ /* Cogit>>#mapObjectReferencesInGeneratedRuntime */ static void mapObjectReferencesInGeneratedRuntime(void) { sqInt i; sqInt literal; sqInt mappedLiteral; usqInt mcpc; for (i = 0; i < runtimeObjectRefIndex; i += 1) { mcpc = objectReferencesInRuntime[i]; literal = longAt(mcpc); mappedLiteral = remapObject(literal); if (mappedLiteral != literal) { /* begin storeLiteral:atAnnotatedAddress:using: */ longAtput(mcpc, mappedLiteral); codeModified = 1; } } } /* Update all references to objects in machine code for a become. Unlike incrementalGC or fullGC a method that does not refer to young may refer to young as a result of the become operation. Unlike incrementalGC or fullGC the reference from a Cog method to its methodObject *must not* change since the two are two halves of the same object. */ /* Cogit>>#mapObjectReferencesInMachineCodeForBecome */ static void mapObjectReferencesInMachineCodeForBecome(void) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; sqInt hasYoungObj; sqInt hasYoungObjPtr; usqInt map; sqInt mapByte; sqInt mcpc; sqInt remappedMethod; sqInt result; sqInt val; val = 0; hasYoungObj = 0; hasYoungObjPtr = ((sqInt)((&hasYoungObj))); codeModified = (freedPIC = 0); mapObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { assert(!hasYoungObj); if (((cogMethod->cmType)) != CMFree) { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->selector = remapOop((cogMethod->selector))); if (((cogMethod->cmType)) == CMClosedPIC) { if ((isYoung((cogMethod->selector))) || (mapObjectReferencesInClosedPIC(cogMethod))) { freedPIC = 1; freeMethod(cogMethod); } } else { if (isYoung((cogMethod->selector))) { hasYoungObj = 1; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); remappedMethod = remapOop((cogMethod->methodObject)); if (remappedMethod != ((cogMethod->methodObject))) { if (methodHasCogMethod(remappedMethod)) { error("attempt to become two cogged methods"); } if (!(withoutForwardingOnandwithsendToCogit((cogMethod->methodObject), remappedMethod, (cogMethod->cmUsesPenultimateLit), methodhasSameCodeAscheckPenultimate))) { error("attempt to become cogged method into different method"); } if ((rawHeaderOf((cogMethod->methodObject))) == (((sqInt)cogMethod))) { rawHeaderOfput((cogMethod->methodObject), (cogMethod->methodHeader)); (cogMethod->methodHeader = rawHeaderOf(remappedMethod)); (cogMethod->methodObject = remappedMethod); rawHeaderOfput(remappedMethod, ((sqInt)cogMethod)); } else { assert((noAssertMethodClassAssociationOf((cogMethod->methodObject))) == (nilObject())); (cogMethod->methodHeader = rawHeaderOf(remappedMethod)); (cogMethod->methodObject = remappedMethod); } } if (isYoung((cogMethod->methodObject))) { hasYoungObj = 1; } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), hasYoungObjPtr); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; if (hasYoungObj) { ensureInYoungReferrers(cogMethod); hasYoungObj = 0; } else { (cogMethod->cmRefersToYoung = 0); } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } pruneYoungReferrers(); if (freedPIC) { unlinkSendsToFree(); } if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)codeBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code for a full gc. Since the current (New)ObjectMemory GC makes everything old in a full GC a method not referring to young will not refer to young afterwards */ /* Cogit>>#mapObjectReferencesInMachineCodeForFullGC */ static void mapObjectReferencesInMachineCodeForFullGC(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; codeModified = 0; mapObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->selector = remapOop((cogMethod->selector))); if (((cogMethod->cmType)) == CMClosedPIC) { assert(!((cogMethod->cmRefersToYoung))); mapObjectReferencesInClosedPIC(cogMethod); } else { if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); (cogMethod->methodObject = remapOop((cogMethod->methodObject))); } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } pruneYoungReferrers(); if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)codeBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code for either a Spur scavenging gc or a Squeak V3 incremental GC. Avoid scanning all code by using the youngReferrers list. In a young gc a method referring to young may no longer refer to young, but a method not referring to young cannot and will not refer to young afterwards. */ /* Cogit>>#mapObjectReferencesInMachineCodeForYoungGC */ static void mapObjectReferencesInMachineCodeForYoungGC(void) { sqInt annotation; CogMethod *cogMethod; sqInt hasYoungObj; sqInt hasYoungObjPtr; usqInt map; sqInt mapByte; sqInt mcpc; usqInt pointer; sqInt result; sqInt val; val = 0; hasYoungObj = 0; hasYoungObjPtr = ((sqInt)((&hasYoungObj))); codeModified = 0; pointer = youngReferrers(); while (pointer < limitAddress) { assert(!hasYoungObj); cogMethod = ((CogMethod *) (longAt(pointer))); if (((cogMethod->cmType)) == CMFree) { assert(!((cogMethod->cmRefersToYoung))); } else { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if ((cogMethod->cmRefersToYoung)) { assert((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)); (cogMethod->selector = remapOop((cogMethod->selector))); if (isYoung((cogMethod->selector))) { hasYoungObj = 1; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); (cogMethod->methodObject = remapOop((cogMethod->methodObject))); if (isYoung((cogMethod->methodObject))) { hasYoungObj = 1; } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), hasYoungObjPtr); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; if (hasYoungObj) { hasYoungObj = 0; } else { (cogMethod->cmRefersToYoung = 0); } } } pointer += BytesPerWord; } pruneYoungReferrers(); if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code. */ /* Cogit>>#mapObjectReferencesInMachineCode: */ void mapObjectReferencesInMachineCode(sqInt gcMode) { switch (gcMode) { case GCModeNewSpace: mapObjectReferencesInMachineCodeForYoungGC(); break; case GCModeFull: mapObjectReferencesInMachineCodeForFullGC(); break; case GCModeBecome: mapObjectReferencesInMachineCodeForBecome(); break; default: error("Case not found and no otherwise clause"); } if (!(asserta((freeStart()) <= (youngReferrers())))) { error("youngReferrers list overflowed"); } } /* Mark objects in machine-code of marked methods (or open PICs with marked selectors). */ /* Cogit>>#markAndTraceMachineCodeOfMarkedMethods */ void markAndTraceMachineCodeOfMarkedMethods(void) { sqInt annotation; sqInt annotation1; CogMethod *cogMethod; usqInt map; usqInt map1; sqInt mapByte; sqInt mapByte1; sqInt mcpc; sqInt mcpc1; sqInt result; sqInt result1; sqInt val; sqInt val1; val = 0; val1 = 0; if (leakCheckFullGC()) { asserta(allMachineCodeObjectReferencesValid()); } codeModified = 0; markAndTraceObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) { /* begin markAndTraceLiteralsIn: */ assert(((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) || ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector)))))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = markLiteralspcmethod(annotation, (((char *) mcpc)), (((sqInt)cogMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } if ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector))))) { /* begin markAndTraceLiteralsIn: */ assert(((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) || ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector)))))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc1 = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map1 = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte1 = byteAt(map1))) != MapEnd) { if (mapByte1 >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc1 += (mapByte1 & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation1 = ((usqInt) mapByte1) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte1 = byteAt(map1 - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation1 += mapByte1 & DisplacementMask; map1 -= 1; } result1 = markLiteralspcmethod(annotation1, (((char *) mcpc1)), (((sqInt)cogMethod))); if (result1 != 0) { goto l4; } } else { if (mapByte1 < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc1 += (((sqInt)((usqInt)((mapByte1 - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map1 -= 1; } l4: /* end mapFor:performUntil:arg: */; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (leakCheckFullGC()) { asserta(allMachineCodeObjectReferencesValid()); } if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Mark and trace any object references in the generated run-time. */ /* Cogit>>#markAndTraceObjectReferencesInGeneratedRuntime */ static void markAndTraceObjectReferencesInGeneratedRuntime(void) { sqInt i; sqInt literal; usqInt mcpc; for (i = 0; i < runtimeObjectRefIndex; i += 1) { mcpc = objectReferencesInRuntime[i]; literal = longAt(mcpc); markAndTraceLiteralinatpc(literal, ((CogMethod *) null), ((usqInt)mcpc)); } } /* Mark and trace objects in the argument and free if it is appropriate. Answer if the method has been freed. firstVisit is a hint used to avoid scanning methods we've already seen. False positives are fine. For a CMMethod this frees if the bytecode method isnt marked, marks and traces object literals and selectors, unlinks sends to targets that should be freed. For a CMClosedPIC this frees if it refers to anything that should be freed or isn't marked. For a CMOpenPIC this frees if the selector isn't marked. */ /* this recurses at most one level down */ /* Cogit>>#markAndTraceOrFreeCogMethod:firstVisit: */ static sqInt NoDbgRegParms markAndTraceOrFreeCogMethodfirstVisit(CogMethod *cogMethod, sqInt firstVisit) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; sqInt val; val = 0; if (((cogMethod->cmType)) == CMFree) { return 1; } assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if (((cogMethod->cmType)) == CMMethod) { if (!(isMarked((cogMethod->methodObject)))) { freeMethod(cogMethod); return 1; } if (firstVisit) { /* begin markLiteralsAndUnlinkUnmarkedSendsIn: */ assert(((cogMethod->cmType)) == CMMethod); assert(isMarked((cogMethod->methodObject))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = markLiteralsAndUnlinkIfUnmarkedSendpcmethod(annotation, (((char *) mcpc)), (((sqInt)cogMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } return 0; } if (((cogMethod->cmType)) == CMClosedPIC) { if (!(closedPICRefersToUnmarkedObject(cogMethod))) { return 0; } freeMethod(cogMethod); return 1; } if (((cogMethod->cmType)) == CMOpenPIC) { if (isMarked((cogMethod->selector))) { return 0; } freeMethod(cogMethod); return 1; } assert((((cogMethod->cmType)) == CMMethod) || ((((cogMethod->cmType)) == CMClosedPIC) || (((cogMethod->cmType)) == CMOpenPIC))); return 0; } /* If entryPoint is that of some method, then mark and trace objects in it and free if it is appropriate. Answer if the method has been freed. */ /* Cogit>>#markAndTraceOrFreePICTarget:in: */ static sqInt NoDbgRegParms markAndTraceOrFreePICTargetin(sqInt entryPoint, CogMethod *cPIC) { CogMethod *targetMethod; assert((entryPoint > methodZoneBase) && (entryPoint < (freeStart()))); if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { return 0; } targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); return markAndTraceOrFreeCogMethodfirstVisit(targetMethod, (((usqInt)targetMethod)) > (((usqInt)cPIC))); } /* Mark and trace literals. Unlink sends that have unmarked cache tags or targets. */ /* Cogit>>#markLiteralsAndUnlinkIfUnmarkedSend:pc:method: */ static sqInt NoDbgRegParms markLiteralsAndUnlinkIfUnmarkedSendpcmethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt cacheTagMarked; sqInt entryPoint1; sqInt literal; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj1; CogMethod *targetMethod1; sqInt unlinkedRoutine; sqInt val; literal = 0; val = 0; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (markAndTraceLiteralinatpc(literal, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); cacheTagMarked = tagCouldBeObj1 && (cacheTagIsMarked(cacheTag1)); if (entryPoint1 > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint1 - offset1)); if ((!cacheTagMarked) || (markAndTraceOrFreeCogMethodfirstVisit(targetMethod1, (((usqInt)targetMethod1)) > (((usqInt)mcpc))))) { /* Either the cacheTag is unmarked (e.g. new class) or the target has been freed (because it is unmarked), so unlink the send. */ /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod1->selector), unlinkedRoutine); codeModified = 1; markAndTraceLiteralinat((targetMethod1->selector), targetMethod1, (&((targetMethod1->selector)))); } } else { /* cacheTag is selector */ if (markAndTraceCacheTagLiteralinatpc(cacheTag1, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } } return 0; } /* Mark and trace literals. Additionally in Newspeak, void push implicits that have unmarked classes. */ /* Cogit>>#markLiterals:pc:method: */ static sqInt NoDbgRegParms markLiteralspcmethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt entryPoint1; sqInt literal; sqInt tagCouldBeObj1; literal = 0; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (markAndTraceLiteralinatpc(literal, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); if (tagCouldBeObj1) { if (markAndTraceCacheTagLiteralinatpc(cacheTag1, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { /* cacheTag is selector */ codeModified = 1; } } } return 0; } /* Cogit>>#markMethodAndReferents: */ void markMethodAndReferents(CogBlockMethod *aCogMethod) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; assert((((aCogMethod->cmType)) == CMMethod) || (((aCogMethod->cmType)) == CMBlock)); cogMethod = (((aCogMethod->cmType)) == CMMethod ? ((CogMethod *) aCogMethod) : cmHomeMethod(aCogMethod)); (cogMethod->cmUsageCount = CMMaxUsageCount); /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = incrementUsageOfTargetIfLinkedSendmcpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#maxCogMethodAddress */ usqInt maxCogMethodAddress(void) { return ((usqInt)(limitZony())); } /* If this is the Newspeak VM and the objectRepresentation supports pinning then allocate space for the implicit receiver caches on the heap. */ /* Cogit>>#maybeAllocAndInitIRCs */ static sqInt maybeAllocAndInitIRCs(void) { return 1; } /* Check that the header fields are consistent with the type. Answer 0 if it is ok, otherwise answer a code for the error. */ /* Cogit>>#maybeFreeCogMethodDoesntLookKosher: */ static sqInt NoDbgRegParms maybeFreeCogMethodDoesntLookKosher(CogMethod *cogMethod) { sqInt result; result = cogMethodDoesntLookKosher(cogMethod); return (result == 2 ? 0 : result); } /* In SIsta Spur counters are held on the heap in pinned objects which must be marked to avoid them being garbage collected. This is the hook through which that happens. */ /* Cogit>>#maybeMarkCountersIn: */ static void NoDbgRegParms maybeMarkCountersIn(CogMethod *cogMethod) { } /* Cogit>>#mclassIsSmallInteger */ static sqInt mclassIsSmallInteger(void) { return (receiverTags & 1); } /* Answer the absolute machine code pc matching the zero-relative bytecode pc of a backward branch in cogMethod, given the start of the bytecodes for cogMethod's block or method object. */ /* Cogit>>#mcPCForBackwardBranch:startBcpc:in: */ usqInt mcPCForBackwardBranchstartBcpcin(sqInt bcpc, sqInt startbcpc, CogBlockMethod *cogMethod) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc1; sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt targetPC; latestContinuation = 0; /* begin mapFor:bcpc:performUntil:arg: */ assert(((cogMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogMethod)) + ((cogMethod->stackCheckOffset)); result = (((0 + (((int)((usqInt)(HasBytecodePC) << 1)))) & 1) && ((((sqInt)(((void *)bcpc)))) == startbcpc) ? ((sqInt)(((char *) mcpc))) : 0); if (result != 0) { return result; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc1 = startbcpc; if (((cogMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc1 += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc1 == ((cogMethod->startpc))); homeMethod = cmHomeMethod(cogMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc1 = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc1, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc1 + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc1, -1, aMethodObj)) : 0)); bcpc1 = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc1, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc1 >= endbcpc) { return 0; } } else { if (((descriptor->isReturn)) && (bcpc1 >= latestContinuation)) { return 0; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj); targetPC = (bcpc1 + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc1 + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc1 = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj)) < 0)); result = findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc1 - (2 * nExts) : bcpc1)), (((void *)bcpc))); if (result != 0) { return result; } bcpc1 = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* For the purposes of become: see if the two methods are similar, i.e. can be safely becommed. This is pretty strict. All literals and bytecodes must be identical. Only trailer bytes and header flags can differ. */ /* Cogit>>#method:hasSameCodeAs:checkPenultimate: */ static sqInt NoDbgRegParms methodhasSameCodeAscheckPenultimate(sqInt methodA, sqInt methodB, sqInt comparePenultimateLiteral) { sqInt bi; sqInt endPCA; sqInt headerA; sqInt headerB; sqInt li; sqInt numLitsA; headerA = methodHeaderOf(methodA); headerB = methodHeaderOf(methodB); numLitsA = literalCountOfMethodHeader(headerA); endPCA = endPCOf(methodA); if (((argumentCountOfMethodHeader(headerA)) != (argumentCountOfMethodHeader(headerB))) || (((temporaryCountOfMethodHeader(headerA)) != (temporaryCountOfMethodHeader(headerB))) || (((primitiveIndexOfMethodheader(methodA, headerA)) != (primitiveIndexOfMethodheader(methodB, headerB))) || ((numLitsA != (literalCountOfMethodHeader(headerB))) || (endPCA > (numBytesOf(methodB))))))) { return 0; } for (li = 1; li < numLitsA; li += 1) { if ((fetchPointerofObject(li, methodA)) != (fetchPointerofObject(li, methodB))) { if ((li < (numLitsA - 1)) || (comparePenultimateLiteral)) { return 0; } } } for (bi = (startPCOfMethod(methodA)); bi <= endPCA; bi += 1) { if ((fetchByteofObject(bi, methodA)) != (fetchByteofObject(bi, methodB))) { return 0; } } return 1; } /* Cogit>>#minCogMethodAddress */ sqInt minCogMethodAddress(void) { return methodZoneBase; } /* Cogit>>#mnuOffset */ sqInt mnuOffset(void) { return missOffset; } /* Cogit>>#needsFrameIfImmutability: */ static sqInt NoDbgRegParms needsFrameIfImmutability(sqInt stackDelta) { return IMMUTABILITY; } /* Cogit>>#needsFrameIfInBlock: */ static sqInt NoDbgRegParms needsFrameIfInBlock(sqInt stackDelta) { return inBlock > 0; } /* Cogit>>#needsFrameNever: */ static sqInt NoDbgRegParms needsFrameNever(sqInt stackDelta) { return 0; } /* Cogit>>#noAssertMethodClassAssociationOf: */ static sqInt NoDbgRegParms noAssertMethodClassAssociationOf(sqInt methodPointer) { return literalofMethod((literalCountOfMethodHeader(noAssertHeaderOf(methodPointer))) - 1, methodPointer); } /* Check that no method is maximally marked. A maximal mark is an indication the method has been scanned to increase the usage count of its referent methods. */ /* Cogit>>#noCogMethodsMaximallyMarked */ static sqInt noCogMethodsMaximallyMarked(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->cmUsageCount)) == CMMaxUsageCount)) { return 0; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return 1; } /* Answer if all targets in the PIC are in-use methods. */ /* Cogit>>#noTargetsFreeInClosedPIC: */ static sqInt NoDbgRegParms noTargetsFreeInClosedPIC(CogMethod *cPIC) { return !(cPICHasFreedTargets(cPIC)); } /* Store the generated machine code, answering the last address */ /* Cogit>>#outputInstructionsAt: */ static sqInt NoDbgRegParms outputInstructionsAt(sqInt startAddress) { sqInt absoluteAddress; AbstractInstruction *abstractInstruction; sqInt i; sqInt j; absoluteAddress = startAddress; for (i = 0; i < opcodeIndex; i += 1) { abstractInstruction = abstractInstructionAt(i); assert(((abstractInstruction->address)) == absoluteAddress); /* begin outputMachineCodeAt: */ for (j = 0; j < ((abstractInstruction->machineCodeSize)); j += 4) { longAtput(absoluteAddress + j, ((abstractInstruction->machineCode))[j / 4]); } absoluteAddress += (abstractInstruction->machineCodeSize); } return absoluteAddress; } /* Output instructions generated for one of the generated run-time routines, a trampoline, etc */ /* Cogit>>#outputInstructionsForGeneratedRuntimeAt: */ static sqInt NoDbgRegParms outputInstructionsForGeneratedRuntimeAt(sqInt startAddress) { sqInt endAddress; sqInt size; computeMaximumSizes(); (methodLabel->address = startAddress); size = generateInstructionsAt(startAddress); endAddress = outputInstructionsAt(startAddress); assert((startAddress + size) == endAddress); methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(backEnd, endAddress, methodZoneBase - 1); return startAddress; } /* Cogit>>#PushCw: */ static AbstractInstruction * NoDbgRegParms gPushCw(sqInt wordConstant) { /* begin gen:literal: */ return checkLiteralforInstruction(wordConstant, genoperand(PushCw, wordConstant)); } /* Code entry closed PIC full or miss to an instance of a young class or to a young target method. Attempt to patch the send site to an open PIC. Answer if the attempt succeeded; in fact it will only return if the attempt failed. The stack looks like: receiver args sp=> sender return address */ /* Cogit>>#patchToOpenPICFor:numArgs:receiver: */ sqInt patchToOpenPICFornumArgsreceiver(sqInt selector, sqInt numArgs, sqInt receiver) { sqInt extent; CogMethod *oPIC; sqInt outerReturn; /* See if an Open PIC is already available. */ outerReturn = stackTop(); oPIC = openPICWithSelector(selector); if (!(oPIC)) { /* otherwise attempt to create an Open PIC. */ oPIC = cogOpenPICSelectornumArgs(selector, numArgs); if ((((((sqInt)oPIC)) >= MaxNegativeErrorCode) && ((((sqInt)oPIC)) <= -1))) { /* For some reason the PIC couldn't be generated, most likely a lack of code memory. */ if ((((sqInt)oPIC)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return 0; } } extent = rewriteInlineCacheAttagtarget(backEnd, outerReturn, inlineCacheValueForSelectorinat(selector, mframeHomeMethodExport(), outerReturn), (((sqInt)oPIC)) + cmEntryOffset); flushICacheFromto(processor, (((usqInt)outerReturn)) - extent, ((usqInt)outerReturn)); flushICacheFromto(processor, ((usqInt)oPIC), (((usqInt)oPIC)) + openPICSize); executeCogMethodfromLinkedSendWithReceiver(oPIC, receiver); return 1; } /* This value is used to decide between MNU processing or interpretation in the closed PIC aborts. */ /* Cogit>>#picAbortDiscriminatorValue */ static sqInt picAbortDiscriminatorValue(void) { return 0; } /* Answer the start of the abort sequence for invoking the interpreter in a closed PIC. */ /* Cogit>>#picInterpretAbortOffset */ static sqInt picInterpretAbortOffset(void) { return (interpretOffset()) - (4 /* pushLinkRegisterByteSize */ + 4 /* callInstructionByteSize */); } /* Cogit>>#printCogMethodFor: */ void printCogMethodFor(void *address) { CogMethod *cogMethod; cogMethod = methodFor(address); if (cogMethod == 0) { if ((codeEntryFor(address)) == null) { print("not a method"); cr(); } else { print("trampoline "); print(codeEntryNameFor(address)); cr(); } } else { printCogMethod(cogMethod); } } /* Cogit>>#printTrampolineTable */ void printTrampolineTable(void) { sqInt i; for (i = 0; i < trampolineTableIndex; i += 2) { printHex(((sqInt)(trampolineAddresses[i + 1]))); print(": "); print(((char *) (trampolineAddresses[i]))); cr(); } } /* Cogit>>#processorHasDivQuoRemAndMClassIsSmallInteger */ static sqInt processorHasDivQuoRemAndMClassIsSmallInteger(void) { return mclassIsSmallInteger(); } /* Cogit>>#processorHasMultiplyAndMClassIsSmallInteger */ static sqInt processorHasMultiplyAndMClassIsSmallInteger(void) { return mclassIsSmallInteger(); } /* Cogit>>#recordGeneratedRunTime:address: */ static void NoDbgRegParms recordGeneratedRunTimeaddress(char *aString, sqInt address) { trampolineAddresses[trampolineTableIndex] = aString; trampolineAddresses[trampolineTableIndex + 1] = (((char *) address)); trampolineTableIndex += 2; } /* This one for C support code. */ /* Cogit>>#recordPrimTraceFunc */ sqInt recordPrimTraceFunc(void) { return recordPrimTrace(); } /* Cogit>>#recordRunTimeObjectReferences */ static void recordRunTimeObjectReferences(void) { sqInt i; AbstractInstruction *instruction; for (i = 0; i < opcodeIndex; i += 1) { instruction = abstractInstructionAt(i); if (((instruction->annotation)) == IsObjectReference) { assert(runtimeObjectRefIndex < NumObjRefsInRuntime); assert(!hasYoungReferent); if (hasYoungReferent) { error("attempt to generate run-time routine containing young object reference. Cannot initialize Cogit run-time."); } objectReferencesInRuntime[runtimeObjectRefIndex] = (((usqInt)((((instruction->opcode)) == Literal ? (instruction->address) : ((instruction->address)) + ((instruction->machineCodeSize)))))); runtimeObjectRefIndex += 1; } } } /* Cogit>>#registerMaskFor: */ static sqInt NoDbgRegParms registerMaskFor(sqInt reg) { return 1U << reg; } /* Cogit>>#relocateCallsAndSelfReferencesInMethod: */ static void NoDbgRegParms relocateCallsAndSelfReferencesInMethod(CogMethod *cogMethod) { sqInt annotation; sqInt callDelta; usqInt map; sqInt mapByte; sqInt mcpc; sqLong refDelta; sqInt result; refDelta = (cogMethod->objectHeader); callDelta = refDelta; assert((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)); assert((callTargetFromReturnAddress(backEnd, (((sqInt)cogMethod)) + missOffset)) == ((((cogMethod->cmType)) == CMMethod ? methodAbortTrampolineFor((cogMethod->cmNumArgs)) : picAbortTrampolineFor((cogMethod->cmNumArgs))))); relocateCallBeforeReturnPCby(backEnd, (((sqInt)cogMethod)) + missOffset, -callDelta); /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = relocateIfCallOrMethodReferencemcpcdelta(annotation, (((char *) mcpc)), refDelta); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#relocateCallsInClosedPIC: */ static void NoDbgRegParms relocateCallsInClosedPIC(CogMethod *cPIC) { sqInt callDelta; sqInt entryPoint; sqInt i; sqInt pc; sqLong refDelta; CogMethod *targetMethod; refDelta = (cPIC->objectHeader); callDelta = refDelta; assert((callTargetFromReturnAddress(backEnd, (((sqInt)cPIC)) + missOffset)) == (picAbortTrampolineFor((cPIC->cmNumArgs)))); relocateCallBeforeReturnPCby(backEnd, (((sqInt)cPIC)) + missOffset, -callDelta); pc = (((sqInt)cPIC)) + firstCPICCaseOffset; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { /* Interpret/MNU */ } else { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert(((targetMethod->cmType)) == CMMethod); if (i == 1) { relocateJumpLongBeforeFollowingAddressby(backEnd, pc, -(callDelta - ((targetMethod->objectHeader)))); } else { relocateJumpLongConditionalBeforeFollowingAddressby(backEnd, pc, -(callDelta - ((targetMethod->objectHeader)))); } } } assert(((cPIC->cPICNumCases)) > 0); relocateMethodReferenceBeforeAddressby(backEnd, (addressOfEndOfCaseinCPIC(2, cPIC)) + 4 /* loadPICLiteralByteSize */, refDelta); relocateJumpLongBeforeFollowingAddressby(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, -callDelta); } /* Cogit>>#relocateIfCallOrMethodReference:mcpc:delta: */ static sqInt NoDbgRegParms relocateIfCallOrMethodReferencemcpcdelta(sqInt annotation, char *mcpc, sqInt refDelta) { sqInt callDelta; sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod; sqInt unlinkedRoutine; callDelta = refDelta; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint <= methodZoneBase) { /* send is not linked; just relocate */ relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -callDelta); return 0; } /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod->cmType)) != CMFree) { /* send target not freed; just relocate. */ relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -(callDelta - ((targetMethod->objectHeader)))); return 0; } unlinkedRoutine = sendTable1[((((targetMethod->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod->cmNumArgs)) : (NumSendTrampolines - 1))]; unlinkedRoutine -= callDelta; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod->selector), unlinkedRoutine); return 0; } if (annotation == IsRelativeCall) { relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -callDelta); return 0; } if (annotation == IsAbsPCReference) { relocateMethodReferenceBeforeAddressby(backEnd, ((sqInt)mcpc), refDelta); } return 0; } /* Cogit>>#remapIfObjectRef:pc:hasYoung: */ static sqInt NoDbgRegParms remapIfObjectRefpchasYoung(sqInt annotation, char *mcpc, sqInt hasYoungPtr) { sqInt cacheTag1; sqInt callSiteReturnAddress; sqInt entryPoint1; sqInt literal; sqInt mappedCacheTag; sqInt mappedLiteral; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj1; CogMethod *targetMethod1; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (couldBeObject(literal)) { mappedLiteral = remapObject(literal); if (literal != mappedLiteral) { /* begin storeLiteral:atAnnotatedAddress:using: */ longAtput(((usqInt)mcpc), mappedLiteral); codeModified = 1; } if ((hasYoungPtr != 0) && (isYoung(mappedLiteral))) { (((sqInt *) hasYoungPtr))[0] = 1; } } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); if (tagCouldBeObj1 && (couldBeObject(cacheTag1))) { mappedCacheTag = remapObject(cacheTag1); if (cacheTag1 != mappedCacheTag) { /* begin rewriteInlineCacheTag:at: */ callSiteReturnAddress = ((usqInt)mcpc); longAtput(pcRelativeAddressAt(((AbstractInstruction *) backEnd), callSiteReturnAddress - 8), mappedCacheTag); ((AbstractInstruction *) backEnd); codeModified = 1; } if ((hasYoungPtr != 0) && (isYoung(mappedCacheTag))) { (((sqInt *) hasYoungPtr))[0] = 1; } } if (hasYoungPtr != 0) { /* Since the unlinking routines may rewrite the cacheTag to the send's selector, and since they don't have the cogMethod to hand and can't add it to youngReferrers, the method must remain in youngReferrers if the targetMethod's selector is young. */ if (entryPoint1 > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint1 - offset1)); if (isYoung((targetMethod1->selector))) { (((sqInt *) hasYoungPtr))[0] = 1; } } } } return 0; } /* Remap a potential object reference from a closed PIC. This may be an object reference, an inline cache tag or null. Answer if the updated literal is young. mcpc is the address of the next instruction following either the load of the method literal or the compare of the class tag. */ /* Cogit>>#remapMaybeObjRefInClosedPICAt: */ static sqInt NoDbgRegParms remapMaybeObjRefInClosedPICAt(sqInt mcpc) { sqInt object; sqInt subject; object = literalBeforeFollowingAddress(backEnd, mcpc); if (!(couldBeObject(object))) { return 0; } subject = remapOop(object); if (object != subject) { storeLiteralbeforeFollowingAddress(backEnd, subject, mcpc); codeModified = 1; } return isYoungObject(subject); } /* Rewrite the three values involved in a CPIC case. Used by the initialize & extend CPICs. c.f. expectedClosedPICPrototype: */ /* write the obj ref/operand via the second ldr */ /* Cogit>>#rewriteCPICCaseAt:tag:objRef:target: */ static void NoDbgRegParms rewriteCPICCaseAttagobjReftarget(sqInt followingAddress, sqInt newTag, sqInt newObjRef, sqInt newTarget) { sqInt classTagPC; sqInt methodObjPC; methodObjPC = (followingAddress - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */; storeLiteralbeforeFollowingAddress(backEnd, newObjRef, methodObjPC); /* rewite the tag via the first ldr */ classTagPC = followingAddress - (jumpLongConditionalByteSize(backEnd)); /* begin storeLiteral32:beforeFollowingAddress: */ storeLiteralbeforeFollowingAddress(((AbstractInstruction *) backEnd), newTag, classTagPC); ((AbstractInstruction *) backEnd); rewriteConditionalJumpLongAttarget(backEnd, followingAddress, newTarget); } /* Cogit>>#SubCw:R: */ static AbstractInstruction * NoDbgRegParms gSubCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(SubCwR, wordConstant, reg)); } /* Answer the number of clean blocks found in the literal frame */ /* Cogit>>#scanForCleanBlocks */ static sqInt scanForCleanBlocks(void) { sqInt i; sqInt iLimiT; sqInt lit; sqInt numCleanBlocks; sqInt startPCOrNil; numCleanBlocks = 0; for (i = 1, iLimiT = (literalCountOf(methodObj)); i <= iLimiT; i += 1) { lit = fetchPointerofObject(i, methodObj); startPCOrNil = startPCOrNilOfLiteralin(lit, methodObj); if (!(startPCOrNil == null)) { numCleanBlocks += 1; } } return numCleanBlocks; } /* Cogit>>#setBreakMethod: */ void setBreakMethod(sqInt anObj) { breakMethod = anObj; } /* Cogit>>#setPostCompileHook: */ void setPostCompileHook(void (*aFunction)(CogMethod *)) { postCompileHook = aFunction; } /* If a method is compiled to machine code via a block entry it won't have a selector. A subsequent send can find the method and hence fill in the selector. */ /* self disassembleMethod: cogMethod */ /* Cogit>>#setSelectorOf:to: */ void setSelectorOfto(CogMethod *cogMethod, sqInt aSelectorOop) { compilationBreakpointisMNUCase(aSelectorOop, numBytesOf(aSelectorOop), 0); assert(((cogMethod->cmType)) == CMMethod); (cogMethod->selector = aSelectorOop); if (isYoung(aSelectorOop)) { ensureInYoungReferrers(cogMethod); } } /* Cogit>>#spanForCleanBlockStartingAt: */ static sqInt NoDbgRegParms spanForCleanBlockStartingAt(sqInt startPC) { BytecodeDescriptor *descriptor; sqInt end; sqInt pc; pc = startPC; end = numBytesOf(methodObj); while (pc <= end) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); pc += (descriptor->numBytes); if ((descriptor->isReturn)) { return pc - startPC; } } error("couldn't locate end of clean block"); return 0; } /* Answer a fake value for the method oop in other than the first case in the PIC prototype. Since we use MoveUniqueCw:R: it must not be confused with a method-relative address. */ /* Cogit>>#subsequentPrototypeMethodOop */ static sqInt subsequentPrototypeMethodOop(void) { return (((((usqInt)195929424)) >= ((methodLabel->address))) && ((((usqInt)195929424)) < (youngReferrers())) ? 233496237 : 195929424); } /* Cogit>>#traceLinkedSendOffset */ sqInt traceLinkedSendOffset(void) { return (cmNoCheckEntryOffset + 4 /* callInstructionByteSize */) + (/* begin pushLinkRegisterByteSize */ 4); } /* Encode true and false and 0 to N such that they can't be confused for register numbers (including NoReg) and can be tested for by isTrampolineArgConstant: and decoded by trampolineArgValue: */ /* Cogit>>#trampolineArgConstant: */ static sqInt NoDbgRegParms trampolineArgConstant(sqInt booleanOrInteger) { assert(booleanOrInteger >= 0); return -2 - booleanOrInteger; } /* Cogit>>#trampolineName:numArgs: */ static char * NoDbgRegParms trampolineNamenumArgs(char *routinePrefix, sqInt numArgs) { char *theString; /* begin trampolineName:numArgs:limit: */ theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= (NumSendTrampolines - 2) ? '0' + numArgs : 'N')); return theString; } /* Malloc a string with the contents for the trampoline table */ /* Cogit>>#trampolineName:numArgs:limit: */ static char * NoDbgRegParms trampolineNamenumArgslimit(char *routinePrefix, int numArgs, sqInt argsLimit) { char *theString; theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= argsLimit ? '0' + numArgs : 'N')); return theString; } /* Cogit>>#trampolineName:numRegArgs: */ static char * NoDbgRegParms trampolineNamenumRegArgs(char *routinePrefix, sqInt numArgs) { sqInt argsLimit; char *theString; /* begin trampolineName:numArgs:limit: */ argsLimit = 2 /* numRegArgs */; theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= argsLimit ? '0' + numArgs : 'N')); return theString; } /* Cogit>>#unknownBytecode */ static sqInt unknownBytecode(void) { return EncounteredUnknownBytecode; } /* Unlink all sends in cog methods. */ /* Cogit>>#unlinkAllSends */ void unlinkAllSends(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); voidOpenPICList(); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if (((cogMethod->cmType)) != CMFree) { freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } /* Cogit>>#unlinkIfFreeOrLinkedSend:pc:of: */ static sqInt NoDbgRegParms unlinkIfFreeOrLinkedSendpcof(sqInt annotation, char *mcpc, sqInt theSelector) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if ((((targetMethod1->cmType)) == CMFree) || (((targetMethod1->selector)) == theSelector)) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod1->selector), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Cogit>>#unlinkIfInvalidClassSend:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfInvalidClassSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send, but maybe a super send or linked to an OpenPIC, in which case the cache tag will be a selector.... */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (!(((annotation == IsSuperSend) || (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend)))) || (((targetMethod1->cmType)) == CMOpenPIC))) { if (!(isValidClassTag(longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8))))))) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } } return 0; } /* Cogit>>#unlinkIfLinkedSendToFree:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfLinkedSendToFreepcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmType)) == CMFree) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Cogit>>#unlinkIfLinkedSend:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfLinkedSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } return 0; } /* Cogit>>#unlinkIfLinkedSend:pc:to: */ static sqInt NoDbgRegParms unlinkIfLinkedSendpcto(sqInt annotation, char *mcpc, sqInt theCogMethod) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if ((((sqInt)targetMethod1)) == theCogMethod) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Unlink all sends in cog methods whose class tag is that of a forwarded class. */ /* Cogit>>#unlinkSendsLinkedForInvalidClasses */ void unlinkSendsLinkedForInvalidClasses(void) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); codeModified = (freedPIC = 0); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfInvalidClassSendpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICHasForwardedClass(cogMethod))) { freeMethod(cogMethod); freedPIC = 1; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedPIC) { unlinkSendsToFree(); } else { if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } } /* Unlink all sends in cog methods. Free all Closed PICs with the selector, or with an MNU case if isMNUSelector. First check if any method actually has the selector; if not there can't be any linked send to it. This routine (including descendents) is performance critical. It contributes perhaps 30% of entire execution time in Compiler recompileAll. */ /* Cogit>>#unlinkSendsOf:isMNUSelector: */ void unlinkSendsOfisMNUSelector(sqInt selector, sqInt isMNUSelector) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt mustScanAndUnlink; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); mustScanAndUnlink = 0; if (isMNUSelector) { while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if (((cogMethod->cpicHasMNUCaseOrCMIsFullBlock)) && (((cogMethod->cmType)) == CMClosedPIC)) { assert(((cogMethod->cmType)) == CMClosedPIC); freeMethod(cogMethod); mustScanAndUnlink = 1; } else { if (((cogMethod->selector)) == selector) { mustScanAndUnlink = 1; if (((cogMethod->cmType)) == CMClosedPIC) { freeMethod(cogMethod); } } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } else { while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->selector)) == selector)) { mustScanAndUnlink = 1; if (((cogMethod->cmType)) == CMClosedPIC) { freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } if (!mustScanAndUnlink) { return; } codeModified = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfFreeOrLinkedSendpcof(annotation, (((char *) mcpc)), selector); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Unlink all sends in cog methods to free methods and/or pics. */ /* Cogit>>#unlinkSendsToFree */ void unlinkSendsToFree(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } codeModified = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendToFreepcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if (((cogMethod->cmType)) == CMClosedPIC) { assert(noTargetsFreeInClosedPIC(cogMethod)); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Unlink all sends in cog methods to a particular target method. If targetMethodObject isn't actually a method (perhaps being used via invokeAsMethod) then there's nothing to do. */ /* Cogit>>#unlinkSendsTo:andFreeIf: */ void unlinkSendsToandFreeIf(sqInt targetMethodObject, sqInt freeIfTrue) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; CogMethod *targetMethod; if (!((isOopCompiledMethod(targetMethodObject)) && (methodHasCogMethod(targetMethodObject)))) { return; } targetMethod = cogMethodOf(targetMethodObject); if (!(methodZoneBase)) { return; } codeModified = (freedPIC = 0); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendpcto(annotation, (((char *) mcpc)), (((sqInt)targetMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICHasTarget(cogMethod, targetMethod))) { freeMethod(cogMethod); freedPIC = 1; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freeIfTrue) { freeMethod(targetMethod); } if (freedPIC) { unlinkSendsToFree(); } else { if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } } /* Cogit>>#XorCw:R: */ static AbstractInstruction * NoDbgRegParms gXorCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(XorCwR, wordConstant, reg)); } /* Access for the object representations when they need to prepend code to trampolines. */ /* Eliminate stale dependent info. */ /* Cogit>>#zeroOpcodeIndex */ static void zeroOpcodeIndex(void) { sqInt i; for (i = 0; i < opcodeIndex; i += 1) { ((abstractOpcodes[i]).dependent = null); } zeroOpcodeIndexForNewOpcodes(); } /* Access for the object representations when they need to prepend code to trampolines. */ /* Cogit>>#zeroOpcodeIndexForNewOpcodes */ static void zeroOpcodeIndexForNewOpcodes(void) { opcodeIndex = 0; /* begin resetLiterals */ /* an impossibly high value */ firstOpcodeIndex = 1U << 16; nextLiteralIndex = (lastDumpedLiteralIndex = 0); } /* CogMethod>>#counters */ static sqInt NoDbgRegParms counters(CogMethod * self_in_counters) { return 0; } /* CogMethodZone>>#addAllToYoungReferrers */ void addAllToYoungReferrers(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)) { ensureInYoungReferrers(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#addToOpenPICList: */ static void NoDbgRegParms addToOpenPICList(CogMethod *anOpenPIC) { assert(((anOpenPIC->cmType)) == CMOpenPIC); assert((openPICList == null) || (((openPICList->cmType)) == CMOpenPIC)); (anOpenPIC->nextOpenPIC = ((usqInt)openPICList)); openPICList = anOpenPIC; } /* CogMethodZone>>#addToYoungReferrers: */ static void NoDbgRegParms addToYoungReferrers(CogMethod *cogMethod) { assert(youngReferrers <= limitAddress); assert((occurrencesInYoungReferrers(cogMethod)) == 0); assert((cogMethod->cmRefersToYoung)); assert((youngReferrers <= limitAddress) && (youngReferrers >= (limitAddress - (methodCount * BytesPerWord)))); if (!(asserta((limitAddress - (methodCount * BytesPerWord)) >= mzFreeStart))) { error("no room on youngReferrers list"); } youngReferrers -= BytesPerWord; longAtput(youngReferrers, ((usqInt)cogMethod)); } /* CogMethodZone>>#allocate: */ static usqInt NoDbgRegParms allocate(sqInt numBytes) { usqInt allocation; sqInt roundedBytes; roundedBytes = (numBytes + 7) & -8; if ((mzFreeStart + roundedBytes) >= (limitAddress - (methodCount * BytesPerWord))) { return 0; } allocation = mzFreeStart; mzFreeStart += roundedBytes; methodCount += 1; return allocation; } /* Free all methods */ /* CogMethodZone>>#clearCogCompiledCode */ static void clearCogCompiledCode(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) == CMMethod) { freeMethod(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } manageFromto(baseAddress, limitAddress); } /* CogMethodZone>>#compactCompiledCode */ static void compactCompiledCode(void) { unsigned short bytes; CogMethod *dest; sqLong objectHeaderValue; CogMethod *source; compactionInProgress = 1; objectHeaderValue = nullHeaderForMachineCodeMethod(); source = ((CogMethod *) baseAddress); voidOpenPICList(); methodCount = 0; while ((source < (limitZony())) && (((source->cmType)) != CMFree)) { assert((cogMethodDoesntLookKosher(source)) == 0); (source->objectHeader = objectHeaderValue); if (((source->cmUsageCount)) > 0) { (source->cmUsageCount = ((source->cmUsageCount)) / 2); } if (((source->cmType)) == CMOpenPIC) { addToOpenPICList(source); } methodCount += 1; source = ((CogMethod *) (roundUpLength((((sqInt)source)) + ((source->blockSize))))); } if (source >= (limitZony())) { haltmsg("no free methods; cannot compact."); return; } dest = source; while (source < (limitZony())) { assert((maybeFreeCogMethodDoesntLookKosher(source)) == 0); bytes = (source->blockSize); if (((source->cmType)) != CMFree) { methodCount += 1; memmove(dest, source, bytes); (dest->objectHeader = objectHeaderValue); if (((dest->cmType)) == CMMethod) { /* For non-Newspeak there should be a one-to-one mapping between bytecoded and cog methods. For Newspeak not necessarily, but only for anonymous accessors. */ /* Only update the original method's header if it is referring to this CogMethod. */ if ((((sqInt)(rawHeaderOf((dest->methodObject))))) == (((sqInt)source))) { rawHeaderOfput((dest->methodObject), ((sqInt)dest)); } else { assert((noAssertMethodClassAssociationOf((dest->methodObject))) == (nilObject())); } } else { if (((dest->cmType)) == CMOpenPIC) { addToOpenPICList(dest); } } if (((dest->cmUsageCount)) > 0) { (dest->cmUsageCount = ((dest->cmUsageCount)) / 2); } dest = ((CogMethod *) ((((usqInt)dest)) + bytes)); } source = ((CogMethod *) ((((usqInt)source)) + bytes)); } mzFreeStart = ((usqInt)dest); methodBytesFreedSinceLastCompaction = 0; compactionInProgress = 0; } /* CogMethodZone>>#ensureInYoungReferrers: */ static void NoDbgRegParms ensureInYoungReferrers(CogMethod *cogMethod) { if (!((cogMethod->cmRefersToYoung))) { assert((occurrencesInYoungReferrers(cogMethod)) == 0); (cogMethod->cmRefersToYoung = 1); addToYoungReferrers(cogMethod); } } /* CogMethodZone>>#followForwardedLiteralsInOpenPICList */ static void followForwardedLiteralsInOpenPICList(void) { CogMethod *openPIC; openPIC = openPICList; while (openPIC != null) { followForwardedLiteralsIn(openPIC); openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } } /* CogMethodZone>>#freeMethod: */ void freeMethod(CogMethod *cogMethod) { assert(((cogMethod->cmType)) != CMFree); assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if (((cogMethod->cmType)) == CMMethod) { /* For non-Newspeak there should ne a one-to-one mapping between bytecoded and cog methods. For Newspeak not necessarily, but only for anonymous accessors. */ /* Only reset the original method's header if it is referring to this CogMethod. */ if ((((sqInt)(rawHeaderOf((cogMethod->methodObject))))) == (((sqInt)cogMethod))) { rawHeaderOfput((cogMethod->methodObject), (cogMethod->methodHeader)); } else { assert((noAssertMethodClassAssociationOf((cogMethod->methodObject))) == (nilObject())); } } if (((cogMethod->cmType)) == CMOpenPIC) { removeFromOpenPICList(cogMethod); } (cogMethod->cmRefersToYoung = 0); (cogMethod->cmType = CMFree); methodBytesFreedSinceLastCompaction += (cogMethod->blockSize); } /* Free methods, preferring older methods for compaction, up to some fraction, currently a quarter. */ /* CogMethodZone>>#freeOlderMethodsForCompaction */ static void freeOlderMethodsForCompaction(void) { sqInt amountToFree; CogMethod *cogMethod; sqInt freeableUsage; sqInt freedSoFar; sqInt initialFreeSpace; sqInt zoneSize; zoneSize = limitAddress - baseAddress; initialFreeSpace = (limitAddress - mzFreeStart) + methodBytesFreedSinceLastCompaction; freedSoFar = initialFreeSpace; /* 4 needs to be e.g. a start-up parameter */ amountToFree = zoneSize / 4; freeableUsage = 0; do { cogMethod = ((CogMethod *) baseAddress); while (((((usqInt)cogMethod)) < mzFreeStart) && (freedSoFar < amountToFree)) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->cmUsageCount)) <= freeableUsage)) { freeMethod(cogMethod); freedSoFar += (cogMethod->blockSize); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } while((freedSoFar < amountToFree) && (((freeableUsage += 1)) < CMMaxUsageCount)); } /* Answer that all entries in youngReferrers are in-use and have the cmRefersToYoung flag set. Used to check that the youngreferrers pruning routines work correctly. */ /* CogMethodZone>>#kosherYoungReferrers */ static sqInt kosherYoungReferrers(void) { CogMethod *cogMethod; usqInt pointer; if ((youngReferrers > limitAddress) || (youngReferrers < mzFreeStart)) { return 0; } pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (!((((cogMethod->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung)))) { return 0; } pointer += BytesPerWord; } return 1; } /* CogMethodZone>>#manageFrom:to: */ static void NoDbgRegParms manageFromto(sqInt theStartAddress, sqInt theLimitAddress) { mzFreeStart = (baseAddress = theStartAddress); youngReferrers = (limitAddress = theLimitAddress); openPICList = null; methodBytesFreedSinceLastCompaction = 0; methodCount = 0; } /* CogMethodZone>>#methodFor: */ CogMethod * methodFor(void *address) { CogMethod *cogMethod; CogMethod *nextMethod; cogMethod = ((CogMethod *) baseAddress); while ((cogMethod < (limitZony())) && ((((usqInt)cogMethod)) <= (((usqInt)address)))) { /* begin methodAfter: */ nextMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); if (nextMethod == cogMethod) { return 0; } if (((((usqInt)address)) >= (((usqInt)cogMethod))) && ((((usqInt)address)) < (((usqInt)nextMethod)))) { return cogMethod; } cogMethod = nextMethod; } return 0; } /* CogMethodZone>>#methodsCompiledToMachineCodeInto: */ sqInt methodsCompiledToMachineCodeInto(sqInt arrayObj) { CogMethod *cogMethod; sqInt methodIndex; methodIndex = 0; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { storePointerUncheckedofObjectwithValue(methodIndex, arrayObj, (cogMethod->methodObject)); methodIndex += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return methodIndex; } /* CogMethodZone>>#numMethods */ sqInt numMethods(void) { return methodCount; } /* CogMethodZone>>#numMethodsOfType: */ sqInt numMethodsOfType(sqInt cogMethodType) { CogMethod *cogMethod; sqInt n; n = 0; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == cogMethodType) { n += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return n; } /* CogMethodZone>>#occurrencesInYoungReferrers: */ static sqInt NoDbgRegParms occurrencesInYoungReferrers(CogMethod *cogMethod) { sqInt count; usqInt pointer; assert(youngReferrers <= limitAddress); count = 0; pointer = youngReferrers; while (pointer < limitAddress) { if ((((sqInt)cogMethod)) == (longAt(pointer))) { count += 1; } pointer += BytesPerWord; } return count; } /* CogMethodZone>>#openPICWithSelector: */ static CogMethod * NoDbgRegParms openPICWithSelector(sqInt aSelector) { CogMethod *openPIC; openPIC = openPICList; do { if ((openPIC == null) || (((openPIC->selector)) == aSelector)) { return openPIC; } openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } while(1); return 0; } /* Some methods have been freed. Compute how much each survivor needs to move during the ensuing compaction and record it in the objectHeader field. For Sista, where we want PICs to last so they can be observed, we need to keep PICs unless they are definitely unused. So we need to identify unused PICs. So in planCompact, zero the usage counts of all PICs, saving the actual usage count in blockEntryOffset. Then in relocateMethodsPreCompaction (actually in relocateIfCallOrMethodReference:mcpc:delta:) restore the usage counts of used PICs. Finally in compactCompiledCode, clear the blockEntryOffset of the unused PICs; they will then have a zero count and be reclaimed in the next code compaction. */ /* CogMethodZone>>#planCompaction */ static void planCompaction(void) { CogMethod *cogMethod; sqInt delta; delta = 0; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) == CMFree) { delta -= (cogMethod->blockSize); } else { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->objectHeader = delta); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethods */ void printCogMethods(void) { CogMethod *cogMethod; sqInt nc; sqInt nf; sqInt nm; sqInt no; sqInt nu; nm = (nc = (no = (nf = (nu = 0)))); cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { printCogMethod(cogMethod); switch ((cogMethod->cmType)) { case CMFree: nf += 1; break; case CMMethod: nm += 1; break; case CMClosedPIC: nc += 1; break; case CMOpenPIC: no += 1; break; default: nu += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } print("CMMethod "); printNum(nm); print(" CMClosedPIC "); printNum(nc); print(" CMOpenPIC "); printNum(no); print(" CMFree "); printNum(nf); if (nu > 0) { print(" UNKNOWN "); printNum(nu); } print(" total "); printNum((((nm + nc) + no) + nf) + nu); cr(); } /* CogMethodZone>>#printCogMethodsOfType: */ void printCogMethodsOfType(sqInt cmType) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == cmType) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithMethod: */ void printCogMethodsWithMethod(sqInt methodOop) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->methodObject)) == methodOop)) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithPrimitive: */ void printCogMethodsWithPrimitive(sqInt primIdx) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (primIdx == (primitiveIndexOfMethodheader((cogMethod->methodObject), (cogMethod->methodHeader))))) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithSelector: */ void printCogMethodsWithSelector(sqInt selectorOop) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->selector)) == selectorOop)) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogYoungReferrers */ void printCogYoungReferrers(void) { CogMethod *cogMethod; usqInt pointer; pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (!((cogMethod->cmRefersToYoung))) { print("*"); } if (((cogMethod->cmType)) == CMFree) { print("!"); } if (!(((cogMethod->cmRefersToYoung)) && (((cogMethod->cmType)) != CMFree))) { print(" "); } printCogMethod(cogMethod); pointer += BytesPerWord; } } /* CogMethodZone>>#printOpenPICList */ sqInt printOpenPICList(void) { sqInt n; CogMethod *openPIC; n = 0; openPIC = openPICList; while (!(openPIC == null)) { n += 1; printCogMethod(openPIC); openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } return n; } /* CogMethodZone>>#pruneYoungReferrers */ static sqInt pruneYoungReferrers(void) { usqInt dest; usqInt next; usqInt source; assert(youngReferrers <= limitAddress); if (youngReferrers == limitAddress) { return null; } dest = limitAddress; while (1) { next = dest - BytesPerWord; if (!((next >= youngReferrers) && (((((CogMethod *) (longAt(next))))->cmRefersToYoung)))) break; dest = next; } assert(dest >= youngReferrers); source = dest - BytesPerWord; while (source >= youngReferrers) { if (((((CogMethod *) (longAt(source))))->cmRefersToYoung)) { assert(source < (dest - BytesPerWord)); longAtput((dest -= BytesPerWord), longAt(source)); } source -= BytesPerWord; } youngReferrers = dest; assert(kosherYoungReferrers()); return 0; } /* CogMethodZone>>#relocateAndPruneYoungReferrers */ static sqInt relocateAndPruneYoungReferrers(void) { CogMethod *cogMethod; usqInt dest; usqInt next; usqInt source; assert(youngReferrers <= limitAddress); if (youngReferrers == limitAddress) { return null; } dest = limitAddress; while (1) { next = dest - BytesPerWord; if (!((next >= youngReferrers) && (((((cogMethod = ((CogMethod *) (longAt(next))))->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung))))) break; if (((cogMethod->objectHeader)) != 0) { longAtput(next, (((sqInt)cogMethod)) + ((cogMethod->objectHeader))); } dest = next; } assert(dest >= youngReferrers); source = dest - BytesPerWord; while (source >= youngReferrers) { cogMethod = ((CogMethod *) (longAt(source))); if ((((cogMethod->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung))) { assert(source < (dest - BytesPerWord)); if (((cogMethod->objectHeader)) != 0) { cogMethod = ((CogMethod *) ((((sqInt)cogMethod)) + (((sqInt)((cogMethod->objectHeader)))))); } longAtput((dest -= BytesPerWord), ((sqInt)cogMethod)); } source -= BytesPerWord; } youngReferrers = dest; return 0; } /* All surviving methods have had the amount they are going to relocate by stored in their objectHeader fields. Relocate all relative calls so that after the compaction of both the method containing each call and the call target the calls invoke the same target. */ /* CogMethodZone>>#relocateMethodsPreCompaction */ static sqInt relocateMethodsPreCompaction(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) != CMFree) { if (((cogMethod->cmType)) == CMClosedPIC) { relocateCallsInClosedPIC(cogMethod); } else { relocateCallsAndSelfReferencesInMethod(cogMethod); } } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } relocateAndPruneYoungReferrers(); return 1; } /* CogMethodZone>>#removeFromOpenPICList: */ static sqInt NoDbgRegParms removeFromOpenPICList(CogMethod *anOpenPIC) { CogMethod *prevPIC; assert(((anOpenPIC->cmType)) == CMOpenPIC); if (!(openPICList)) { return null; } assert((((openPICList->cmType)) == CMOpenPIC) && ((((openPICList->nextOpenPIC)) == null) || ((((((CogMethod *) ((openPICList->nextOpenPIC))))->cmType)) == CMOpenPIC))); if (anOpenPIC == openPICList) { /* N.B. Use self rather than coInterpreter to avoid attempting to cast nil. Conversion to CogMethod done in the nextOpenPIC accessor. */ openPICList = ((CogMethod *) ((anOpenPIC->nextOpenPIC))); return null; } prevPIC = openPICList; do { assert((prevPIC != null) && (((prevPIC->cmType)) == CMOpenPIC)); if (((prevPIC->nextOpenPIC)) == (((usqInt)anOpenPIC))) { (prevPIC->nextOpenPIC = (anOpenPIC->nextOpenPIC)); return null; } prevPIC = ((CogMethod *) ((prevPIC->nextOpenPIC))); } while(1); return 0; } /* CogMethodZone>>#voidOpenPICList */ static void voidOpenPICList(void) { openPICList = null; } /* CogMethodZone>>#voidYoungReferrersPostTenureAll */ static void voidYoungReferrersPostTenureAll(void) { CogMethod *cogMethod; usqInt pointer; assert(youngReferrers <= limitAddress); pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (((cogMethod->cmType)) != CMFree) { (cogMethod->cmRefersToYoung = 0); } pointer += BytesPerWord; } youngReferrers = limitAddress; } /* CogMethodZone>>#whereIsMaybeCodeThing: */ char * whereIsMaybeCodeThing(sqInt anOop) { if (oopisGreaterThanOrEqualToandLessThan(anOop, codeBase, limitAddress)) { if (oopisLessThan(anOop, methodZoneBase)) { return " is in generated runtime"; } if (oopisLessThan(anOop, mzFreeStart)) { return " is in generated methods"; } if (oopisLessThan(anOop, youngReferrers)) { return " is in code zone"; } return " is in young referrers"; } return null; } /* CogObjectRepresentation>>#checkValidObjectReference: */ static sqInt NoDbgRegParms checkValidObjectReference(sqInt anOop) { return (!(isImmediate(anOop))) && ((heapMapAtWord(pointerForOop(anOop))) != 0); } /* CogObjectRepresentation>>#genCmpClassFloatCompactIndexR: */ static AbstractInstruction * NoDbgRegParms genCmpClassFloatCompactIndexR(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ClassFloatCompactIndex, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ClassFloatCompactIndex)); } return anInstruction; } /* CogObjectRepresentation>>#genCmpClassMethodContextCompactIndexR: */ static AbstractInstruction * NoDbgRegParms genCmpClassMethodContextCompactIndexR(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ClassMethodContextCompactIndex)); } return anInstruction; } /* CogObjectRepresentation>>#genDoubleArithmetic:preOpCheck: */ static sqInt NoDbgRegParms genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)) { AbstractInstruction *doOp; AbstractInstruction *jumpFailAlloc; AbstractInstruction *jumpFailCheck; AbstractInstruction *jumpFailClass; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpNonInt; jumpFailCheck = ((AbstractInstruction *) 0); jumpNonInt = ((AbstractInstruction *) 0); /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); jumpImmediate = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFailClass = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); /* begin Label */ doOp = genoperandoperand(Label, (labelCounter += 1), bytecodePC); if (!(preOpCheckOrNil == null)) { jumpFailCheck = preOpCheckOrNil(DPFPReg0, DPFPReg1); } genoperandoperand(arithmeticOperator, DPFPReg1, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* maybeGenConvertIfSmallFloatIn:scratchReg:into:andJumpTo: */ /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonInt = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(ClassReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, ClassReg, DPFPReg1); /* begin Jump: */ genoperand(Jump, ((sqInt)doOp)); jmpTarget(jumpFailAlloc, jmpTarget(jumpFailClass, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jmpTarget(jumpNonInt, ((AbstractInstruction *) (((jumpFailClass->operands))[0]))); if (!(preOpCheckOrNil == null)) { jmpTarget(jumpFailCheck, ((AbstractInstruction *) (((jumpFailClass->operands))[0]))); } return 0; } /* CogObjectRepresentation>>#genDoubleComparison:invert: */ static sqInt NoDbgRegParms genDoubleComparisoninvert(AbstractInstruction * NoDbgRegParms (*jumpOpcodeGenerator)(void *), sqInt invertComparison) { AbstractInstruction *anInstruction; AbstractInstruction *compare; sqInt constant; AbstractInstruction *jumpCond; AbstractInstruction *jumpFail; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpNonInt; jumpNonInt = ((AbstractInstruction *) 0); /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); jumpImmediate = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); if (invertComparison) { /* May need to invert for NaNs */ /* begin CmpRd:Rd: */ compare = genoperandoperand(CmpRdRd, DPFPReg0, DPFPReg1); } else { /* begin CmpRd:Rd: */ compare = genoperandoperand(CmpRdRd, DPFPReg1, DPFPReg0); } /* FP jumps are a little weird */ jumpCond = jumpOpcodeGenerator(0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCond, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* maybeGenConvertIfSmallFloatIn:scratchReg:into:andJumpTo: */ /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonInt = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, Arg0Reg, DPFPReg1); /* begin Jump: */ genoperand(Jump, ((sqInt)compare)); jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jmpTarget(jumpNonInt, ((AbstractInstruction *) (((jumpFail->operands))[0]))); return CompletePrimitive; } /* Get the method header (first word) of a CompiledMethod into headerReg. Deal with the method possibly being cogged. */ /* CogObjectRepresentation>>#genGetMethodHeaderOf:into:scratch: */ static sqInt NoDbgRegParms genGetMethodHeaderOfintoscratch(sqInt methodReg, sqInt headerReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpNotCogged; sqInt offset; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, BaseHeaderSize, methodReg, headerReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BaseHeaderSize)); } jumpNotCogged = genJumpSmallInteger(headerReg); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodHeader); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, headerReg, headerReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } jmpTarget(jumpNotCogged, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genLoadSlot:sourceReg:destReg: */ static sqInt NoDbgRegParms genLoadSlotsourceRegdestReg(sqInt index, sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, (index * BytesPerWord) + BaseHeaderSize, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } return 0; } /* CogObjectRepresentation>>#genPrimitiveAdd */ static sqInt genPrimitiveAdd(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); /* begin AddR:R: */ genoperandoperand(AddRR, ReceiverResultReg, ClassReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveAsFloat */ static sqInt genPrimitiveAsFloat(void) { AbstractInstruction *jumpFailAlloc; /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, TempReg, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFailAlloc, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genPrimitiveBitAnd */ static sqInt genPrimitiveBitAnd(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveBitOr */ static sqInt genPrimitiveBitOr(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin OrR:R: */ genoperandoperand(OrRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* rTemp := rArg0 rClass := tTemp rTemp := rTemp & 1 jz nonInt rClass >>= 1 cmp 0,rClass jge neg cmp 31,rClass // numSmallIntegerBits, jge for sign jge tooBig rTemp := rReceiver rTemp <<= rClass rTemp >>= rClass (arithmetic) cmp rTemp,rReceiver jnz ovfl rReceiver := rReceiver - 1 rReceiver := rReceiver <<= rClass rReceiver := rReceiver + 1 ret neg: rClass := 0 - rClass cmp 31,rClass // numSmallIntegerBits jge inRange rClass := 31 inRange rReceiver := rReceiver >>= rClass. rReceiver := rReceiver | smallIntegerTags. ret ovfl tooBig nonInt: fail */ /* CogObjectRepresentation>>#genPrimitiveBitShift */ static sqInt genPrimitiveBitShift(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *jumpInRange; AbstractInstruction *jumpNegative; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; AbstractInstruction *jumpTooBig; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpNegative))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpNegative: */ jumpNegative = genConditionalBranchoperand(JumpNegative, ((sqInt)0)); /* begin CmpCq:R: */ anInstruction1 = genoperandoperand(CmpCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } /* begin JumpGreaterOrEqual: */ jumpTooBig = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin LogicalShiftLeftR:R: */ genoperandoperand(LogicalShiftLeftRR, ClassReg, TempReg); /* begin ArithmeticShiftRightR:R: */ genoperandoperand(ArithmeticShiftRightRR, ClassReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, ReceiverResultReg); /* begin JumpNonZero: */ jumpOvfl = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); /* begin LogicalShiftLeftR:R: */ genoperandoperand(LogicalShiftLeftRR, ClassReg, ReceiverResultReg); genAddSmallIntegerTagsTo(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNegative, genoperand(NegateR, ClassReg)); /* begin CmpCq:R: */ anInstruction2 = genoperandoperand(CmpCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } /* begin JumpLessOrEqual: */ jumpInRange = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin MoveCq:R: */ anInstruction3 = genoperandoperand(MoveCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } jmpTarget(jumpInRange, genoperandoperand(ArithmeticShiftRightRR, ClassReg, ReceiverResultReg)); genClearAndSetSmallIntegerTagsIn(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, jmpTarget(jumpTooBig, jmpTarget(jumpOvfl, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveBitXor */ static sqInt genPrimitiveBitXor(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); /* begin XorR:R: */ genoperandoperand(XorRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveClass */ static sqInt genPrimitiveClass(void) { sqInt reg; sqInt reg1; reg = ReceiverResultReg; if (methodOrBlockNumArgs > 0) { if (methodOrBlockNumArgs > 1) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ reg1 = (reg = Arg0Reg); assert(0 < (numRegArgs())); } if ((genGetClassObjectOfintoscratchReginstRegIsReceiver(reg, ReceiverResultReg, TempReg, reg == ReceiverResultReg)) == BadRegisterSet) { genGetClassObjectOfintoscratchReginstRegIsReceiver(reg, ClassReg, TempReg, reg == ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* CogObjectRepresentation>>#genPrimitiveDiv */ static sqInt genPrimitiveDiv(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *convert; AbstractInstruction *jumpExact; AbstractInstruction *jumpIsSI; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } } /* begin JumpGreaterOrEqual: */ jumpSameSign = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } jmpTarget(jumpSameSign, (convert = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpIsSI = genJumpIsSmallIntegerValuescratch(TempReg, Arg1Reg); jmpTarget(jumpIsSI, convert); jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveDivide */ static sqInt genPrimitiveDivide(void) { AbstractInstruction *anInstruction; AbstractInstruction *jumpInexact; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOverflow; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpInexact = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); jumpOverflow = genJumpNotSmallIntegerValuescratch(TempReg, Arg1Reg); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOverflow, jmpTarget(jumpInexact, jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveEqual */ static sqInt genPrimitiveEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpZero, gJumpFPEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatAdd */ static sqInt genPrimitiveFloatAdd(void) { return genDoubleArithmeticpreOpCheck(AddRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveFloatDivide */ static sqInt genPrimitiveFloatDivide(void) { return genDoubleArithmeticpreOpCheck(DivRdRd, genDoubleFailIfZeroArgRcvrarg); } /* CogObjectRepresentation>>#genPrimitiveFloatEqual */ static sqInt genPrimitiveFloatEqual(void) { return genDoubleComparisoninvert(gJumpFPEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatGreaterOrEqual */ static sqInt genPrimitiveFloatGreaterOrEqual(void) { return genDoubleComparisoninvert(gJumpFPGreaterOrEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatGreaterThan */ static sqInt genPrimitiveFloatGreaterThan(void) { return genDoubleComparisoninvert(gJumpFPGreater, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatLessOrEqual */ static sqInt genPrimitiveFloatLessOrEqual(void) { return genDoubleComparisoninvert(gJumpFPGreaterOrEqual, 1); } /* CogObjectRepresentation>>#genPrimitiveFloatLessThan */ static sqInt genPrimitiveFloatLessThan(void) { return genDoubleComparisoninvert(gJumpFPGreater, 1); } /* CogObjectRepresentation>>#genPrimitiveFloatMultiply */ static sqInt genPrimitiveFloatMultiply(void) { return genDoubleArithmeticpreOpCheck(MulRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveFloatNotEqual */ static sqInt genPrimitiveFloatNotEqual(void) { return genDoubleComparisoninvert(gJumpFPNotEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatSquareRoot */ static sqInt genPrimitiveFloatSquareRoot(void) { AbstractInstruction *jumpFailAlloc; /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); /* begin SqrtRd: */ genoperand(SqrtRd, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFailAlloc, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genPrimitiveFloatSubtract */ static sqInt genPrimitiveFloatSubtract(void) { return genDoubleArithmeticpreOpCheck(SubRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveGreaterOrEqual */ static sqInt genPrimitiveGreaterOrEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpGreaterOrEqual, gJumpFPGreaterOrEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveGreaterThan */ static sqInt genPrimitiveGreaterThan(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpGreater, gJumpFPGreater, 0); } /* CogObjectRepresentation>>#genPrimitiveIdentical */ static sqInt genPrimitiveIdentical(void) { return genPrimitiveIdenticalOrNotIf(0); } /* CogObjectRepresentation>>#genPrimitiveLessOrEqual */ static sqInt genPrimitiveLessOrEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpLessOrEqual, gJumpFPGreaterOrEqual, 1); } /* CogObjectRepresentation>>#genPrimitiveLessThan */ static sqInt genPrimitiveLessThan(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpLess, gJumpFPGreater, 1); } /* CogObjectRepresentation>>#genPrimitiveMod */ static sqInt genPrimitiveMod(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpExact; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, Arg1Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genRemoveSmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpGreaterOrEqual: */ jumpSameSign = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ClassReg); jmpTarget(jumpSameSign, jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genSetSmallIntegerTagsIn(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveMultiply */ static sqInt genPrimitiveMultiply(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(processorHasMultiplyAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); genRemoveSmallIntegerTagsInScratchReg(Arg1Reg); /* begin MulR:R: */ genMulRR(backEnd, Arg1Reg, ClassReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); genSetSmallIntegerTagsIn(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* subclasses override if they can */ /* CogObjectRepresentation>>#genPrimitiveNewMethod */ static sqInt genPrimitiveNewMethod(void) { return UnimplementedPrimitive; } /* CogObjectRepresentation>>#genPrimitiveNotEqual */ static sqInt genPrimitiveNotEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpNonZero, gJumpFPNotEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveNotIdentical */ static sqInt genPrimitiveNotIdentical(void) { return genPrimitiveIdenticalOrNotIf(1); } /* CogObjectRepresentation>>#genPrimitiveQuo */ static sqInt genPrimitiveQuo(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *convert; AbstractInstruction *jumpExact; AbstractInstruction *jumpIsSI; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin Label */ convert = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpIsSI = genJumpIsSmallIntegerValuescratch(TempReg, Arg1Reg); jmpTarget(jumpIsSI, convert); jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveSubtract */ static sqInt genPrimitiveSubtract(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, TempReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); genAddSmallIntegerTagsTo(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genSmallIntegerComparison: */ static sqInt NoDbgRegParms genSmallIntegerComparison(sqInt jumpOpcode) { AbstractInstruction *anInstruction; sqInt constant; AbstractInstruction *jumpFail; AbstractInstruction *jumpTrue; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpFail = genJumpNotSmallInteger(Arg0Reg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); jumpTrue = genConditionalBranchoperand(jumpOpcode, 0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpTrue, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* Stack looks like return address */ /* CogObjectRepresentation>>#genSmallIntegerComparison:orDoubleComparison:invert: */ static sqInt NoDbgRegParms genSmallIntegerComparisonorDoubleComparisoninvert(sqInt jumpOpcode, AbstractInstruction * NoDbgRegParms (*jumpFPOpcodeGenerator)(void *), sqInt invertComparison) { AbstractInstruction *anInstruction; sqInt constant; AbstractInstruction *jumpCond; AbstractInstruction *jumpFail; AbstractInstruction *jumpNonInt; sqInt r; jumpNonInt = ((AbstractInstruction *) 0); r = genSmallIntegerComparison(jumpOpcode); if (r < 0) { return r; } # if defined(DPFPReg0) /* Fall through on non-SmallInteger argument. Argument may be a Float : let us check or fail */ jumpNonInt = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genConvertSmallIntegerToIntegerInReg(ReceiverResultReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, ReceiverResultReg, DPFPReg0); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); if (invertComparison) { /* May need to invert for NaNs */ /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg0, DPFPReg1); } else { /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg1, DPFPReg0); } /* FP jumps are a little weird */ jumpCond = jumpFPOpcodeGenerator(0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCond, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNonInt, jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); # endif /* defined(DPFPReg0) */ return CompletePrimitive; } /* CogObjectRepresentation>>#isUnannotatableConstant: */ static sqInt NoDbgRegParms isUnannotatableConstant(CogSimStackEntry *simStackEntry) { return (((simStackEntry->type)) == SSConstant) && ((isImmediate((simStackEntry->constant))) || (!(shouldAnnotateObjectReference((simStackEntry->constant))))); } /* Character gets mapped to zero. See inlineCacheTagForInstance:. */ /* CogObjectRepresentationFor32BitSpur>>#classForInlineCacheTag: */ static sqInt NoDbgRegParms classForInlineCacheTag(sqInt inlineCacheTag) { return classOrNilAtIndex((inlineCacheTag == 0 ? characterTag() : inlineCacheTag)); } /* CogObjectRepresentationFor32BitSpur>>#genAddSmallIntegerTagsTo: */ static sqInt NoDbgRegParms genAddSmallIntegerTagsTo(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Set the SmallInteger tag bits when the tag bits may be filled with garbage. */ /* CogObjectRepresentationFor32BitSpur>>#genClearAndSetSmallIntegerTagsIn: */ static sqInt NoDbgRegParms genClearAndSetSmallIntegerTagsIn(sqInt scratchReg) { return genSetSmallIntegerTagsIn(scratchReg); } /* Convert the Character in reg to a SmallInteger, assuming the Character's value is a valid character. */ /* self assume: objectMemory smallIntegerTag = 1 */ /* CogObjectRepresentationFor32BitSpur>>#genConvertCharacterToSmallIntegerInReg: */ static void NoDbgRegParms genConvertCharacterToSmallIntegerInReg(sqInt reg) { assert(((numCharacterBits()) + 1) == (numSmallIntegerBits())); /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, 1, reg); } /* CogObjectRepresentationFor32BitSpur>>#genConvertIntegerToSmallIntegerInReg: */ static sqInt NoDbgRegParms genConvertIntegerToSmallIntegerInReg(sqInt reg) { AbstractInstruction *anInstruction; /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, 1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Convert the SmallInteger in reg to a Character, assuming the SmallInteger's value is a valid character. */ /* self assume: objectMemory smallIntegerTag = 1 */ /* CogObjectRepresentationFor32BitSpur>>#genConvertSmallIntegerToCharacterInReg: */ static void NoDbgRegParms genConvertSmallIntegerToCharacterInReg(sqInt reg) { assert(((numCharacterBits()) + 1) == (numSmallIntegerBits())); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, reg); } /* CogObjectRepresentationFor32BitSpur>>#genConvertSmallIntegerToIntegerInReg: */ static sqInt NoDbgRegParms genConvertSmallIntegerToIntegerInReg(sqInt reg) { /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, reg); return 0; } /* Fetch the instance's identity hash into destReg, encoded as a SmallInteger. */ /* Get header word in scratchReg */ /* CogObjectRepresentationFor32BitSpur>>#genGetHashFieldNonImmOf:asSmallIntegerInto: */ static sqInt NoDbgRegParms genGetHashFieldNonImmOfasSmallIntegerInto(sqInt instReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 4, instReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(4)); } /* begin AndCq:R: */ quickConstant = identityHashHalfWordMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } genConvertIntegerToSmallIntegerInReg(destReg); return 0; } /* Fetch the instance's identity hash into destReg, unencoded. */ /* CogObjectRepresentationFor32BitSpur>>#genGetHashFieldNonImmOf:into: */ static sqInt NoDbgRegParms genGetHashFieldNonImmOfinto(sqInt instReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 4, instReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(4)); } /* begin AndCq:R: */ quickConstant = identityHashHalfWordMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return 0; } /* Extract the inline cache tag for the object in sourceReg into destReg. The inline cache tag for a given object is the value loaded in inline caches to distinguish objects of different classes. In Spur this is either the tags for immediates, (with 1 & 3 collapsed to 1 for SmallIntegers, and 2 collapsed to 0 for Characters), or the receiver's classIndex. If forEntry is true answer the entry label at which control is to enter (cmEntryOffset). If forEntry is false, control enters at the start. If forEntry is true, generate something like this: Limm: andl $0x1, rDest j Lcmp Lentry: movl rSource, rDest andl $0x3, rDest jnz Limm movl 0(%edx), rDest andl $0x3fffff, rDest Lcmp: If forEntry is false, generate something like the following. At least on a 2.2GHz Intel Core i7 the following is slightly faster than the above, 136m sends/sec vs 130m sends/sec for nfib in tinyBenchmarks Lentry: movl rSource, rDest andl $0x3, rDest jz LnotImm andl $1, rDest j Lcmp LnotImm: movl 0(%edx), rDest andl $0x3fffff, rDest Lcmp: But we expect most SmallInteger arithmetic to be performed in-line and so prefer the version that is faster for non-immediates (because it branches for immediates only). */ /* CogObjectRepresentationFor32BitSpur>>#genGetInlineCacheClassTagFrom:into:forEntry: */ static AbstractInstruction * NoDbgRegParms genGetInlineCacheClassTagFromintoforEntry(sqInt sourceReg, sqInt destReg, sqInt forEntry) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *entryLabel; AbstractInstruction *immLabel; AbstractInstruction *jumpCompare; AbstractInstruction *jumpNotImm; sqInt quickConstant; if (forEntry) { /* begin AlignmentNops: */ genoperand(AlignmentNops, BytesPerWord); /* begin Label */ immLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, 1, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin Jump: */ jumpCompare = genoperand(Jump, ((sqInt)0)); /* begin AlignmentNops: */ genoperand(AlignmentNops, BytesPerWord); /* begin Label */ entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); gAndCqRR(tagMask(), sourceReg, destReg); /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)immLabel)); flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } jmpTarget(jumpCompare, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } else { /* begin Label */ entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); gAndCqRR(tagMask(), sourceReg, destReg); /* begin JumpZero: */ jumpNotImm = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AndCqR, 1, destReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } /* begin Jump: */ jumpCompare = genoperand(Jump, ((sqInt)0)); flag("endianness"); jmpTarget(jumpNotImm, checkQuickConstantforInstruction(0, genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg))); jmpTarget(jumpCompare, gAndCqR(classIndexMask(), destReg)); } return entryLabel; } /* Get the size in byte-sized slots of the object in srcReg into destReg. srcReg may equal destReg. destReg <- numSlots << self shiftForWord - (fmt bitAnd: 3). Assumes the object in srcReg has a byte format, i.e. 16 to 23 or 24 to 31 */ /* CogObjectRepresentationFor32BitSpur>>#genGetNumBytesOf:into: */ static sqInt NoDbgRegParms genGetNumBytesOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *jmp; sqInt quickConstant; genGetRawSlotSizeOfNonImminto(srcReg, destReg); /* begin CmpCq:R: */ quickConstant = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jmp = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genGetOverflowSlotsOfinto(srcReg, destReg); jmpTarget(jmp, gLogicalShiftLeftCqR(shiftForWord(), destReg)); genGetBitsofFormatByteOfinto(3, srcReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, destReg); return 0; } /* CogObjectRepresentationFor32BitSpur>>#genGetOverflowSlotsOf:into: */ static sqInt NoDbgRegParms genGetOverflowSlotsOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, -BaseHeaderSize, srcReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(-BaseHeaderSize)); } return 0; } /* Generate a test for aRegister containing an integer value in the SmallInteger range, and a jump if so, answering the jump. c.f. Spur32BitMemoryManager>>isIntegerValue: */ /* CogObjectRepresentationFor32BitSpur>>#genJumpIsSmallIntegerValue:scratch: */ static AbstractInstruction * NoDbgRegParms genJumpIsSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg) { return (/* begin MoveR:R: */ genoperandoperand(MoveRR, aRegister, scratchReg), /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, scratchReg), /* begin XorR:R: */ genoperandoperand(XorRR, aRegister, scratchReg), /* begin JumpGreaterOrEqual: */ genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0))); } /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallIntegerInScratchReg: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerInScratchReg(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } /* Generate a test for aRegister containing an integer value outside the SmallInteger range, and a jump if so, answering the jump. c.f. Spur32BitMemoryManager>>isIntegerValue: */ /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallIntegerValue:scratch: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg) { return (/* begin MoveR:R: */ genoperandoperand(MoveRR, aRegister, scratchReg), /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, scratchReg), /* begin XorR:R: */ genoperandoperand(XorRR, aRegister, scratchReg), /* begin JumpLess: */ genConditionalBranchoperand(JumpLess, ((sqInt)0))); } /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallInteger: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallInteger(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } /* CogObjectRepresentationFor32BitSpur>>#genJumpSmallInteger: */ static AbstractInstruction * NoDbgRegParms genJumpSmallInteger(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtPut */ static sqInt genPrimitiveAtPut(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction *jumpArrayOutOfBounds; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpBytesOutOfRange; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction *jumpHasFixedFields; AbstractInstruction *jumpImmediate; AbstractInstruction * jumpImmutable; AbstractInstruction *jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction *jumpIsContext; AbstractInstruction *jumpIsShorts; AbstractInstruction * jumpNonSmallIntegerValue; AbstractInstruction *jumpNotIndexableBits; AbstractInstruction *jumpNotIndexablePointers; AbstractInstruction * jumpNotPointers; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpShortsOutOfRange; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordsOutOfRange; AbstractInstruction *methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant10; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; jumpImmutable = ((AbstractInstruction *) 0); nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant10 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperand(TstCqR, quickConstant10, TempReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(quickConstant10)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpAbove: */ jumpNotPointers = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg1Reg, TempReg, 0); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ jumpNotIndexablePointers = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin JumpNonZero: */ jumpHasFixedFields = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant2 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, quickConstant2, Arg0Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpHasFixedFields, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, formatReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant3)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AddCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant4)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg0Reg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotPointers, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonSmallIntegerValue = genJumpNotSmallInteger(Arg1Reg); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, quickConstant5, formatReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant7 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(CmpCqR, quickConstant7, formatReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant7)); } /* begin JumpBelow: */ jumpNotIndexableBits = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); if (!(setsConditionCodesFor(lastOpcode(), JumpLess))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin AddCq:R: */ quickConstant8 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant8, Arg0Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant8)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, checkQuickConstantforInstruction((((usqInt)0xFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFF << 1) | 1), Arg1Reg))); /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), nSlotsOrBytesReg); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant9 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, quickConstant9, formatReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant9)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ methodInBounds = genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, checkQuickConstantforInstruction((((usqInt)0xFFFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFFFF << 1) | 1), Arg1Reg))); /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, nSlotsOrBytesReg); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsCompiledMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpIsContext, jmpTarget(jumpNotIndexableBits, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpWordsOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexablePointers, jmpTarget(jumpNonSmallIntegerValue, jmpTarget(jumpFixedFieldsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))))))))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the code for primitives 61 & 165, at:put:/basicAt:put: & integerAt:put:. If signedVersion is true then generate signed accesses to the bits classes (a la 164 & 165). If signedVersion is false, generate unsigned accesses (a la 60, 61, 63 & 64). */ /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtPutSigned: */ static sqInt NoDbgRegParms genPrimitiveAtPutSigned(sqInt signedVersion) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction * jumpArrayOutOfBounds; AbstractInstruction * jumpBadIndex; AbstractInstruction * jumpBytesOutOfBounds; AbstractInstruction * jumpBytesOutOfRange; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction * jumpHasFixedFields; AbstractInstruction * jumpImmediate; AbstractInstruction * jumpImmutable; AbstractInstruction * jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction * jumpIsContext; AbstractInstruction * jumpIsShorts; AbstractInstruction * jumpNonSmallIntegerValue; AbstractInstruction * jumpNotIndexableBits; AbstractInstruction * jumpNotIndexablePointers; AbstractInstruction * jumpNotPointers; AbstractInstruction * jumpShortsOutOfBounds; AbstractInstruction * jumpShortsOutOfRange; AbstractInstruction * jumpWordsOutOfBounds; AbstractInstruction * jumpWordsOutOfRange; AbstractInstruction * methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant10; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; jumpImmutable = ((AbstractInstruction *) 0); jumpWordsOutOfRange = ((AbstractInstruction *) 0); nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant10 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperand(TstCqR, quickConstant10, TempReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(quickConstant10)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant)); } /* begin JumpAbove: */ jumpNotPointers = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg1Reg, TempReg, 0); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ jumpNotIndexablePointers = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin JumpNonZero: */ jumpHasFixedFields = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant2 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, quickConstant2, Arg0Reg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant2)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpHasFixedFields, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(AndCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant3)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant4)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg0Reg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotPointers, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonSmallIntegerValue = genJumpNotSmallInteger(Arg1Reg); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, quickConstant5, formatReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant7 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(CmpCqR, quickConstant7, formatReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant7)); } /* begin JumpBelow: */ jumpNotIndexableBits = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); if (!signedVersion) { if (!(setsConditionCodesFor(lastOpcode(), JumpLess))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); } /* begin AddCq:R: */ quickConstant8 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, quickConstant8, Arg0Reg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(quickConstant8)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } if (signedVersion) { jmpTarget(jumpIsBytes, genoperandoperand(MoveRR, SendNumArgsReg, TempReg)); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 7, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(1)); } } else { jmpTarget(jumpIsBytes, checkQuickConstantforInstruction((((usqInt)0xFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFF << 1) | 1), Arg1Reg))); } /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), nSlotsOrBytesReg); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant9 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperand(CmpCqR, quickConstant9, formatReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(quickConstant9)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ methodInBounds = genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } if (signedVersion) { jmpTarget(jumpIsShorts, genoperandoperand(MoveRR, SendNumArgsReg, TempReg)); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 15, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } } else { jmpTarget(jumpIsShorts, checkQuickConstantforInstruction((((usqInt)0xFFFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFFFF << 1) | 1), Arg1Reg))); } /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, nSlotsOrBytesReg); /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsCompiledMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpIsContext, jmpTarget(jumpNotIndexableBits, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexablePointers, jmpTarget(jumpNonSmallIntegerValue, jmpTarget(jumpFixedFieldsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))))))); if (!signedVersion) { jmpTarget(jumpWordsOutOfRange, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); } # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the code for primitives 60 & 164, at:/basicAt: & integerAt:. If signedVersion is true then generate signed accesses to the bits classes (a la 164 & 165). If signedVersion is false, generate unsigned accesses (a la 60, 61, 63 & 64). */ /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtSigned: */ static sqInt NoDbgRegParms genPrimitiveAtSigned(sqInt signedVersion) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction * convertToIntAndReturn; AbstractInstruction * first; AbstractInstruction * first1; sqInt formatReg; AbstractInstruction * jumpArrayOutOfBounds; AbstractInstruction * jumpBadIndex; AbstractInstruction * jumpBytesOutOfBounds; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction * jumpHasFixedFields; AbstractInstruction * jumpImmediate; AbstractInstruction * jumpIsArray; AbstractInstruction * jumpIsBytes; AbstractInstruction * jumpIsContext; AbstractInstruction * jumpIsMethod; AbstractInstruction * jumpIsShorts; AbstractInstruction * jumpIsWords; AbstractInstruction * jumpNotIndexable; AbstractInstruction * jumpShortsOutOfBounds; AbstractInstruction * jumpWordsOutOfBounds; AbstractInstruction * jumpWordTooBig; AbstractInstruction * methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg1Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpIsArray = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin JumpBelow: */ jumpNotIndexable = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin JumpBelowOrEqual: */ jumpHasFixedFields = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant4)); } /* begin JumpAboveOrEqual: */ jumpIsWords = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); jmpTarget(jumpNotIndexable, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin Jump: */ jumpNotIndexable = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsArray, genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg)); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant5 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, quickConstant5, Arg1Reg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant5)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), nSlotsOrBytesReg)); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BaseHeaderSize, Arg1Reg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize)); } methodInBounds = anInstruction8; /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (signedVersion) { /* begin SignExtend8R:R: */ /* begin LogicalShiftLeftCq:R: */ first = genoperandoperand(LogicalShiftLeftCqR, (BytesPerWord * 8) - 8, ReceiverResultReg); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, (BytesPerWord * 8) - 8, ReceiverResultReg); goto l8; l8: /* end SignExtend8R:R: */; } /* begin Label */ convertToIntAndReturn = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, nSlotsOrBytesReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, 1, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveM16rR, BaseHeaderSize, ReceiverResultReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(BaseHeaderSize)); } if (signedVersion) { /* begin SignExtend16R:R: */ /* begin LogicalShiftLeftCq:R: */ first1 = genoperandoperand(LogicalShiftLeftCqR, (BytesPerWord * 8) - 16, ReceiverResultReg); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, (BytesPerWord * 8) - 16, ReceiverResultReg); goto l13; l13: /* end SignExtend16R:R: */; } /* begin Jump: */ genoperand(Jump, ((sqInt)convertToIntAndReturn)); jmpTarget(jumpIsWords, genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg)); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant7 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant7, Arg1Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant7)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, TempReg); jumpWordTooBig = jumpNotSmallIntegerUnsignedValueInRegister(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)convertToIntAndReturn)); jmpTarget(jumpHasFixedFields, gAndCqR(classIndexMask(), TempReg)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant8 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AndCqR, quickConstant8, formatReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant8)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg1Reg); /* begin AddCq:R: */ quickConstant9 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, quickConstant9, Arg1Reg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant9)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpWordTooBig, jmpTarget(jumpFixedFieldsOutOfBounds, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexable, jmpTarget(jumpIsContext, jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))))); return 0; } /* Arguably we should fail for immediates, but so far no one has complained, so... */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveIdentityHash */ static sqInt genPrimitiveIdentityHash(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction * inst; AbstractInstruction *jumpImm; AbstractInstruction *jumpNotSet; AbstractInstruction *jumpSI; AbstractInstruction * ret; jumpImm = genJumpImmediate(ReceiverResultReg); genGetHashFieldNonImmOfasSmallIntegerInto(ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ConstZero, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ConstZero)); } /* begin JumpZero: */ jumpNotSet = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ ret = genoperand(RetN, 0); } else { /* begin RetN: */ ret = genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImm, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSI = genJumpSmallInteger(ReceiverResultReg); jmpTarget(jumpSI, ret); genConvertCharacterToSmallIntegerInReg(ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)ret)); jmpTarget(jumpNotSet, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!(primitiveIndex == 75)) { return 0; } /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceNewHashTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* :Assume the receiuver is never a SmallInteger. One would use ^self for that. */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveImmediateAsInteger */ static sqInt genPrimitiveImmediateAsInteger(void) { genConvertCharacterToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* Implement primitiveNew for convenient cases: - the receiver has a hash - the receiver is fixed size (excluding ephemerons to save instructions & miniscule time) - single word header/num slots < numSlotsMask - the result fits in eden (actually below scavengeThreshold) */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveNew */ static sqInt genPrimitiveNew(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt byteSizeReg; AbstractInstruction *fillLoop; sqInt fillReg; sqInt halfHeaderReg; sqInt instSpecReg; AbstractInstruction *jumpHasSlots; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpTooBig; AbstractInstruction *jumpUnhashed; AbstractInstruction *jumpVariableOrEphemeron; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; AbstractInstruction *skip; if (methodOrBlockNumArgs != 0) { return UnimplementedPrimitive; } /* inst spec will hold class's instance specification, then byte size and finally end of new object. */ halfHeaderReg = (fillReg = SendNumArgsReg); /* get freeStart as early as possible so as not to wait later... */ instSpecReg = (byteSizeReg = ClassReg); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, Arg1Reg)); genGetHashFieldNonImmOfinto(ReceiverResultReg, halfHeaderReg); /* begin JumpZero: */ jumpUnhashed = genConditionalBranchoperand(JumpZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ReceiverResultReg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin LogicalShiftRightCq:R: */ quickConstant = fixedFieldsFieldWidth(); genoperandoperand(LogicalShiftRightCqR, quickConstant, TempReg); /* begin AndCq:R: */ quickConstant2 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant2)); } /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant3, instSpecReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant3)); } /* begin CmpCq:R: */ quickConstant4 = nonIndexablePointerFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant4)); } /* begin JumpAbove: */ jumpVariableOrEphemeron = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant5, instSpecReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpTooBig = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ quickConstant1 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant1, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, 0, byteSizeReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpHasSlots = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, BaseHeaderSize * 2, byteSizeReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BaseHeaderSize * 2)); } /* begin Jump: */ skip = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasSlots, genoperandoperand(MoveRR, byteSizeReg, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, byteSizeReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, byteSizeReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), byteSizeReg); jmpTarget(skip, gLogicalShiftLeftCqR(numSlotsHalfShift(), halfHeaderReg)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, byteSizeReg); /* begin CmpCq:R: */ quickConstant6 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant6, byteSizeReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, byteSizeReg, address1)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(LoadEffectiveAddressMwrR, BaseHeaderSize, ReceiverResultReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveCq:R: */ quickConstant7 = nilObject(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(MoveCqR, quickConstant7, fillReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant7)); } /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperandoperand(MoveRMwr, fillReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(0)); } fillLoop = anInstruction13; /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperandoperand(MoveRMwr, fillReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, 8, Arg1Reg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(8)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, byteSizeReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)fillLoop)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpUnhashed, jmpTarget(jumpVariableOrEphemeron, jmpTarget(jumpTooBig, jmpTarget(jumpNoSpace, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return 0; } /* Implement primitiveNewWithArg for convenient cases: - the receiver has a hash - the receiver is variable and not compiled method - single word header/num slots < numSlotsMask - the result fits in eden See superclass method for dynamic frequencies of formats. For the moment we implement only arrayFormat, firstByteFormat & firstLongFormat */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveNewWithArg */ static sqInt genPrimitiveNewWithArg(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt byteSizeReg; AbstractInstruction *fillLoop; sqInt fillReg; sqInt halfHeaderReg; sqInt instSpecReg; AbstractInstruction *jumpArrayFormat; AbstractInstruction *jumpArrayTooBig; AbstractInstruction *jumpByteFormat; AbstractInstruction *jumpBytePrepDone; AbstractInstruction *jumpByteTooBig; AbstractInstruction *jumpFailCuzFixed; AbstractInstruction *jumpHasSlots; AbstractInstruction *jumpLongPrepDone; AbstractInstruction *jumpLongTooBig; AbstractInstruction *jumpNElementsNonInt; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpUnhashed; sqInt literal; sqInt maxSlots; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; AbstractInstruction *skip; sqInt wordConstant; if (methodOrBlockNumArgs != 1) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* inst spec will hold class's instance specification and then byte size and finally numSlots half of header */ halfHeaderReg = (fillReg = SendNumArgsReg); /* The max slots we'll allocate here are those for a single header */ instSpecReg = (byteSizeReg = ClassReg); /* get freeStart as early as possible so as not to wait later... */ maxSlots = (numSlotsMask()) - 1; /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, Arg1Reg)); genGetHashFieldNonImmOfinto(ReceiverResultReg, halfHeaderReg); /* begin JumpZero: */ jumpUnhashed = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* get class's format inst var for inst spec (format field) */ jumpNElementsNonInt = genJumpNotSmallInteger(Arg0Reg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ReceiverResultReg, instSpecReg); /* begin LogicalShiftRightCq:R: */ quickConstant = (fixedFieldsFieldWidth()) + 1 /* numSmallIntegerTagBits */; genoperandoperand(LogicalShiftRightCqR, quickConstant, instSpecReg); /* begin AndCq:R: */ quickConstant3 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant3, instSpecReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant3)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, TempReg); /* begin LogicalShiftLeftCq:R: */ quickConstant1 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant1, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin CmpCq:R: */ quickConstant4 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant4, instSpecReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant4)); } /* begin JumpZero: */ jumpArrayFormat = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant5, instSpecReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant5)); } /* begin JumpZero: */ jumpByteFormat = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant6, instSpecReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant6)); } /* begin JumpNonZero: */ jumpFailCuzFixed = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)maxSlots << 1) | 1); anInstruction4 = genoperandoperand(CmpCqR, (((usqInt)maxSlots << 1) | 1), Arg0Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(literal)); } /* begin JumpAbove: */ jumpLongTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperand(PushCq, 0); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin Jump: */ jumpLongPrepDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpByteFormat, checkQuickConstantforInstruction((((usqInt)(maxSlots * BytesPerWord) << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)(maxSlots * BytesPerWord) << 1) | 1), Arg0Reg))); /* begin JumpAbove: */ jumpByteTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, BytesPerWord, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord)); } /* begin SubR:R: */ genoperandoperand(SubRR, instSpecReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, BytesPerWord - 1, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BytesPerWord - 1)); } /* begin LogicalShiftLeftCq:R: */ quickConstant2 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant2, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BytesPerWord - 1, instSpecReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BytesPerWord - 1)); } /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, shiftForWord(), instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperand(PushCq, 0); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(0)); } /* begin Jump: */ jumpBytePrepDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpArrayFormat, checkQuickConstantforInstruction((((usqInt)maxSlots << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)maxSlots << 1) | 1), Arg0Reg))); /* begin JumpAbove: */ jumpArrayTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin PushCw: */ wordConstant = nilObject(); /* begin gen:literal: */ checkLiteralforInstruction(wordConstant, genoperand(PushCw, wordConstant)); jmpTarget(jumpBytePrepDone, jmpTarget(jumpLongPrepDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(CmpCqR, 0, byteSizeReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpHasSlots = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(MoveCqR, BaseHeaderSize * 2, byteSizeReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(BaseHeaderSize * 2)); } /* begin Jump: */ skip = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasSlots, genoperandoperand(MoveRR, byteSizeReg, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, byteSizeReg); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, byteSizeReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), byteSizeReg); jmpTarget(skip, gLogicalShiftLeftCqR(numSlotsHalfShift(), halfHeaderReg)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, byteSizeReg); /* begin CmpCq:R: */ quickConstant7 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(CmpCqR, quickConstant7, byteSizeReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(quickConstant7)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, byteSizeReg, address1)); /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(4)); } /* begin PopR: */ genoperand(PopR, fillReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(LoadEffectiveAddressMwrR, BaseHeaderSize, ReceiverResultReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveRMwr, fillReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(0)); } fillLoop = anInstruction18; /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, fillReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(AddCqR, 8, Arg1Reg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(8)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, byteSizeReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)fillLoop)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNoSpace, genoperand(PopR, TempReg)); jmpTarget(jumpUnhashed, jmpTarget(jumpFailCuzFixed, jmpTarget(jumpArrayTooBig, jmpTarget(jumpByteTooBig, jmpTarget(jumpLongTooBig, jmpTarget(jumpNElementsNonInt, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))); return 0; } /* Implement primitiveShallowCopy/primitiveClone for convenient cases: - the receiver is not a context - the receiver is not a compiled method - the result fits in eden (actually below scavengeThreshold) */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveShallowCopy */ static sqInt genPrimitiveShallowCopy(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction *continuance; AbstractInstruction *copyLoop; sqInt formatReg; AbstractInstruction * jumpEmpty; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpIsMethod; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpTooBig; AbstractInstruction *jumpVariable; sqInt ptrReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt resultReg; sqInt slotsReg; jumpImmediate = genJumpImmediate(ReceiverResultReg); resultReg = Arg0Reg; /* get freeStart as early as possible so as not to wait later... */ slotsReg = Arg1Reg; /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, resultReg)); genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (ptrReg = (formatReg = SendNumArgsReg)), NoReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpIsMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = indexablePointersFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpVariable = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin Label */ continuance = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genGetRawSlotSizeOfNonImminto(ReceiverResultReg, slotsReg); /* begin CmpCq:R: */ quickConstant2 = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, slotsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpZero: */ jumpTooBig = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, 0, slotsReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpEmpty = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, slotsReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, slotsReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, slotsReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), slotsReg); /* begin AddR:R: */ genoperandoperand(AddRR, resultReg, slotsReg); /* begin CmpCq:R: */ quickConstant3 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant3, slotsReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, resultReg, ptrReg); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, slotsReg, address1)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(SubCqR, BytesPerWord * 2, slotsReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveMwrR, 0, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant4 = (((sqInt)((usqInt)((formatMask())) << (formatShift())))) + (classIndexMask()); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, 0, resultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveMwrR, BytesPerWord, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(BytesPerWord)); } /* begin AndCq:R: */ quickConstant5 = ((sqInt)((usqInt)((numSlotsMask())) << (numSlotsHalfShift()))); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(AndCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperandoperand(MoveRMwr, TempReg, BytesPerWord, resultReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(BytesPerWord)); } /* begin Label */ copyLoop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, BytesPerWord * 2, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, BytesPerWord * 2, ptrReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, 0, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ptrReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, BytesPerWord, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, TempReg, BytesPerWord, ptrReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BytesPerWord)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, ptrReg, slotsReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)copyLoop)); /* begin MoveR:R: */ genoperandoperand(MoveRR, resultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpVariable, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, ClassReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)continuance)); jmpTarget(jumpImmediate, jmpTarget(jumpNoSpace, jmpTarget(jumpIsMethod, jmpTarget(jumpTooBig, jmpTarget(jumpEmpty, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); return 0; } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveStringAt */ static sqInt genPrimitiveStringAt(void) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction *done; sqInt formatReg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpIsBytes; AbstractInstruction *jumpIsShorts; AbstractInstruction *jumpNotIndexable; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpWordsDone; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordTooBig; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg1Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 1, Arg1Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpGreaterOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpGreaterOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpNotIndexable = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant3 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, quickConstant3, Arg1Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant3)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, TempReg); jumpWordTooBig = jumpNotCharacterUnsignedValueInRegister(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); /* begin Jump: */ jumpWordsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, BytesPerWord - 1, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AddCqR, BaseHeaderSize, Arg1Reg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); jmpTarget(jumpWordsDone, (done = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genConvertIntegerToCharacterInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AndCqR, (BytesPerWord / 1) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((BytesPerWord / 1) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperandoperand(MoveM16rR, BaseHeaderSize, ReceiverResultReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(BaseHeaderSize)); } /* begin Jump: */ genoperand(Jump, ((sqInt)done)); jmpTarget(jumpWordTooBig, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexable, jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))); return CompletePrimitive; } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveStringAtPut */ static sqInt genPrimitiveStringAtPut(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction *jumpBadArg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpBytesOutOfRange; AbstractInstruction * jumpImmutable; AbstractInstruction *jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction *jumpIsShorts; AbstractInstruction * jumpNotString; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpShortsOutOfRange; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordsOutOfRange; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; jumpImmutable = ((AbstractInstruction *) 0); /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); jumpBadArg = genJumpNotCharacterInScratchReg(TempReg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant5 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(TstCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpBelow: */ jumpNotString = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, quickConstant4, Arg0Reg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant4)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gCmpCqR(characterObjectOf(0xFFFF), Arg1Reg)); /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, gCmpCqR(characterObjectOf(0xFF), Arg1Reg)); /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, BytesPerWord - 1, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotString, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpWordsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpNotString->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadArg, jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentationFor32BitSpur>>#genRemoveSmallIntegerTagsInScratchReg: */ static sqInt NoDbgRegParms genRemoveSmallIntegerTagsInScratchReg(sqInt scratchReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* CogObjectRepresentationFor32BitSpur>>#genShiftAwaySmallIntegerTagsInScratchReg: */ static sqInt NoDbgRegParms genShiftAwaySmallIntegerTagsInScratchReg(sqInt scratchReg) { /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, scratchReg); return 0; } /* Get the literal count of a CompiledMethod into headerReg, plus one if requested. If inBytes is true, scale the count by the word size. Deal with the possibility of the method being cogged. */ /* CogObjectRepresentationFor32BitSpur>>#getLiteralCountOf:plusOne:inBytes:into:scratch: */ static sqInt NoDbgRegParms getLiteralCountOfplusOneinBytesintoscratch(sqInt methodReg, sqInt plusOne, sqInt inBytes, sqInt litCountReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; genGetMethodHeaderOfintoscratch(methodReg, litCountReg, scratchReg); if (inBytes) { /* begin AndCq:R: */ quickConstant = ((sqInt)((usqInt)((alternateHeaderNumLiteralsMask())) << 1)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, litCountReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, litCountReg); } else { /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, 1, litCountReg); /* begin AndCq:R: */ quickConstant1 = alternateHeaderNumLiteralsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant1, litCountReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } } if (plusOne) { /* begin AddCq:R: */ quickConstant2 = (inBytes ? BytesPerWord : 1); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant2, litCountReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } } return 0; } /* Answer the relevant inline cache tag for an instance. c.f. getInlineCacheClassTagFrom:into: & inlineCacheTagForClass: */ /* CogObjectRepresentationFor32BitSpur>>#inlineCacheTagForInstance: */ static sqInt NoDbgRegParms inlineCacheTagForInstance(sqInt oop) { return (isImmediate(oop) ? oop & 1 : classIndexOf(oop)); } /* CogObjectRepresentationFor32BitSpur>>#jumpNotSmallIntegerUnsignedValueInRegister: */ static AbstractInstruction * NoDbgRegParms jumpNotSmallIntegerUnsignedValueInRegister(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0x3FFFFFFF, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0x3FFFFFFF)); } /* begin JumpAbove: */ return genConditionalBranchoperand(JumpAbove, ((sqInt)0)); } /* Mark and trace a literal in an inline cache preceding address in cogMethodOrNil. Answer if code was modified. */ /* CogObjectRepresentationFor32BitSpur>>#markAndTraceCacheTagLiteral:in:atpc: */ static sqInt NoDbgRegParms markAndTraceCacheTagLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address) { sqInt objOop; AbstractInstruction * self_in_rewriteInlineCacheTagat; if (!(couldBeObject(literal))) { return 0; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return 0; } objOop = followForwarded(literal); /* begin rewriteInlineCacheTag:at: */ self_in_rewriteInlineCacheTagat = ((AbstractInstruction *) (backEnd())); longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheTagat, address - 8), objOop); markAndTraceUpdatedLiteralin(objOop, cogMethodOrNil); return 1; } /* CogObjectRepresentationFor32BitSpur>>#numSmallIntegerBits */ static sqInt numSmallIntegerBits(void) { return 0x1F; } /* The two valid tag patterns are 0 (Character) and 1 (SmallInteger) */ /* CogObjectRepresentationFor32BitSpur>>#validInlineCacheTag: */ static sqInt NoDbgRegParms validInlineCacheTag(usqInt classIndexOrTagPattern) { return (classIndexOrTagPattern <= 1) || ((classAtIndex(classIndexOrTagPattern)) != null); } /* Answer if the cacheTag is not unmarked, i.e. answer true for compact class indices and immediates; only answer false for unmarked objects. In Spur linked send cache tags are class indices so effectively they're always marked. */ /* CogObjectRepresentationForSpur>>#cacheTagIsMarked: */ static sqInt NoDbgRegParms cacheTagIsMarked(sqInt cacheTag) { return 1; } /* CogObjectRepresentationForSpur>>#callStoreCheckTrampoline */ static void callStoreCheckTrampoline(void) { AbstractInstruction *abstractInstruction; /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* CogObjectRepresentationForSpur>>#checkValidDerivedObjectReference: */ static sqInt NoDbgRegParms checkValidDerivedObjectReference(sqInt bodyAddress) { return (heapMapAtWord(pointerForOop(bodyAddress - BaseHeaderSize))) != 0; } /* CogObjectRepresentationForSpur>>#checkValidOopReference: */ static sqInt NoDbgRegParms checkValidOopReference(sqInt anOop) { return (isImmediate(anOop)) || ((heapMapAtWord(pointerForOop(anOop))) != 0); } /* CogObjectRepresentationForSpur>>#couldBeDerivedObject: */ static sqInt NoDbgRegParms couldBeDerivedObject(sqInt bodyAddress) { return oopisGreaterThanOrEqualTo(bodyAddress - BaseHeaderSize, startOfMemory()); } /* CogObjectRepresentationForSpur>>#couldBeObject: */ static sqInt NoDbgRegParms couldBeObject(sqInt literal) { return (isNonImmediate(literal)) && (oopisGreaterThanOrEqualTo(literal, startOfMemory())); } /* Create a trampoline to answer the active context that will answer it if a frame is already married, and create it otherwise. Assume numArgs is in SendNumArgsReg and ClassReg is free. */ /* CogObjectRepresentationForSpur>>#genActiveContextTrampolineLarge:inBlock:called: */ static sqInt NoDbgRegParms genActiveContextTrampolineLargeinBlockcalled(sqInt isLarge, sqInt isInBlock, char *aString) { sqInt startAddress; startAddress = methodZoneBase(); zeroOpcodeIndex(); genGetActiveContextLargeinBlock(isLarge, isInBlock); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress(aString, startAddress); recordRunTimeObjectReferences(); return startAddress; } /* CogObjectRepresentationForSpur>>#genAllocFloatValue:into:scratchReg:scratchReg: */ static AbstractInstruction * NoDbgRegParms genAllocFloatValueintoscratchRegscratchReg(sqInt dpreg, sqInt resultReg, sqInt scratch1, sqInt scratch2) { sqInt address; sqInt address1; usqIntptr_t allocSize; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *jumpFail; usqLong newFloatHeader; sqInt quickConstant; sqInt quickConstant1; allocSize = BaseHeaderSize + (sizeof(double)); newFloatHeader = headerForSlotsformatclassIndex((sizeof(double)) / BytesPerWord, firstLongFormat(), ClassFloatCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, resultReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(LoadEffectiveAddressMwrR, allocSize, resultReg, scratch1); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(allocSize)); } /* begin CmpCq:R: */ quickConstant = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, scratch1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpFail = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, scratch1, address1)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant1 = ((usqInt) newFloatHeader); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant1, scratch1); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveRMwr, scratch1, 0, resultReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, newFloatHeader >> 32, scratch1); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(newFloatHeader >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, scratch1, 4, resultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveRdM64r, dpreg, BaseHeaderSize, resultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize)); } return jumpFail; } /* Check the remembered bit of the object in objReg; answer the jump taken if the bit is already set. Only need to fetch the byte containing it, which reduces the size of the mask constant. */ /* CogObjectRepresentationForSpur>>#genCheckRememberedBitOf:scratch: */ static AbstractInstruction * NoDbgRegParms genCheckRememberedBitOfscratch(sqInt objReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; int mask; sqInt rememberedBitByteOffset; rememberedBitByteOffset = (rememberedBitShift()) / 8; mask = 1U << ((rememberedBitShift()) % 8); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, rememberedBitByteOffset, objReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(rememberedBitByteOffset)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, mask, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(mask)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* CogObjectRepresentationForSpur>>#genConvertCharacterToCodeInReg: */ static sqInt NoDbgRegParms genConvertCharacterToCodeInReg(sqInt reg) { sqInt quickConstant; /* begin LogicalShiftRightCq:R: */ quickConstant = numTagBits(); genoperandoperand(LogicalShiftRightCqR, quickConstant, reg); return 0; } /* CogObjectRepresentationForSpur>>#genConvertIntegerToCharacterInReg: */ static sqInt NoDbgRegParms genConvertIntegerToCharacterInReg(sqInt reg) { AbstractInstruction *anInstruction; sqInt quickConstant; sqInt quickConstant1; /* begin LogicalShiftLeftCq:R: */ quickConstant = numTagBits(); genoperandoperand(LogicalShiftLeftCqR, quickConstant, reg); /* begin AddCq:R: */ quickConstant1 = characterTag(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant1)); } return 0; } /* Create a closure with the given startpc, numArgs and numCopied within a context with ctxtNumArgs, large if isLargeCtxt that is in a block if isInBlock. If numCopied > 0 pop those values off the stack. */ /* CogObjectRepresentationForSpur>>#genCreateClosureAt:numArgs:numCopied:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock) { AbstractInstruction *anInstruction; sqInt i; genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(bcpc, numArgs, numCopied, ctxtNumArgs, isLargeCtxt, isInBlock); for (i = 1; i <= numCopied; i += 1) { /* begin PopR: */ genoperand(PopR, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, TempReg, (((numCopied - i) + ClosureFirstCopiedValueIndex) * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((((numCopied - i) + ClosureFirstCopiedValueIndex) * BytesPerOop) + BaseHeaderSize)); } } return 0; } /* Create a full closure with the given values. */ /* CogObjectRepresentationForSpur>>#genCreateFullClosure:numArgs:numCopied:ignoreContext:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(sqInt compiledBlock, sqInt numArgs, sqInt numCopied, sqInt ignoreContext, sqInt contextNumArgs, sqInt contextIsLarge, sqInt contextIsBlock) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; usqInt byteSize; sqInt constant; usqLong header; sqInt literal; sqInt numSlots; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; /* First get thisContext into ReceiverResultReg and thence in ClassReg. */ if (ignoreContext) { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ClassReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(MoveCqR, constant, ClassReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(constant)); } } } else { genGetActiveContextNumArgslargeinBlock(contextNumArgs, contextIsLarge, contextIsBlock); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); } numSlots = FullClosureFirstCopiedValueIndex + numCopied; byteSize = smallObjectBytesForSlots(numSlots); assert(ClassFullBlockClosureCompactIndex != 0); header = headerForSlotsformatclassIndex(numSlots, indexablePointersFormat(), ClassFullBlockClosureCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(LoadEffectiveAddressMwrR, byteSize, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(byteSize)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveRMwr, ClassReg, (ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral((ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize)); } if (shouldAnnotateObjectReference(compiledBlock)) { annotateobjRef(gMoveCwR(compiledBlock, TempReg), compiledBlock); } else { /* begin MoveCq:R: */ anInstruction = genoperandoperand(MoveCqR, compiledBlock, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(compiledBlock)); } } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)numArgs << 1) | 1); anInstruction9 = genoperandoperand(MoveCqR, (((usqInt)numArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(literal)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral((ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize)); } return 0; } /* Make sure that the object in reg is not forwarded. This routine assumes the object will never be forwarded to an immediate, as it is used to unforward literal variables (associations). Use the fact that isForwardedObjectClassIndexPun is a power of two to save an instruction. */ /* CogObjectRepresentationForSpur>>#genEnsureObjInRegNotForwarded:scratchReg: */ static sqInt NoDbgRegParms genEnsureObjInRegNotForwardedscratchReg(sqInt reg, sqInt scratch) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *loop; AbstractInstruction *ok; sqInt quickConstant; assert(reg != scratch); /* begin Label */ loop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(ok, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchReg(sqInt reg, sqInt scratch) { AbstractInstruction *instruction; /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ instruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); return genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(reg, scratch, instruction, 0); } /* Make sure that the oop in reg is not forwarded. Use the fact that isForwardedObjectClassIndexPun is a power of two to save an instruction. */ /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg:ifForwarder:ifNotForwarder: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(sqInt reg, sqInt scratch, sqInt fwdJumpTarget, sqInt nonFwdJumpTargetOrZero) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction * finished; AbstractInstruction * imm; AbstractInstruction * ok; sqInt quickConstant; assert(reg != scratch); /* notionally self genGetClassIndexOfNonImm: reg into: scratch. cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: TempReg. but the following is an instruction shorter: */ imm = genJumpImmediate(reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin Jump: */ genoperand(Jump, ((sqInt)(((void *) fwdJumpTarget)))); if ((((usqInt)nonFwdJumpTargetOrZero)) == 0) { /* begin Label */ finished = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { finished = nonFwdJumpTargetOrZero; } jmpTarget(imm, jmpTarget(ok, finished)); return 0; } /* Make sure that the oop in reg is not forwarded, updating the slot in objReg with the value. */ /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg:updatingSlot:in: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(sqInt reg, sqInt scratch, sqInt index, sqInt objReg) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *imm; AbstractInstruction *loop; AbstractInstruction *ok; sqInt quickConstant; /* Open-code self genEnsureOopInRegNotForwarded: reg scratchReg: scratch updatingMw: index * objectMemory wordSize + objectMemory baseHeaderSize r: objReg. to avoid calling the store check unless the receiver is forwarded. */ assert((reg != scratch) && (objReg != scratch)); /* begin Label */ loop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* notionally self genGetClassIndexOfNonImm: reg into: scratch. cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: TempReg. but the following is an instruction shorter: */ imm = genJumpImmediate(reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveRMwr, reg, (index * BytesPerWord) + BaseHeaderSize, objReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } assert((reg == Arg0Reg) && ((scratch == TempReg) && (objReg == ReceiverResultReg))); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckContextReceiverTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(ok, jmpTarget(imm, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Do the store check. Answer the argument for the benefit of the code generator; ReceiverResultReg may be caller-saved and hence smashed by this call. Answering it allows the code generator to reload ReceiverResultReg cheaply. In Spur the only thing we leave to the run-time is adding the receiver to the remembered set and setting its isRemembered bit. */ /* CogObjectRepresentationForSpur>>#generateObjectRepresentationTrampolines */ static void generateObjectRepresentationTrampolines(void) { sqInt instVarIndex; AbstractInstruction *jumpSC; # if IMMUTABILITY for (instVarIndex = 0; instVarIndex < NumStoreTrampolines; instVarIndex += 1) { ceStoreTrampolines[instVarIndex] = (genStoreTrampolineCalledinstVarIndex(trampolineNamenumArgslimit("ceStoreTrampoline", instVarIndex, NumStoreTrampolines - 2), instVarIndex)); } # endif /* IMMUTABILITY */ ceNewHashTrampoline = genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceNewHashOf, "ceNewHash", 1, ReceiverResultReg, null, null, null, /* begin emptyRegisterMask */ 0, 1, ReceiverResultReg, 0); /* begin genStoreCheckTrampoline */ if (CheckRememberedInTrampoline) { zeroOpcodeIndex(); jumpSC = genCheckRememberedBitOfscratch(ReceiverResultReg, R0); assert(((jumpSC->opcode)) == JumpNonZero); (jumpSC->opcode = JumpZero); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpSC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } ceStoreCheckTrampoline = genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(remember, "ceStoreCheckTrampoline", 1, ReceiverResultReg, null, null, null, ((CallerSavedRegisterMask | (1U << ReceiverResultReg)) - (1U << ReceiverResultReg)), 1, (CallerSavedRegisterMask & (1U << ReceiverResultReg) ? ReceiverResultReg : /* begin cResultRegister */ R0), CheckRememberedInTrampoline); ceStoreCheckContextReceiverTrampoline = genStoreCheckContextReceiverTrampoline(); ceScheduleScavengeTrampoline = genTrampolineForcalledregsToSave(ceScheduleScavenge, "ceScheduleScavengeTrampoline", CallerSavedRegisterMask); ceSmallActiveContextInMethodTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, 0, "ceSmallMethodContext"); ceSmallActiveContextInBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, InVanillaBlock, "ceSmallBlockContext"); ceSmallActiveContextInFullBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, InFullBlock, "ceSmallFullBlockContext"); ceLargeActiveContextInMethodTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, 0, "ceLargeMethodContext"); ceLargeActiveContextInBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, InVanillaBlock, "ceLargeBlockContext"); ceLargeActiveContextInFullBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, InFullBlock, "ceLargeFullBlockContext"); } /* Create a trampoline to answer the active context that will answer it if a frame is already married, and create it otherwise. Assume numArgs is in SendNumArgsReg and ClassReg is free. */ /* CogObjectRepresentationForSpur>>#genGetActiveContextLarge:inBlock: */ static sqInt NoDbgRegParms genGetActiveContextLargeinBlock(sqInt isLarge, sqInt isInBlock) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction22; AbstractInstruction *anInstruction23; AbstractInstruction *anInstruction24; AbstractInstruction *anInstruction25; AbstractInstruction *anInstruction26; AbstractInstruction *anInstruction27; AbstractInstruction *anInstruction28; AbstractInstruction *anInstruction29; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction30; AbstractInstruction *anInstruction31; AbstractInstruction *anInstruction32; AbstractInstruction *anInstruction33; AbstractInstruction *anInstruction34; AbstractInstruction *anInstruction35; AbstractInstruction *anInstruction36; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt constant; AbstractInstruction *continuation; AbstractInstruction *exit; usqLong header; AbstractInstruction * inst; AbstractInstruction *jumpNeedScavenge; AbstractInstruction *jumpSingle; AbstractInstruction *loopHead; sqInt offset; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt slotSize; /* load the flag; stash it in both TempReg & ClassReg; do the compare (a prime candidated for use of AndCq:R:R:) */ /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveMwrR, FoxMethod, FPReg, ClassReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(FoxMethod)); } gAndCqRR(MFMethodFlagHasContextFlag, ClassReg, TempReg); /* begin JumpZero: */ jumpSingle = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveMwrR, FoxThisContext, FPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(FoxThisContext)); } /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpSingle, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(OrCqR, MFMethodFlagHasContextFlag, ClassReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(MFMethodFlagHasContextFlag)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, ClassReg, FoxMethod, FPReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(FoxMethod)); } switch (isInBlock) { case InFullBlock: /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 3, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } break; case InVanillaBlock: /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 3, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(3)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveM16rR, 0, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, ClassReg); break; case 0: /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, 1, ClassReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } break; default: error("Case not found and no otherwise clause"); } slotSize = (isLarge ? LargeContextSlots : SmallContextSlots); header = headerForSlotsformatclassIndex(slotSize, indexablePointersFormat(), ClassMethodContextCompactIndex); flag("endianness"); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant2 = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(MoveCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction31 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction31)) { (anInstruction31->dependent = locateLiteral(4)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin AddCq:R: */ quickConstant3 = smallObjectBytesForSlots(slotSize); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AddCqR, quickConstant3, TempReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant3)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant4 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant4)); } /* begin JumpAboveOrEqual: */ jumpNeedScavenge = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ continuation = genoperandoperand(MoveRR, FPReg, TempReg); genSetSmallIntegerTagsIn(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (SenderIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BaseHeaderSize + (SenderIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, FoxSavedFP, FPReg, TempReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(FoxSavedFP)); } genSetSmallIntegerTagsIn(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (InstructionPointerIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize + (InstructionPointerIndex * BytesPerOop))); } /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodObject); /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(offset)); } /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (MethodIndex * BytesPerWord), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BaseHeaderSize + (MethodIndex * BytesPerWord))); } /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperandoperand(MoveRMwr, ReceiverResultReg, FoxThisContext, FPReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(FoxThisContext)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, SPReg, TempReg); /* begin LogicalShiftRightCq:R: */ quickConstant = 2 /* log2BytesPerWord */; genoperandoperand(LogicalShiftRightCqR, quickConstant, TempReg); /* begin SubCq:R: */ quickConstant5 = 3; /* begin checkQuickConstant:forInstruction: */ anInstruction22 = genoperandoperand(SubCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction22)) { (anInstruction22->dependent = locateLiteral(quickConstant5)); } /* begin AddR:R: */ genoperandoperand(AddRR, SendNumArgsReg, TempReg); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction23 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (StackPointerIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction23)) { (anInstruction23->dependent = locateLiteral(BaseHeaderSize + (StackPointerIndex * BytesPerOop))); } if (isInBlock > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, 2, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(2)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, TempReg, FPReg, TempReg); } else { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction36 = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction36)) { (anInstruction36->dependent = locateLiteral(constant)); } } } /* begin checkQuickConstant:forInstruction: */ anInstruction24 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (ClosureIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction24)) { (anInstruction24->dependent = locateLiteral(BaseHeaderSize + (ClosureIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction25 = genoperandoperandoperand(MoveMwrR, FoxMFReceiver, FPReg, TempReg); if (usesOutOfLineLiteral(anInstruction25)) { (anInstruction25->dependent = locateLiteral(FoxMFReceiver)); } /* begin checkQuickConstant:forInstruction: */ anInstruction26 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (ReceiverIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction26)) { (anInstruction26->dependent = locateLiteral(BaseHeaderSize + (ReceiverIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction27 = genoperandoperand(MoveCqR, 1, ClassReg); if (usesOutOfLineLiteral(anInstruction27)) { (anInstruction27->dependent = locateLiteral(1)); } /* begin CmpR:R: */ loopHead = genoperandoperand(CmpRR, SendNumArgsReg, ClassReg); /* begin JumpGreater: */ exit = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, ClassReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction28 = genoperandoperand(AddCqR, 2, TempReg); if (usesOutOfLineLiteral(anInstruction28)) { (anInstruction28->dependent = locateLiteral(2)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, TempReg, FPReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction29 = genoperandoperand(AddCqR, ReceiverIndex + (BaseHeaderSize / BytesPerWord), ClassReg); if (usesOutOfLineLiteral(anInstruction29)) { (anInstruction29->dependent = locateLiteral(ReceiverIndex + (BaseHeaderSize / BytesPerWord))); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, ClassReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction30 = genoperandoperand(SubCqR, (ReceiverIndex + (BaseHeaderSize / BytesPerWord)) - 1, ClassReg); if (usesOutOfLineLiteral(anInstruction30)) { (anInstruction30->dependent = locateLiteral((ReceiverIndex + (BaseHeaderSize / BytesPerWord)) - 1)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loopHead)); jmpTarget(exit, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin MoveCq:R: */ quickConstant1 = nilObject(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(MoveCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant1)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction32 = genoperandoperand(AddCqR, FoxMFReceiver, ClassReg); if (usesOutOfLineLiteral(anInstruction32)) { (anInstruction32->dependent = locateLiteral(FoxMFReceiver)); } /* begin checkQuickConstant:forInstruction: */ anInstruction33 = genoperandoperand(AddCqR, (ReceiverIndex + 1) + (BaseHeaderSize / BytesPerWord), SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction33)) { (anInstruction33->dependent = locateLiteral((ReceiverIndex + 1) + (BaseHeaderSize / BytesPerWord))); } /* begin checkQuickConstant:forInstruction: */ anInstruction34 = genoperandoperand(SubCqR, BytesPerWord, ClassReg); if (usesOutOfLineLiteral(anInstruction34)) { (anInstruction34->dependent = locateLiteral(BytesPerWord)); } loopHead = anInstruction34; /* begin CmpR:R: */ genoperandoperand(CmpRR, SPReg, ClassReg); /* begin JumpBelow: */ exit = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, SendNumArgsReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction35 = genoperandoperand(AddCqR, 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction35)) { (anInstruction35->dependent = locateLiteral(1)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loopHead)); jmpTarget(exit, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpNeedScavenge, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); CallRTregistersToBeSavedMask(ceScheduleScavengeTrampoline, ((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)); genoperand(PopR, LinkReg); /* begin Jump: */ genoperand(Jump, ((sqInt)continuation)); return 0; } /* Get the active context into ReceiverResultReg, creating it if necessary. */ /* CogObjectRepresentationForSpur>>#genGetActiveContextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genGetActiveContextNumArgslargeinBlock(sqInt numArgs, sqInt isLargeContext, sqInt isInBlock) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; sqInt routine; if (isLargeContext) { switch (isInBlock) { case 0: routine = ceLargeActiveContextInMethodTrampoline; break; case InVanillaBlock: routine = ceLargeActiveContextInBlockTrampoline; break; case InFullBlock: routine = ceLargeActiveContextInFullBlockTrampoline; break; default: error("Case not found and no otherwise clause"); routine = -1; } } else { switch (isInBlock) { case 0: routine = ceSmallActiveContextInMethodTrampoline; break; case InVanillaBlock: routine = ceSmallActiveContextInBlockTrampoline; break; case InFullBlock: routine = ceSmallActiveContextInFullBlockTrampoline; break; default: error("Case not found and no otherwise clause"); routine = -1; } } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, numArgs, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(numArgs)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, routine); (abstractInstruction->annotation = IsRelativeCall); return 0; } /* CogObjectRepresentationForSpur>>#genGetBits:ofFormatByteOf:into: */ static sqInt NoDbgRegParms genGetBitsofFormatByteOfinto(sqInt mask, sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, 3, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, mask, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(mask)); } return 0; } /* Fetch the instance's class index into destReg. */ /* CogObjectRepresentationForSpur>>#genGetClassIndexOfNonImm:into: */ static sqInt NoDbgRegParms genGetClassIndexOfNonImminto(sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return 0; } /* Fetch the class object whose index is in instReg into destReg. It is non-obvious, but the Cogit assumes loading a class does not involve a runtime call, so do not call classAtIndex: */ /* CogObjectRepresentationForSpur>>#genGetClassObjectOfClassIndex:into:scratchReg: */ static sqInt NoDbgRegParms genGetClassObjectOfClassIndexintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; sqInt offset; sqInt quickConstant; sqInt quickConstant2; sqInt quickConstant3; assert(instReg != destReg); assert(instReg != scratchReg); assert(destReg != scratchReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, scratchReg); /* begin LogicalShiftRightCq:R: */ quickConstant = classTableMajorIndexShift(); genoperandoperand(LogicalShiftRightCqR, quickConstant, scratchReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), scratchReg); assert(!(shouldAnnotateObjectReference(classTableRootObj()))); /* begin MoveMw:r:R: */ offset = (classTableRootObj()) + BaseHeaderSize; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, scratchReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, scratchReg); /* begin AndCq:R: */ quickConstant2 = classTableMinorIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AndCqR, quickConstant2, scratchReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin AddCq:R: */ quickConstant3 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, quickConstant3, scratchReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, scratchReg, destReg, destReg); return 0; } /* Fetch the instance's class into destReg. If the instance is not the receiver and is forwarded, follow forwarding. */ /* CogObjectRepresentationForSpur>>#genGetClassObjectOf:into:scratchReg:instRegIsReceiver: */ static sqInt NoDbgRegParms genGetClassObjectOfintoscratchReginstRegIsReceiver(sqInt instReg, sqInt destReg, sqInt scratchReg, sqInt instRegIsReceiver) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpIsImm; AbstractInstruction *jumpNotForwarded; AbstractInstruction *loop; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; if ((instReg == destReg) || ((instReg == scratchReg) || (destReg == scratchReg))) { return BadRegisterSet; } /* begin MoveR:R: */ loop = genoperandoperand(MoveRR, instReg, scratchReg); /* begin AndCq:R: */ quickConstant1 = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant1, scratchReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ jumpIsImm = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, 0, instReg, scratchReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant2 = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AndCqR, quickConstant2, scratchReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } if (!instRegIsReceiver) { /* if it is forwarded... */ /* begin CmpCq:R: */ quickConstant = isForwardedObjectClassIndexPun(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ jumpNotForwarded = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, BaseHeaderSize, instReg, instReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(BaseHeaderSize)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(jumpNotForwarded, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } jmpTarget(jumpIsImm, genoperandoperand(MoveRR, scratchReg, destReg)); if (scratchReg == TempReg) { /* begin PushR: */ genoperand(PushR, instReg); genGetClassObjectOfClassIndexintoscratchReg(destReg, instReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, destReg); /* begin PopR: */ genoperand(PopR, instReg); } else { genGetClassObjectOfClassIndexintoscratchReg(destReg, scratchReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, scratchReg, destReg); } return 0; } /* CogObjectRepresentationForSpur>>#genGetClassTagOf:into:scratchReg: */ static AbstractInstruction * NoDbgRegParms genGetClassTagOfintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg) { return genGetInlineCacheClassTagFromintoforEntry(instReg, destReg, 1); } /* Fetch the instance's class index into destReg. */ /* CogObjectRepresentationForSpur>>#genGetCompactClassIndexNonImmOf:into: */ static sqInt NoDbgRegParms genGetCompactClassIndexNonImmOfinto(sqInt instReg, sqInt destReg) { return genGetClassIndexOfNonImminto(instReg, destReg); } /* CogObjectRepresentationForSpur>>#genGetDoubleValueOf:into: */ static sqInt NoDbgRegParms genGetDoubleValueOfinto(sqInt srcReg, sqInt destFPReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveM64rRd, BaseHeaderSize, srcReg, destFPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BaseHeaderSize)); } return 0; } /* Get the format field of the object in srcReg into destReg. srcReg may equal destReg. */ /* CogObjectRepresentationForSpur>>#genGetFormatOf:into: */ static sqInt NoDbgRegParms genGetFormatOfinto(sqInt srcReg, sqInt destReg) { return genGetBitsofFormatByteOfinto(formatMask(), srcReg, destReg); } /* Get the format of the object in sourceReg into destReg. If scratchRegOrNone is not NoReg, load at least the least significant 32-bits (64-bits in 64-bits) of the header word, which contains the format, into scratchRegOrNone. */ /* CogObjectRepresentationForSpur>>#genGetFormatOf:into:leastSignificantHalfOfBaseHeaderIntoScratch: */ static sqInt NoDbgRegParms genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(sqInt sourceReg, sqInt destReg, sqInt scratchRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt quickConstant; sqInt quickConstant1; if (scratchRegOrNone == NoReg) { flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, 3, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, destReg, scratchRegOrNone); /* begin LogicalShiftRightCq:R: */ quickConstant = formatShift(); genoperandoperand(LogicalShiftRightCqR, quickConstant, destReg); } /* begin AndCq:R: */ quickConstant1 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant1, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } return 0; } /* Get the size in word-sized slots of the object in srcReg into destReg. srcReg may equal destReg. */ /* CogObjectRepresentationForSpur>>#genGetNumSlotsOf:into: */ static sqInt NoDbgRegParms genGetNumSlotsOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *jmp; sqInt quickConstant; assert(srcReg != destReg); genGetRawSlotSizeOfNonImminto(srcReg, destReg); /* begin CmpCq:R: */ quickConstant = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jmp = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genGetOverflowSlotsOfinto(srcReg, destReg); jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* The raw numSlots field is the most significant byte of the 64-bit header word. MoveMbrR zero-extends. */ /* CogObjectRepresentationForSpur>>#genGetRawSlotSizeOfNonImm:into: */ static sqInt NoDbgRegParms genGetRawSlotSizeOfNonImminto(sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction1; /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMbrR, 7, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(7)); } return 0; } /* CogObjectRepresentationForSpur>>#genJumpImmediate: */ static AbstractInstruction * NoDbgRegParms genJumpImmediate(sqInt aRegister) { AbstractInstruction *anInstruction; sqInt quickConstant; /* begin TstCq:R: */ quickConstant = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, quickConstant, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* CogObjectRepresentationForSpur>>#genJumpImmutable:scratchReg: */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpImmutablescratchReg(sqInt sourceReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin genJumpBaseHeaderImmutable: */ quickConstant = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } #endif /* IMMUTABILITY */ /* CogObjectRepresentationForSpur>>#genJumpMutable:scratchReg: */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpMutablescratchReg(sqInt sourceReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin genJumpBaseHeaderMutable: */ quickConstant = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } #endif /* IMMUTABILITY */ /* CogObjectRepresentationForSpur>>#genJumpNotCharacterInScratchReg: */ static AbstractInstruction * NoDbgRegParms genJumpNotCharacterInScratchReg(sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; sqInt quickConstant1; /* begin AndCq:R: */ quickConstant = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin CmpCq:R: */ quickConstant1 = characterTag(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* Generate a call to code that allocates a new Array of size. The Array should be initialized with nils iff initialized is true. The size arg is passed in SendNumArgsReg, the result must come back in ReceiverResultReg. */ /* CogObjectRepresentationForSpur>>#genNewArrayOfSize:initialized: */ static sqInt NoDbgRegParms genNewArrayOfSizeinitialized(sqInt size, sqInt initialized) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; sqInt constant; usqLong header; sqInt i; sqInt offset; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; assert(size < (numSlotsMask())); header = headerForSlotsformatclassIndex(size, arrayFormat(), ClassArrayCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } if (initialized && (size > 0)) { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(constant)); } } for (i = 0; i < size; i += 1) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, TempReg, (i * BytesPerWord) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((i * BytesPerWord) + BaseHeaderSize)); } } } /* begin LoadEffectiveAddressMw:r:R: */ offset = smallObjectBytesForSlots(size); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(LoadEffectiveAddressMwrR, offset, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(offset)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Create a closure with the given startpc, numArgs and numCopied within a context with ctxtNumArgs, large if isLargeCtxt that is in a block if isInBlock. Do /not/ initialize the copied values. */ /* CogObjectRepresentationForSpur>>#genNoPopCreateClosureAt:numArgs:numCopied:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; usqInt byteSize; usqLong header; sqInt literal; sqInt literal1; sqInt numSlots; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; /* First get thisContext into ReceiverResultRega and thence in ClassReg. */ genGetActiveContextNumArgslargeinBlock(ctxtNumArgs, isLargeCtxt, isInBlock); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); numSlots = ClosureFirstCopiedValueIndex + numCopied; byteSize = smallObjectBytesForSlots(numSlots); header = headerForSlotsformatclassIndex(numSlots, indexablePointersFormat(), ClassBlockClosureCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperandoperand(LoadEffectiveAddressMwrR, byteSize, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(byteSize)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperandoperand(MoveRMwr, ClassReg, (ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral((ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)bcpc << 1) | 1); anInstruction7 = genoperandoperand(MoveCqR, (((usqInt)bcpc << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(literal)); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal1 = (((usqInt)numArgs << 1) | 1); anInstruction9 = genoperandoperand(MoveCqR, (((usqInt)numArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(literal1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral((ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize)); } return 0; } /* CogObjectRepresentationForSpur>>#genPrimitiveAsCharacter */ static sqInt genPrimitiveAsCharacter(void) { AbstractInstruction *jumpNotInt; AbstractInstruction *jumpOutOfRange; sqInt reg; jumpNotInt = ((AbstractInstruction *) 0); if (methodOrBlockNumArgs == 0) { reg = ReceiverResultReg; } else { if (methodOrBlockNumArgs > 1) { return UnimplementedPrimitive; } reg = Arg0Reg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotInt = genJumpNotSmallInteger(reg); } /* begin MoveR:R: */ genoperandoperand(MoveRR, reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); jumpOutOfRange = jumpNotCharacterUnsignedValueInRegister(TempReg); genConvertSmallIntegerToCharacterInReg(reg); if (reg != ReceiverResultReg) { /* begin MoveR:R: */ genoperandoperand(MoveRR, reg, ReceiverResultReg); } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOutOfRange, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (reg != ReceiverResultReg) { jmpTarget(jumpNotInt, ((AbstractInstruction *) (((jumpOutOfRange->operands))[0]))); } return CompletePrimitive; } /* Generate primitive 60, at: with unsigned access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveAt */ static sqInt genPrimitiveAt(void) { return genPrimitiveAtSigned(0); } /* CogObjectRepresentationForSpur>>#genPrimitiveIdenticalOrNotIf: */ static sqInt NoDbgRegParms genPrimitiveIdenticalOrNotIf(sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *comp; sqInt constant; sqInt constant1; AbstractInstruction *jumpCmp; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin CmpR:R: */ comp = genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); if (orNot) { /* begin JumpZero: */ jumpCmp = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(Arg0Reg, TempReg, comp, 0); } else { /* begin JumpNonZero: */ jumpCmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* begin genMoveConstant:R: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!orNot) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(Arg0Reg, TempReg, comp, 0); } /* begin genMoveConstant:R: */ constant1 = falseObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gMoveCwR(constant1, ReceiverResultReg), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, constant1, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* Generate primitive 164, at: with signed access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveIntegerAt */ static sqInt genPrimitiveIntegerAt(void) { return genPrimitiveAtSigned(1); } /* Generate primitive 165, at:put: with signed access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveIntegerAtPut */ static sqInt genPrimitiveIntegerAtPut(void) { return genPrimitiveAtPutSigned(1); } /* CogObjectRepresentationForSpur>>#genPrimitiveObjectAt */ static sqInt genPrimitiveObjectAt(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt headerReg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBounds; AbstractInstruction *jumpNotHeaderIndex; sqInt literal; sqInt quickConstant; sqInt quickConstant1; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genGetMethodHeaderOfintoscratch(ReceiverResultReg, (headerReg = Arg1Reg), TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)1 << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)1 << 1) | 1), Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpNotHeaderIndex = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, headerReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotHeaderIndex, gAndCqR((((usqInt)(alternateHeaderNumLiteralsMask()) << 1) | 1), headerReg)); /* begin SubCq:R: */ quickConstant = ((((usqInt)1 << 1) | 1)) - (smallIntegerTag()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, quickConstant, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, headerReg, Arg0Reg); /* begin JumpAbove: */ jumpBounds = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin AddCq:R: */ quickConstant1 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg0Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpBounds, gAddCqR(((((usqInt)1 << 1) | 1)) - (smallIntegerTag()), Arg0Reg)); jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* c.f. StackInterpreter>>stSizeOf: lengthOf:baseHeader:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationForSpur>>#genPrimitiveSize */ static sqInt genPrimitiveSize(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction * jump32BitLongsDone; AbstractInstruction * jump64BitLongsDone; AbstractInstruction * jumpArrayDone; AbstractInstruction * jumpBytesDone; AbstractInstruction * jumpHasFixedFields; AbstractInstruction *jumpImm; AbstractInstruction * jumpIs64BitLongs; AbstractInstruction * jumpIsBytes; AbstractInstruction *jumpIsContext; AbstractInstruction * jumpIsContext1; AbstractInstruction * jumpIsShorts; AbstractInstruction *jumpNotIndexable; AbstractInstruction * jumpNotIndexable1; AbstractInstruction * jumpShortsDone; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; jumpImm = genJumpImmediate(ReceiverResultReg); /* begin genGetSizeOf:into:formatReg:scratchReg:abortJumpsInto: */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, SendNumArgsReg, TempReg); genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpGreaterOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpArrayDone = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin JumpLess: */ jumpNotIndexable1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpLessOrEqual: */ jumpHasFixedFields = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant3, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant3)); } /* begin JumpGreaterOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant4, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant4)); } /* begin JumpGreaterOrEqual: */ jump32BitLongsDone = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = sixtyFourBitIndexableFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant5, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant5)); } /* begin JumpZero: */ jumpIs64BitLongs = genConditionalBranchoperand(JumpZero, ((sqInt)0)); jmpTarget(jumpNotIndexable1, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin Jump: */ jumpNotIndexable1 = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, BytesPerWord - 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); /* begin Jump: */ jumpBytesDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(1)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); /* begin Jump: */ jumpShortsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIs64BitLongs, genoperandoperand(LogicalShiftRightCqR, 1, ClassReg)); /* begin Jump: */ jump64BitLongsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasFixedFields, gAndCqR(classIndexMask(), TempReg)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, SendNumArgsReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext1 = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, ClassReg); genGetClassObjectOfClassIndexintoscratchReg(SendNumArgsReg, ClassReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ClassReg, SendNumArgsReg); genConvertSmallIntegerToIntegerInReg(SendNumArgsReg); /* begin PopR: */ genoperand(PopR, ClassReg); /* begin AndCq:R: */ quickConstant6 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, quickConstant6, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); jmpTarget(jumpArrayDone, jmpTarget(jump64BitLongsDone, jmpTarget(jump32BitLongsDone, jmpTarget(jumpShortsDone, jmpTarget(jumpBytesDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); jumpNotIndexable = jumpNotIndexable1; jumpIsContext = jumpIsContext1; genConvertIntegerToSmallIntegerInReg(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImm, jmpTarget(jumpNotIndexable, jmpTarget(jumpIsContext, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); return CompletePrimitive; } /* primitiveCompareWith: */ /* CogObjectRepresentationForSpur>>#genPrimitiveStringCompareWith */ static sqInt genPrimitiveStringCompareWith(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction * instr; AbstractInstruction *jump; AbstractInstruction *jumpAbove; AbstractInstruction *jumpIncorrectFormat1; AbstractInstruction *jumpIncorrectFormat2; AbstractInstruction *jumpIncorrectFormat3; AbstractInstruction *jumpIncorrectFormat4; AbstractInstruction *jumpMidFailure; AbstractInstruction *jumpSuccess; sqInt minSizeReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt string1CharOrByteSizeReg; sqInt string1Reg; sqInt string2CharOrByteSizeReg; sqInt string2Reg; /* I redefine those name to ease program comprehension */ string1Reg = ReceiverResultReg; string2Reg = Arg0Reg; string1CharOrByteSizeReg = Arg1Reg; string2CharOrByteSizeReg = ClassReg; /* Load arguments in reg */ minSizeReg = SendNumArgsReg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetFormatOfinto(string1Reg, TempReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpAboveOrEqual: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(string1Reg, string1CharOrByteSizeReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), string1CharOrByteSizeReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, string1CharOrByteSizeReg); genGetFormatOfinto(string2Reg, TempReg); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpIncorrectFormat3 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant3, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIncorrectFormat4 = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(string2Reg, string2CharOrByteSizeReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), string2CharOrByteSizeReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, string2CharOrByteSizeReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, string1CharOrByteSizeReg, string2CharOrByteSizeReg); /* begin JumpBelow: */ jumpAbove = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, string1CharOrByteSizeReg, minSizeReg); /* begin Jump: */ jump = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpAbove, genoperandoperand(MoveRR, string2CharOrByteSizeReg, minSizeReg)); jmpTarget(jump, checkQuickConstantforInstruction(0, genoperandoperand(CmpCqR, 0, minSizeReg))); /* begin JumpZero: */ jumpSuccess = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, BaseHeaderSize, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, BaseHeaderSize, minSizeReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveXbr:R:R: */ instr = genoperandoperandoperand(MoveXbrRR, TempReg, string1Reg, string1CharOrByteSizeReg); /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, TempReg, string2Reg, string2CharOrByteSizeReg); /* begin SubR:R: */ genoperandoperand(SubRR, string2CharOrByteSizeReg, string1CharOrByteSizeReg); /* begin JumpNonZero: */ jumpMidFailure = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, minSizeReg); /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)instr)); genGetNumBytesOfinto(string1Reg, string1CharOrByteSizeReg); genGetNumBytesOfinto(string2Reg, string2CharOrByteSizeReg); jmpTarget(jumpSuccess, genoperandoperand(SubRR, string2CharOrByteSizeReg, string1CharOrByteSizeReg)); jmpTarget(jumpMidFailure, genoperandoperand(MoveRR, string1CharOrByteSizeReg, ReceiverResultReg)); genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIncorrectFormat4, jmpTarget(jumpIncorrectFormat3, jmpTarget(jumpIncorrectFormat2, jmpTarget(jumpIncorrectFormat1, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return CompletePrimitive; } /* replaceFrom: start to: stop with: replacement startingAt: repStart. The primitive in the JIT tries to deal with two pathological cases, copy of arrays and byteStrings, which often copies only a dozen of fields and where switching to the C runtime cost a lot. Based on heuristics on the method class, I generate a quick array path (typically for Array), a quick byteString path (typically for ByteString, ByteArray and LargeInteger) or no quick path at all (Typically for Bitmap). The many tests to ensure that the primitive won't fail are not super optimised (multiple reloading or stack arguments in registers) but this is still good enough and worth it since we're avoiding the Smalltalk to C stack switch. The tight copying loops are optimised. It is possible to build a bigger version with the 2 different paths but I (Clement) believe this is too big machine code wise to be worth it. */ /* CogObjectRepresentationForSpur>>#genPrimitiveStringReplace */ static sqInt genPrimitiveStringReplace(void) { sqInt adjust; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction22; AbstractInstruction *anInstruction23; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt arrayReg; AbstractInstruction * inst; AbstractInstruction * instr; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jumpEmpty; AbstractInstruction *jumpImm; AbstractInstruction *jumpImmutable; AbstractInstruction *jumpIncorrectFormat1; AbstractInstruction *jumpIncorrectFormat2; AbstractInstruction *jumpIncorrectFormat3; AbstractInstruction *jumpIncorrectFormat4; AbstractInstruction *jumpNotSmi1; AbstractInstruction *jumpNotSmi2; AbstractInstruction *jumpNotSmi3; AbstractInstruction *jumpOutOfBounds1; AbstractInstruction *jumpOutOfBounds2; AbstractInstruction *jumpOutOfBounds3; AbstractInstruction *jumpOutOfBounds4; sqInt literal; sqInt literal1; sqInt offset; sqInt offset1; sqInt offset2; sqInt offset3; sqInt offset4; sqInt offset5; sqInt offset6; sqInt offset7; sqInt offset8; sqInt offset9; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt replReg; sqInt repStartReg; sqInt result; sqInt startReg; sqInt stopReg; sqInt wordConstant; /* Can I generate a quick path for this method ? */ jmpAlreadyRemembered = ((AbstractInstruction *) 0); jumpImmutable = ((AbstractInstruction *) 0); jumpOutOfBounds3 = ((AbstractInstruction *) 0); jumpOutOfBounds4 = ((AbstractInstruction *) 0); if (!((seemsToBeInstantiating(arrayFormat())) || (seemsToBeInstantiating(firstByteFormat())))) { return UnimplementedPrimitive; } arrayReg = ReceiverResultReg; startReg = Arg0Reg; stopReg = Arg1Reg; replReg = ClassReg; /* Load arguments in reg */ repStartReg = SendNumArgsReg; /* begin genStackArgAt:into: */ offset6 = (0) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperandoperand(MoveMwrR, offset6, SPReg, repStartReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(offset6)); } /* begin genStackArgAt:into: */ offset7 = (1) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperandoperand(MoveMwrR, offset7, SPReg, replReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(offset7)); } /* begin genStackArgAt:into: */ offset8 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction22 = genoperandoperandoperand(MoveMwrR, offset8, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction22)) { (anInstruction22->dependent = locateLiteral(offset8)); } /* begin genStackArgAt:into: */ offset9 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction23 = genoperandoperandoperand(MoveMwrR, offset9, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction23)) { (anInstruction23->dependent = locateLiteral(offset9)); } /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi1 = genJumpNotSmallInteger(repStartReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi2 = genJumpNotSmallInteger(stopReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi3 = genJumpNotSmallInteger(startReg); /* if start>stop primitive success */ jumpImm = genJumpImmediate(replReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpLess: */ jumpEmpty = genConditionalBranchoperand(JumpLess, ((sqInt)0)); # if IMMUTABILITY jumpImmutable = genJumpImmutablescratchReg(ReceiverResultReg, TempReg); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)0 << 1) | 1); anInstruction12 = genoperandoperand(CmpCqR, (((usqInt)0 << 1) | 1), startReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(literal)); } /* begin JumpLessOrEqual: */ jumpOutOfBounds1 = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ literal1 = (((usqInt)0 << 1) | 1); anInstruction13 = genoperandoperand(CmpCqR, (((usqInt)0 << 1) | 1), repStartReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(literal1)); } /* begin JumpLessOrEqual: */ jumpOutOfBounds2 = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); if (seemsToBeInstantiating(arrayFormat())) { /* Are they both array format ? */ genGetFormatOfinto(arrayReg, TempReg); genGetFormatOfinto(replReg, startReg); /* begin CmpCq:R: */ quickConstant = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, startReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetNumSlotsOfinto(arrayReg, TempReg); genConvertSmallIntegerToIntegerInReg(stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds3 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); genGetNumSlotsOfinto(replReg, TempReg); /* begin genStackArgAt:into: */ offset = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperandoperand(MoveMwrR, offset, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(offset)); } genConvertSmallIntegerToIntegerInReg(startReg); genConvertSmallIntegerToIntegerInReg(repStartReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, stopReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds4 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, arrayReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(arrayReg, TempReg); } /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); callStoreCheckTrampoline(); genoperand(PopR, LinkReg); jmpTarget(jmpDestYoung, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin genStackArgAt:into: */ offset1 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveMwrR, offset1, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(offset1)); } genConvertSmallIntegerToIntegerInReg(stopReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, repStartReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), repStartReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, replReg); adjust = (((usqInt) BaseHeaderSize) >> (shiftForWord())) - 1; if (adjust != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, adjust, startReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(adjust)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, adjust, stopReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(adjust)); } } /* begin MoveXwr:R:R: */ instr = genoperandoperandoperand(MoveXwrRR, startReg, replReg, TempReg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, startReg, arrayReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, 1, startReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpAboveOrEqual: */ genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)instr)); jmpTarget(jumpEmpty, (methodOrBlockNumArgs <= 2 /* numRegArgs */ ? (/* begin RetN: */ genoperand(RetN, 0)) : (/* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord)))); jmpTarget(jumpIncorrectFormat1, jmpTarget(jumpIncorrectFormat2, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } if (seemsToBeInstantiating(firstByteFormat())) { /* Are they both byte array format ? CompiledMethod excluded */ genGetFormatOfinto(arrayReg, TempReg); genGetFormatOfinto(replReg, repStartReg); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant2, repStartReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, quickConstant3, repStartReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant3)); } /* begin JumpGreaterOrEqual: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant4)); } /* begin JumpLess: */ jumpIncorrectFormat3 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(CmpCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant5)); } /* begin JumpGreaterOrEqual: */ jumpIncorrectFormat4 = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(arrayReg, startReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), startReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, startReg); genConvertSmallIntegerToIntegerInReg(stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds3 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, repStartReg, TempReg); /* begin genStackArgAt:into: */ offset2 = (0) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, offset2, SPReg, repStartReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(offset2)); } /* begin genStackArgAt:into: */ offset3 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveMwrR, offset3, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(offset3)); } genConvertSmallIntegerToIntegerInReg(startReg); genConvertSmallIntegerToIntegerInReg(repStartReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, stopReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, stopReg); genGetNumSlotsOfinto(replReg, startReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), startReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, startReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds4 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin genStackArgAt:into: */ offset4 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, offset4, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(offset4)); } genConvertSmallIntegerToIntegerInReg(startReg); /* begin genStackArgAt:into: */ offset5 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveMwrR, offset5, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(offset5)); } genConvertSmallIntegerToIntegerInReg(stopReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, repStartReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, replReg); adjust = BaseHeaderSize - 1; if (adjust != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, adjust, startReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(adjust)); } /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, adjust, stopReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(adjust)); } } /* begin MoveXbr:R:R: */ instr = genoperandoperandoperand(MoveXbrRR, startReg, replReg, TempReg); /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, startReg, arrayReg); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, 1, startReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpAboveOrEqual: */ genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)instr)); jmpTarget(jumpEmpty, (methodOrBlockNumArgs <= 2 /* numRegArgs */ ? (/* begin RetN: */ genoperand(RetN, 0)) : (/* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord)))); jmpTarget(jumpIncorrectFormat4, jmpTarget(jumpIncorrectFormat3, jmpTarget(jumpIncorrectFormat2, jmpTarget(jumpIncorrectFormat1, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); } if (((result = compileInterpreterPrimitive())) < 0) { return result; } jmpTarget(jumpImm, jmpTarget(jumpNotSmi1, jmpTarget(jumpNotSmi2, jmpTarget(jumpNotSmi3, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); jmpTarget(jumpOutOfBounds1, jmpTarget(jumpOutOfBounds2, jmpTarget(jumpOutOfBounds3, jmpTarget(jumpOutOfBounds4, ((AbstractInstruction *) (((jumpImm->operands))[0])))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpImm->operands))[0]))); # endif /* IMMUTABILITY */ return CompletePrimitive; } /* CogObjectRepresentationForSpur>>#genSetSmallIntegerTagsIn: */ static sqInt NoDbgRegParms genSetSmallIntegerTagsIn(sqInt scratchReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(OrCqR, 1, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Create a trampoline to store-check the update of the receiver in a closure's outerContext in compileBlockFrameBuild:. */ /* CogObjectRepresentationForSpur>>#genStoreCheckContextReceiverTrampoline */ static sqInt genStoreCheckContextReceiverTrampoline(void) { sqInt startAddress; startAddress = methodZoneBase(); zeroOpcodeIndex(); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg0Reg, TempReg, 0); /* begin RetN: */ genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceStoreCheckContextReceiver", startAddress); recordRunTimeObjectReferences(); return startAddress; } /* Generate the code for a store check of valueReg into destReg. */ /* CogObjectRepresentationForSpur>>#genStoreCheckReceiverReg:valueReg:scratchReg:inFrame: */ static sqInt NoDbgRegParms genStoreCheckReceiverRegvalueRegscratchReginFrame(sqInt destReg, sqInt valueReg, sqInt scratchReg, sqInt inFrame) { AbstractInstruction *abstractInstruction; AbstractInstruction * inst; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jmpImmediate; AbstractInstruction *jmpSourceOld; sqInt wordConstant; /* Is value stored an immediate? If so we're done */ jmpAlreadyRemembered = ((AbstractInstruction *) 0); /* Get the old/new boundary in scratchReg */ jmpImmediate = genJumpImmediate(valueReg); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, scratchReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, destReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, valueReg); /* begin JumpAboveOrEqual: */ jmpSourceOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(destReg, scratchReg); } assert(destReg == ReceiverResultReg); /* begin evaluateTrampolineCallBlock:protectLinkRegIfNot: */ if (inFrame) { /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); } else { /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); } jmpTarget(jmpImmediate, jmpTarget(jmpDestYoung, jmpTarget(jmpSourceOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, ((AbstractInstruction *) (((jmpSourceOld->operands))[0]))); } return 0; } /* CogObjectRepresentationForSpur>>#genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: */ static sqInt NoDbgRegParms genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt inFrame, sqInt needsStoreCheck) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } if (needsStoreCheck) { return genStoreCheckReceiverRegvalueRegscratchReginFrame(destReg, sourceReg, scratchReg, inFrame); } return 0; } /* This method is used for unchecked stores in objects after their creation (typically, inlined creation of Array, closures and some temp vectors). Currently there is no need to do the immutability check here */ /* CogObjectRepresentationForSpur>>#genStoreSourceReg:slotIndex:intoNewObjectInDestReg: */ static sqInt NoDbgRegParms genStoreSourceRegslotIndexintoNewObjectInDestReg(sqInt sourceReg, sqInt index, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } return 0; } /* Convention: - RcvrResultReg holds the object mutated. If immutability failure: - TempReg holds the instance variable index mutated if instVarIndex > numDedicatedStoreTrampoline - ClassReg holds the value to store Registers are not lived across this trampoline as the immutability failure may need new stack frames. */ /* CogObjectRepresentationForSpur>>#genStoreTrampolineCalled:instVarIndex: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreTrampolineCalledinstVarIndex(char *trampolineName, sqInt instVarIndex) { AbstractInstruction *jumpRC; AbstractInstruction *jumpSC; zeroOpcodeIndex(); jumpSC = genJumpMutablescratchReg(ReceiverResultReg, SendNumArgsReg); compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceCannotAssignTowithIndexvalueToAssign, 3, ReceiverResultReg, (instVarIndex < (NumStoreTrampolines - 1) ? (/* begin trampolineArgConstant: */ assert(instVarIndex >= 0), -2 - instVarIndex) : TempReg), ClassReg, null, 0 /* emptyRegisterMask */, 1, NoReg); jmpTarget(jumpSC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (CheckRememberedInTrampoline) { jumpRC = genCheckRememberedBitOfscratch(ReceiverResultReg, SendNumArgsReg); assert(((jumpRC->opcode)) == JumpNonZero); (jumpRC->opcode = JumpZero); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpRC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(remember, trampolineName, 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); } #endif /* IMMUTABILITY */ /* Store check code is duplicated to use a single trampoline */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityAndStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *immutableJump; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jmpImmediate; AbstractInstruction *jmpSourceOld; sqInt wordConstant; jmpAlreadyRemembered = ((AbstractInstruction *) 0); immutableJump = genJumpImmutablescratchReg(destReg, scratchReg); /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } /* Get the old/new boundary in scratchReg */ jmpImmediate = genJumpImmediate(sourceReg); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, scratchReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, destReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, sourceReg); /* begin JumpAboveOrEqual: */ jmpSourceOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(destReg, scratchReg); } jmpTarget(immutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (index >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, index, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(index)); } /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction3->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[index]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); if (needRestoreRcvr) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } jmpTarget(jmpImmediate, jmpTarget(jmpDestYoung, jmpTarget(jmpSourceOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, ((AbstractInstruction *) (((jmpSourceOld->operands))[0]))); } return 0; } #endif /* IMMUTABILITY */ /* Gen an immutability check with no store check (e.g. assigning an immediate literal) */ /* imm check has its own trampoline */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityButNoStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *immutabilityFailure; AbstractInstruction *mutableJump; mutableJump = genJumpMutablescratchReg(destReg, scratchReg); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (index >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, index, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(index)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[index]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); if (needRestoreRcvr) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } /* begin Jump: */ immutabilityFailure = genoperand(Jump, ((sqInt)0)); jmpTarget(mutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction3->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } jmpTarget(immutabilityFailure, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } #endif /* IMMUTABILITY */ /* We know there is a frame as immutability check requires a frame */ /* needRestoreRcvr has to be true to keep RcvrResultReg live with the receiver in it across the trampoline */ /* Trampoline convention... */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityCheckSourceReg:slotIndex:destReg:scratchReg:needsStoreCheck:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needsStoreCheck, sqInt needRestoreRcvr) { assert(destReg == ReceiverResultReg); assert(scratchReg == TempReg); assert(sourceReg == ClassReg); if (needsStoreCheck) { genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sourceReg, index, destReg, scratchReg, needRestoreRcvr); } else { genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sourceReg, index, destReg, scratchReg, needRestoreRcvr); } return 0; } #endif /* IMMUTABILITY */ /* Make sure SendNumArgsReg and ClassReg are available in addition to ReceiverResultReg and TempReg in genGetActiveContextNumArgs:large:inBlock:. */ /* CogObjectRepresentationForSpur>>#getActiveContextAllocatesInMachineCode */ static sqInt getActiveContextAllocatesInMachineCode(void) { return 1; } /* Since all cache tags in Spur are class indices none of them are young or have to be updated in a scavenge. */ /* CogObjectRepresentationForSpur>>#inlineCacheTagIsYoung: */ static sqInt NoDbgRegParms inlineCacheTagIsYoung(sqInt cacheTag) { return 0; } /* CogObjectRepresentationForSpur>>#jumpNotCharacterUnsignedValueInRegister: */ static AbstractInstruction * NoDbgRegParms jumpNotCharacterUnsignedValueInRegister(sqInt reg) { AbstractInstruction *anInstruction; /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, (1U << 30 /* numCharacterBits */) - 1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((1U << 30 /* numCharacterBits */) - 1)); } /* begin JumpAbove: */ return genConditionalBranchoperand(JumpAbove, ((sqInt)0)); } /* Mark and trace a literal in a machine code instruction preceding address in cogMethodOrNil. Answer if code was modified. */ /* CogObjectRepresentationForSpur>>#markAndTraceLiteral:in:atpc: */ static sqInt NoDbgRegParms markAndTraceLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address) { sqInt objOop; if (!(couldBeObject(literal))) { return 0; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return 0; } objOop = followForwarded(literal); storeLiteralbeforeFollowingAddress(backEnd(), objOop, address); markAndTraceUpdatedLiteralin(objOop, cogMethodOrNil); return 1; } /* Mark and trace a literal in a sqInt variable of cogMethod. */ /* CogObjectRepresentationForSpur>>#markAndTraceLiteral:in:at: */ static void NoDbgRegParms markAndTraceLiteralinat(sqInt literal, CogMethod *cogMethod, sqInt *address) { sqInt objOop; if (!(couldBeObject(literal))) { return; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return; } objOop = followForwarded(literal); address[0] = objOop; markAndTraceUpdatedLiteralin(objOop, cogMethod); } /* Common code to mark a literal in cogMethod and add the cogMethod to youngReferrers if the literal is young. */ /* CogObjectRepresentationForSpur>>#markAndTraceUpdatedLiteral:in: */ static void NoDbgRegParms markAndTraceUpdatedLiteralin(sqInt objOop, CogMethod *cogMethodOrNil) { if (isNonImmediate(objOop)) { if ((cogMethodOrNil != null) && (isYoungObject(objOop))) { ensureInYoungReferrers(cogMethodOrNil); } markAndTrace(objOop); } } /* If primIndex has an accessorDepth and fails, or it is external and fails with PrimErrNoMemory, call ceCheckAndMaybeRetryPrimitive if so If ceCheck.... answers true, retry the primitive. */ /* CogObjectRepresentationForSpur>>#maybeCompileRetryOnPrimitiveFail: */ static sqInt NoDbgRegParms maybeCompileRetryOnPrimitiveFail(sqInt primIndex) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmp; if ((accessorDepthForPrimitiveIndex(primIndex)) >= 0) { /* begin MoveAw:R: */ address = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmp = genConditionalBranchoperand(JumpZero, ((sqInt)0)); } else { if ((primNumberExternalCall()) != primIndex) { return 0; } /* begin MoveAw:R: */ address1 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, PrimErrNoMemory, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(PrimErrNoMemory)); } /* begin JumpNonZero: */ jmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } compileCallFornumArgsargargargargresultRegregsToSave(ceCheckAndMaybeRetryPrimitive, 1, trampolineArgConstant(primIndex), null, null, null, TempReg, 0 /* emptyRegisterMask */); jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Generate a shift of the register containing the class tag in a method cache probe. c.f. SpurMemoryManager>>methodCacheHashOf:with: */ /* CogObjectRepresentationForSpur>>#maybeShiftClassTagRegisterForMethodCacheProbe: */ static sqInt NoDbgRegParms maybeShiftClassTagRegisterForMethodCacheProbe(sqInt classTagReg) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 2, classTagReg); return 0; } /* CogObjectRepresentationForSpur>>#numCharacterBits */ static sqInt numCharacterBits(void) { return 30; } /* Define how many register arguments a StackToRegisterMappingCogit can and should use with the receiver. The value must be 0, 1 or 2. Note that a SimpleStackBasedCogit always has 0 register args (although the receiver is passed in a register). The Spur object representation is simple enough that implementing at:put: is straight-forward and hence 2 register args are worth while. The method must be inlined in CoInterpreter, and dead code eliminated so that the register-popping enilopmarts such as enterRegisterArgCogMethod:- at:receiver: do not have to be implemented in SimpleStackBasedCogit. */ /* CogObjectRepresentationForSpur>>#numRegArgs */ sqInt numRegArgs(void) { return 2; } /* CogObjectRepresentationForSpur>>#remapObject: */ static sqInt NoDbgRegParms remapObject(sqInt objOop) { assert(addressCouldBeObj(objOop)); return (shouldRemapObj(objOop) ? remapObj(objOop) : objOop); } /* CogObjectRepresentationForSpur>>#remapOop: */ static sqInt NoDbgRegParms remapOop(sqInt objOop) { return (shouldRemapOop(objOop) ? remapObj(objOop) : objOop); } /* Objects in newSpace or oldSpace except nil, true, false & classTableRootObj need to be annotated. */ /* CogObjectRepresentationForSpur>>#shouldAnnotateObjectReference: */ static sqInt NoDbgRegParms shouldAnnotateObjectReference(sqInt anOop) { return (isNonImmediate(anOop)) && ((oopisGreaterThan(anOop, classTableRootObj())) || (oopisLessThan(anOop, nilObject()))); } /* CogObjectRepresentationForSpur>>#slotOffsetOfInstVarIndex: */ static sqInt NoDbgRegParms slotOffsetOfInstVarIndex(sqInt index) { return (index * BytesPerWord) + BaseHeaderSize; } /* CogOutOfLineLiteralsARMCompiler>>#cmpC32RTempByteSize */ static sqInt NoDbgRegParms cmpC32RTempByteSize(AbstractInstruction * self_in_cmpC32RTempByteSize) { return 8; } /* Generate an out-of-line literal. Copy the value and any annotation from the stand-in in the literals manager. */ /* CogOutOfLineLiteralsARMCompiler>>#concretizeLiteral */ static AbstractInstruction * NoDbgRegParms concretizeLiteral(AbstractInstruction * self_in_concretizeLiteral) { usqInt literal; AbstractInstruction * literalAsInstruction; literalAsInstruction = ((AbstractInstruction *) (((self_in_concretizeLiteral->operands))[0])); literal = ((addressIsInInstructions(literalAsInstruction)) || (literalAsInstruction == (methodLabel())) ? (literalAsInstruction->address) : ((usqInt)literalAsInstruction)); assert((((self_in_concretizeLiteral->dependent)) != null) && (((((self_in_concretizeLiteral->dependent))->opcode)) == Literal)); if (!(((((self_in_concretizeLiteral->dependent))->annotation)) == null)) { assert(((self_in_concretizeLiteral->annotation)) == null); (self_in_concretizeLiteral->annotation) = (((self_in_concretizeLiteral->dependent))->annotation); } if (!(((((self_in_concretizeLiteral->dependent))->address)) == null)) { assert(((((self_in_concretizeLiteral->dependent))->address)) == ((self_in_concretizeLiteral->address))); } (((self_in_concretizeLiteral->dependent))->address = (self_in_concretizeLiteral->address)); /* begin machineCodeAt:put: */ ((self_in_concretizeLiteral->machineCode))[0 / 4] = literal; (self_in_concretizeLiteral->machineCodeSize) = 4; return self_in_concretizeLiteral; } /* CogOutOfLineLiteralsARMCompiler>>#inlineCacheTagAt: */ static sqInt NoDbgRegParms inlineCacheTagAt(AbstractInstruction * self_in_inlineCacheTagAt, sqInt callSiteReturnAddress) { return longAt(pcRelativeAddressAt(self_in_inlineCacheTagAt, ((usqInt)(callSiteReturnAddress - 8)))); } /* Answer if the receiver is a pc-dependent instruction. With out-of-line literals any instruction that refers to a literal depends on the address of the literal, so add them in addition to the jumps. */ /* CogOutOfLineLiteralsARMCompiler>>#isPCDependent */ static sqInt NoDbgRegParms isPCDependent(AbstractInstruction * self_in_isPCDependent) { return (isJump(self_in_isPCDependent)) || ((((self_in_isPCDependent->opcode)) == AlignmentNops) || ((((self_in_isPCDependent->opcode)) != Literal) && ((((self_in_isPCDependent->dependent)) != null) && (((((self_in_isPCDependent->dependent))->opcode)) == Literal)))); } /* Return the literal referenced by the instruction immediately preceding followingAddress. */ /* CogOutOfLineLiteralsARMCompiler>>#literalBeforeFollowingAddress: */ static sqInt NoDbgRegParms literalBeforeFollowingAddress(AbstractInstruction * self_in_literalBeforeFollowingAddress, sqInt followingAddress) { return longAt(pcRelativeAddressAt(self_in_literalBeforeFollowingAddress, (instructionIsLDR(self_in_literalBeforeFollowingAddress, longAt(followingAddress - 4)) ? (/* begin instructionAddressBefore: */ followingAddress - 4) : (/* begin instructionAddressBefore: */ (followingAddress - 4) - 4)))); } /* Answer the size of a literal load instruction (which does not include the size of the literal). With out-of-line literals this is always a single LDR instruction that refers to the literal. */ /* CogOutOfLineLiteralsARMCompiler>>#literalLoadInstructionBytes */ static sqInt NoDbgRegParms literalLoadInstructionBytes(AbstractInstruction * self_in_literalLoadInstructionBytes) { return 4; } /* Answer the byte size of a MoveCwR opcode's corresponding machine code. On ARM this is a single instruction pc-relative register load - unless we have made a mistake and not turned on the out of line literals manager */ /* CogOutOfLineLiteralsARMCompiler>>#loadLiteralByteSize */ static sqInt NoDbgRegParms loadLiteralByteSize(AbstractInstruction * self_in_loadLiteralByteSize) { return 4; } /* Answer the NSSendCache for the return address of a Newspeak self, super, outer, or implicit receiver send. */ /* CogOutOfLineLiteralsARMCompiler>>#nsSendCacheAt: */ static sqInt NoDbgRegParms nsSendCacheAt(AbstractInstruction * self_in_nsSendCacheAt, sqInt callSiteReturnAddress) { return longAt(pcRelativeAddressAt(self_in_nsSendCacheAt, ((usqInt)(callSiteReturnAddress - 8)))); } /* The maximum offset in a LDR is (1<<12)-1, or (1<<10)-1 instructions. Be conservative. The issue is that one abstract instruction can emit multiple hardware instructions so we assume a 2 to 1 worst case of hardware instructions to abstract opcodes.. */ /* CogOutOfLineLiteralsARMCompiler>>#outOfLineLiteralOpcodeLimit */ static sqInt NoDbgRegParms outOfLineLiteralOpcodeLimit(AbstractInstruction * self_in_outOfLineLiteralOpcodeLimit) { return (1U << ((12 - 2) - 1)) - 1; } /* Extract the address of the ldr rX, [pc, #NNN] instruction at address */ /* CogOutOfLineLiteralsARMCompiler>>#pcRelativeAddressAt: */ static sqInt NoDbgRegParms pcRelativeAddressAt(AbstractInstruction * self_in_pcRelativeAddressAt, sqInt instrAddress) { sqInt inst; sqInt offset; inst = longAt(instrAddress); assert((inst & 4284416000U) == (ldrrnplusimm(self_in_pcRelativeAddressAt, 0, PC, 0, 0))); offset = inst & 0xFFF; return (instrAddress + 8) + ((inst & (1U << 23) ? offset : -offset)); } /* If possible we generate the method address using pc-relative addressing. If so we don't need to relocate it in code. So check if pc-relative code was generated, and if not, adjust a load literal. There are two cases, a push or a register load. If a push, then there is a register load, but in the instruction before. */ /* CogOutOfLineLiteralsARMCompiler>>#relocateMethodReferenceBeforeAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateMethodReferenceBeforeAddressby(AbstractInstruction * self_in_relocateMethodReferenceBeforeAddressby, sqInt pc, sqInt delta) { sqInt litAddr; sqInt pcPrecedingLoad; sqInt reference; /* If the load is not done via pc-relative addressing we have to relocate. */ pcPrecedingLoad = (instructionIsPush(self_in_relocateMethodReferenceBeforeAddressby, longAt(pc - 4)) ? pc - 4 : pc); if (!(isPCRelativeValueLoad(self_in_relocateMethodReferenceBeforeAddressby, longAt(pcPrecedingLoad - 4)))) { litAddr = pcRelativeAddressAt(self_in_relocateMethodReferenceBeforeAddressby, pcPrecedingLoad); reference = longAt(litAddr); longAtput(litAddr, reference + delta); } return self_in_relocateMethodReferenceBeforeAddressby; } /* Rewrite a CallFull or JumpFull instruction to transfer to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'bx ip' or 'blx ip' instruction for the actual jump or call. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteFullTransferAt:target:expectedInstruction: */ static sqInt NoDbgRegParms rewriteFullTransferAttargetexpectedInstruction(AbstractInstruction * self_in_rewriteFullTransferAttargetexpectedInstruction, usqInt callSiteReturnAddress, usqInt callTargetAddress, sqInt expectedInstruction) { assert((instructionBeforeAddress(self_in_rewriteFullTransferAttargetexpectedInstruction, callSiteReturnAddress)) == expectedInstruction); longAtput(pcRelativeAddressAt(self_in_rewriteFullTransferAttargetexpectedInstruction, callSiteReturnAddress - 8), callTargetAddress); return 0; } /* Rewrite an inline cache to call a different target for a new tag. This variant is used to link unlinked sends in ceSend:to:numArgs: et al. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteInlineCacheAt:tag:target: */ static sqInt NoDbgRegParms rewriteInlineCacheAttagtarget(AbstractInstruction * self_in_rewriteInlineCacheAttagtarget, usqInt callSiteReturnAddress, sqInt cacheTag, usqInt callTargetAddress) { sqInt call; usqInt callDistance; if (!(callTargetAddress >= (minCallAddress()))) { error("linking callsite to invalid address"); } /* pc offset */ /* return offset */ callDistance = ((usqInt) (callTargetAddress - ((callSiteReturnAddress + 8) - 4))); assert(isInImmediateJumpRange(self_in_rewriteInlineCacheAttagtarget, callDistance)); call = bl(self_in_rewriteInlineCacheAttagtarget, callDistance); longAtput(callSiteReturnAddress - 4, call); longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheAttagtarget, callSiteReturnAddress - 8), cacheTag); assert((inlineCacheTagAt(self_in_rewriteInlineCacheAttagtarget, callSiteReturnAddress)) == cacheTag); return 4; } /* Rewrite an inline cache with a new tag. This variant is used by the garbage collector. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteInlineCacheTag:at: */ static AbstractInstruction * NoDbgRegParms rewriteInlineCacheTagat(AbstractInstruction * self_in_rewriteInlineCacheTagat, sqInt cacheTag, sqInt callSiteReturnAddress) { longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheTagat, callSiteReturnAddress - 8), cacheTag); return self_in_rewriteInlineCacheTagat; } /* Size a jump and set its address. The target may be another instruction or an absolute address. On entry the address inst var holds our virtual address. On exit address is set to eventualAbsoluteAddress, which is where this instruction will be output. The span of a jump to a following instruction is therefore between that instruction's address and this instruction's address ((which are both still their virtual addresses), but the span of a jump to a preceding instruction or to an absolute address is between that instruction's address (which by now is its eventual absolute address) or absolute address and eventualAbsoluteAddress. ARM is simple; the 26-bit call/jump range means no short jumps. This routine only has to determine the targets of jumps, not determine sizes. This version also deals with out-of-line literals. If this is the real literal, update the stand-in in literalsManager with the address (because instructions referring to the literal are referring to the stand-in). If this is annotated with IsObjectReference transfer the annotation to the stand-in, whence it will be transferred to the real literal, simplifying update of literals. */ /* CogOutOfLineLiteralsARMCompiler>>#sizePCDependentInstructionAt: */ static usqInt NoDbgRegParms sizePCDependentInstructionAt(AbstractInstruction * self_in_sizePCDependentInstructionAt, sqInt eventualAbsoluteAddress) { usqInt alignment; if (((self_in_sizePCDependentInstructionAt->opcode)) == AlignmentNops) { (self_in_sizePCDependentInstructionAt->address) = eventualAbsoluteAddress; alignment = ((self_in_sizePCDependentInstructionAt->operands))[0]; return ((self_in_sizePCDependentInstructionAt->machineCodeSize) = ((eventualAbsoluteAddress + (alignment - 1)) & (-alignment)) - eventualAbsoluteAddress); } assert((isJump(self_in_sizePCDependentInstructionAt)) || ((((self_in_sizePCDependentInstructionAt->opcode)) == Call) || ((((self_in_sizePCDependentInstructionAt->opcode)) == CallFull) || ((((self_in_sizePCDependentInstructionAt->dependent)) != null) && (((((self_in_sizePCDependentInstructionAt->dependent))->opcode)) == Literal))))); if (isJump(self_in_sizePCDependentInstructionAt)) { resolveJumpTarget(self_in_sizePCDependentInstructionAt); } (self_in_sizePCDependentInstructionAt->address) = eventualAbsoluteAddress; if ((((self_in_sizePCDependentInstructionAt->dependent)) != null) && (((((self_in_sizePCDependentInstructionAt->dependent))->opcode)) == Literal)) { if (((self_in_sizePCDependentInstructionAt->opcode)) == Literal) { (((self_in_sizePCDependentInstructionAt->dependent))->address = (self_in_sizePCDependentInstructionAt->address)); } if (((self_in_sizePCDependentInstructionAt->annotation)) == (getIsObjectReference())) { (((self_in_sizePCDependentInstructionAt->dependent))->annotation = (self_in_sizePCDependentInstructionAt->annotation)); (self_in_sizePCDependentInstructionAt->annotation) = null; } } return ((self_in_sizePCDependentInstructionAt->machineCodeSize) = (self_in_sizePCDependentInstructionAt->maxSize)); } /* Rewrite the literal in the instruction immediately preceding followingAddress. */ /* CogOutOfLineLiteralsARMCompiler>>#storeLiteral:beforeFollowingAddress: */ static AbstractInstruction * NoDbgRegParms storeLiteralbeforeFollowingAddress(AbstractInstruction * self_in_storeLiteralbeforeFollowingAddress, sqInt literal, sqInt followingAddress) { longAtput(pcRelativeAddressAt(self_in_storeLiteralbeforeFollowingAddress, (instructionIsLDR(self_in_storeLiteralbeforeFollowingAddress, longAt(followingAddress - 4)) ? (/* begin instructionAddressBefore: */ followingAddress - 4) : (/* begin instructionAddressBefore: */ (followingAddress - 4) - 4))), literal); return self_in_storeLiteralbeforeFollowingAddress; } /* Update an instruction that depends on a label outside of generated code (e.g. a method or block header). */ /* CogOutOfLineLiteralsARMCompiler>>#updateLabel: */ static AbstractInstruction * NoDbgRegParms updateLabel(AbstractInstruction * self_in_updateLabel, AbstractInstruction *labelInstruction) { if (((self_in_updateLabel->opcode)) != Literal) { assert((((self_in_updateLabel->opcode)) == MoveCwR) || (((self_in_updateLabel->opcode)) == PushCw)); ((self_in_updateLabel->operands))[0] = (((labelInstruction->address)) + (((labelInstruction->operands))[1])); } return self_in_updateLabel; } /* Answer if the receiver uses an out-of-line literal. Needs only to work for the opcodes created with gen:literal:operand: et al. */ /* CogOutOfLineLiteralsARMCompiler>>#usesOutOfLineLiteral */ static sqInt NoDbgRegParms usesOutOfLineLiteral(AbstractInstruction * self_in_usesOutOfLineLiteral) { sqInt constant; sqInt constant1; sqInt constant2; sqInt constant3; sqInt constant4; sqInt constant5; sqInt i1; sqInt i2; sqInt i3; sqInt i4; sqInt value; unsigned int value1; unsigned int value2; switch ((self_in_usesOutOfLineLiteral->opcode)) { case CallFull: case JumpFull: case AddCwR: case AndCwR: case CmpCwR: case OrCwR: case SubCwR: case XorCwR: return 1; case AddCqR: case CmpCqR: case SubCqR: /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ constant = ((self_in_usesOutOfLineLiteral->operands))[0]; value = constant; while (1) { if ((value & 0xFF) == value) { return 0; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value) { return 0; } } if (!((value == constant) && (constant != 0))) break; value = -constant; } return 1; case AndCqR: case AndCqRR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant1 = ((self_in_usesOutOfLineLiteral->operands))[0]; value1 = constant1; while (1) { if ((value1 & 0xFF) == value1) { return 0; } for (i2 = 2; i2 <= 30; i2 += 2) { if ((value1 & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == value1) { return 0; } } if (!(value1 == constant1)) break; value1 = (constant1 < 0 ? -1 - constant1 : (unsigned int)~constant1); } return (1U << (highBit(((self_in_usesOutOfLineLiteral->operands))[0]))) != ((((self_in_usesOutOfLineLiteral->operands))[0]) + 1); case OrCqR: case TstCqR: case LoadEffectiveAddressMwrR: case MoveCqR: case MoveM16rR: case PushCq: /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ constant2 = ((self_in_usesOutOfLineLiteral->operands))[0]; if ((constant2 & 0xFF) == constant2) { return 0; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant2 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant2) { return 0; } } return 1; case XorCqR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant3 = ((self_in_usesOutOfLineLiteral->operands))[0]; value2 = constant3; while (1) { if ((value2 & 0xFF) == value2) { return 0; } for (i4 = 2; i4 <= 30; i4 += 2) { if ((value2 & (((0xFFU << i4) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i4)))) == value2) { return 0; } } if (!(value2 == constant3)) break; value2 = (constant3 < 0 ? -1 - constant3 : (unsigned int)~constant3); } return 1; case MoveCwR: case PushCw: return !(((addressIsInInstructions(((AbstractInstruction *) (((self_in_usesOutOfLineLiteral->operands))[0])))) || ((((AbstractInstruction *) (((self_in_usesOutOfLineLiteral->operands))[0]))) == (methodLabel()))) || (((((usqInt)(((self_in_usesOutOfLineLiteral->operands))[0]))) >= ((methodLabel->address))) && ((((usqInt)(((self_in_usesOutOfLineLiteral->operands))[0]))) < (youngReferrers())))); case MoveAwR: case MoveAbR: case PrefetchAw: return (((((self_in_usesOutOfLineLiteral->operands))[0]) != null) && (((((self_in_usesOutOfLineLiteral->operands))[0]) >= (varBaseAddress())) && (((((self_in_usesOutOfLineLiteral->operands))[0]) - (varBaseAddress())) < (1U << 12))) ? 0 : 1); case MoveRAw: case MoveRAb: return (((((self_in_usesOutOfLineLiteral->operands))[1]) != null) && (((((self_in_usesOutOfLineLiteral->operands))[1]) >= (varBaseAddress())) && (((((self_in_usesOutOfLineLiteral->operands))[1]) - (varBaseAddress())) < (1U << 12))) ? 0 : 1); case MoveRMwr: case MoveRdM64r: case MoveRMbr: case MoveRM16r: /* begin is12BitValue:ifTrue:ifFalse: */ constant4 = ((self_in_usesOutOfLineLiteral->operands))[1]; if ((SQABS(constant4)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant4 >= 0) { return 0; } else { return 0; } } else { return 1; } case MoveMbrR: case MoveM64rRd: case MoveMwrR: /* begin is12BitValue:ifTrue:ifFalse: */ constant5 = ((self_in_usesOutOfLineLiteral->operands))[0]; if ((SQABS(constant5)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant5 >= 0) { return 0; } else { return 0; } } else { return 1; } default: assert(0); } return 0; } /* CogSimStackEntry>>#ensureSpilledAt:from: */ static SimStackEntry * NoDbgRegParms ensureSpilledAtfrom(SimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *inst; sqInt literal; sqInt reg; sqInt wordConstant; if ((self_in_ensureSpilledAtfrom->spilled)) { if (((self_in_ensureSpilledAtfrom->type)) == SSSpill) { assert(((((self_in_ensureSpilledAtfrom->offset)) == baseOffset) && (((self_in_ensureSpilledAtfrom->registerr)) == baseRegister)) || (violatesEnsureSpilledSpillAssert())); return self_in_ensureSpilledAtfrom; } } assert(((self_in_ensureSpilledAtfrom->type)) != SSSpill); traceSpill(self_in_ensureSpilledAtfrom); if (((self_in_ensureSpilledAtfrom->type)) == SSConstant) { if (shouldAnnotateObjectReference((self_in_ensureSpilledAtfrom->constant))) { inst = annotateobjRef(gPushCw((self_in_ensureSpilledAtfrom->constant)), (self_in_ensureSpilledAtfrom->constant)); } else { /* begin PushCq: */ wordConstant = (self_in_ensureSpilledAtfrom->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperand(PushCq, wordConstant); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(wordConstant)); } inst = anInstruction; } } else { if (((self_in_ensureSpilledAtfrom->type)) == SSBaseOffset) { /* begin checkQuickConstant:forInstruction: */ literal = (self_in_ensureSpilledAtfrom->offset); anInstruction1 = genoperandoperandoperand(MoveMwrR, (self_in_ensureSpilledAtfrom->offset), (self_in_ensureSpilledAtfrom->registerr), TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(literal)); } /* begin PushR: */ inst = genoperand(PushR, TempReg); } else { assert(((self_in_ensureSpilledAtfrom->type)) == SSRegister); /* begin PushR: */ reg = (self_in_ensureSpilledAtfrom->registerr); inst = genoperand(PushR, reg); } (self_in_ensureSpilledAtfrom->type) = SSSpill; (self_in_ensureSpilledAtfrom->offset) = baseOffset; (self_in_ensureSpilledAtfrom->registerr) = baseRegister; } (self_in_ensureSpilledAtfrom->spilled) = 1; return self_in_ensureSpilledAtfrom; } /* CogSimStackEntry>>#isSameEntryAs: */ static sqInt NoDbgRegParms isSameEntryAs(SimStackEntry * self_in_isSameEntryAs, CogSimStackEntry *ssEntry) { return (((self_in_isSameEntryAs->type)) == ((ssEntry->type))) && ((((((self_in_isSameEntryAs->type)) == SSBaseOffset) || (((self_in_isSameEntryAs->type)) == SSSpill)) && ((((self_in_isSameEntryAs->offset)) == ((ssEntry->offset))) && (((self_in_isSameEntryAs->registerr)) == ((ssEntry->registerr))))) || (((((self_in_isSameEntryAs->type)) == SSRegister) && (((self_in_isSameEntryAs->registerr)) == ((ssEntry->registerr)))) || ((((self_in_isSameEntryAs->type)) == SSConstant) && (((self_in_isSameEntryAs->constant)) == ((ssEntry->constant)))))); } /* CogSimStackEntry>>#popToReg: */ static SimStackEntry * NoDbgRegParms popToReg(SimStackEntry * self_in_popToReg, sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt literal; sqInt quickConstant; sqInt reg1; if ((self_in_popToReg->spilled)) { /* begin PopR: */ genoperand(PopR, reg); } else { switch ((self_in_popToReg->type)) { case SSBaseOffset: /* begin checkQuickConstant:forInstruction: */ literal = (self_in_popToReg->offset); anInstruction = genoperandoperandoperand(MoveMwrR, (self_in_popToReg->offset), (self_in_popToReg->registerr), reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } break; case SSConstant: if (shouldAnnotateObjectReference((self_in_popToReg->constant))) { annotateobjRef(gMoveCwR((self_in_popToReg->constant), reg), (self_in_popToReg->constant)); } else { /* begin MoveCq:R: */ quickConstant = (self_in_popToReg->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } } break; case SSRegister: if (reg != ((self_in_popToReg->registerr))) { /* begin MoveR:R: */ reg1 = (self_in_popToReg->registerr); genoperandoperand(MoveRR, reg1, reg); } else { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } break; default: error("Case not found and no otherwise clause"); } } return self_in_popToReg; } /* Answer a bit mask for the receiver's register, if any. */ /* CogSimStackEntry>>#registerMask */ static sqInt NoDbgRegParms registerMask(SimStackEntry * self_in_registerMask) { sqInt reg; return ((((self_in_registerMask->type)) == SSBaseOffset) || (((self_in_registerMask->type)) == SSRegister) ? (/* begin registerMaskFor: */ (reg = (self_in_registerMask->registerr)), 1U << reg) : 0); } /* CogSimStackEntry>>#registerMaskOrNone */ static sqInt NoDbgRegParms registerMaskOrNone(SimStackEntry * self_in_registerMaskOrNone) { sqInt reg; return (((self_in_registerMaskOrNone->type)) == SSRegister ? (/* begin registerMaskFor: */ (reg = (self_in_registerMaskOrNone->registerr)), 1U << reg) : 0); } /* CogSimStackEntry>>#registerOrNone */ static sqInt NoDbgRegParms registerOrNone(SimStackEntry * self_in_registerOrNone) { return (((self_in_registerOrNone->type)) == SSRegister ? (self_in_registerOrNone->registerr) : NoReg); } /* CogSimStackEntry>>#storeToReg: */ static SimStackEntry * NoDbgRegParms storeToReg(SimStackEntry * self_in_storeToReg, sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt literal; sqInt quickConstant; sqInt reg1; switch ((self_in_storeToReg->type)) { case SSBaseOffset: case SSSpill: /* begin checkQuickConstant:forInstruction: */ literal = (self_in_storeToReg->offset); anInstruction = genoperandoperandoperand(MoveMwrR, (self_in_storeToReg->offset), (self_in_storeToReg->registerr), reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } break; case SSConstant: if (shouldAnnotateObjectReference((self_in_storeToReg->constant))) { annotateobjRef(gMoveCwR((self_in_storeToReg->constant), reg), (self_in_storeToReg->constant)); } else { /* begin MoveCq:R: */ quickConstant = (self_in_storeToReg->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } } break; case SSRegister: if (reg != ((self_in_storeToReg->registerr))) { /* begin MoveR:R: */ reg1 = (self_in_storeToReg->registerr); genoperandoperand(MoveRR, reg1, reg); } else { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } break; default: error("Case not found and no otherwise clause"); } return self_in_storeToReg; } /* CogSSBytecodeFixup>>#isMergeFixup */ static sqInt NoDbgRegParms isMergeFixup(BytecodeFixup * self_in_isMergeFixup) { return (((usqInt)((self_in_isMergeFixup->targetInstruction)))) == NeedsMergeFixupFlag; } /* Allocate an unsharable Literal instruction for the literal and answer it. */ /* OutOfLineLiteralsManager>>#allocateLiteral: */ static AbstractInstruction * NoDbgRegParms allocateLiteral(sqInt aLiteral) { AbstractInstruction *existingInst; sqInt i; sqInt iLimiT; sqInt initialNumLiterals; AbstractInstruction *litInst; AbstractInstruction *newInst; AbstractInstruction *newLiterals; if (nextLiteralIndex >= literalsSize) { /* begin allocateLiterals: */ initialNumLiterals = literalsSize + 8; if (initialNumLiterals > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(initialNumLiterals, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i = 0; i < nextLiteralIndex; i += 1) { existingInst = literalInstructionAt(i); newInst = (&(newLiterals[i])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i = 0, iLimiT = (opcodeIndex - 1); i <= iLimiT; i += 1) { existingInst = abstractInstructionAt(i); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = initialNumLiterals; } } litInst = literalInstructionAt(nextLiteralIndex); initializeUniqueLiteral(litInst, aLiteral); /* Record the opcodeIndex of the first dependent instruction (the first instruction that references an out-of-line literal) */ nextLiteralIndex += 1; if (firstOpcodeIndex > opcodeIndex) { firstOpcodeIndex = opcodeIndex - 1; } return litInst; } /* OutOfLineLiteralsManager>>#checkLiteral:forInstruction: */ static AbstractInstruction * NoDbgRegParms checkLiteralforInstruction(sqInt literal, AbstractInstruction *anInstruction) { if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } return anInstruction; } /* OutOfLineLiteralsManager>>#checkQuickConstant:forInstruction: */ static AbstractInstruction * NoDbgRegParms checkQuickConstantforInstruction(sqInt literal, AbstractInstruction *anInstruction) { if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } return anInstruction; } /* Output all pending literal instructions, making the originals dependents of the generated ones so that a later pass will copy the address of each generated literl inst to its original in literals, and hence allow the instruction using the literal to compute the correct address.. */ /* OutOfLineLiteralsManager>>#dumpLiterals: */ static sqInt NoDbgRegParms dumpLiterals(sqInt generateBranchAround) { sqInt i; sqInt index; AbstractInstruction *jump; AbstractInstruction *litInst; jump = ((AbstractInstruction *) 0); if (generateBranchAround) { /* begin Jump: */ jump = genoperand(Jump, ((sqInt)0)); } for (i = lastDumpedLiteralIndex; i < nextLiteralIndex; i += 1) { litInst = literalInstructionAt(i); ((genoperand(Literal, ((litInst->operands))[0]))->dependent = litInst); /* begin setLiteralOpcodeIndex: */ index = opcodeIndex; assert(((litInst->opcode)) == Literal); ((litInst->operands))[2] = index; } if (generateBranchAround) { jmpTarget(jump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin getOpcodeIndex */ firstOpcodeIndex = opcodeIndex; lastDumpedLiteralIndex = nextLiteralIndex; return 0; } /* return the offset need from the cPICEndSize in order to point to just after the last instruction - here that means bytesPerOop * list size */ /* OutOfLineLiteralsManager>>#endSizeOffset */ static sqInt endSizeOffset(void) { return nextLiteralIndex * BytesPerOop; } /* A literal is in range if its opcode index is within outOfLineLiteralOpcodeLimit, or if its index has yet to be assigned. */ /* OutOfLineLiteralsManager>>#literalInstructionInRange: */ static sqInt NoDbgRegParms literalInstructionInRange(AbstractInstruction *litInst) { sqInt opcodeIdx; /* begin literalOpcodeIndex */ assert(((litInst->opcode)) == Literal); opcodeIdx = ((sqInt)(((litInst->operands))[2])); return ((((sqInt)opcodeIdx)) < 0) || ((assert((getOpcodeIndex()) >= opcodeIdx), (opcodeIndex - opcodeIdx) < (outOfLineLiteralOpcodeLimit(backEnd())))); } /* Search for a Literal instruction that is in-range and answer it. Otherwise allocate a new sharable Literal instruction for the literal and answer it. */ /* OutOfLineLiteralsManager>>#locateLiteral: */ static AbstractInstruction * NoDbgRegParms locateLiteral(sqInt aLiteral) { AbstractInstruction *existingInst; sqInt i; sqInt i1; sqInt iLimiT; sqInt initialNumLiterals; AbstractInstruction *litInst; AbstractInstruction *newInst; AbstractInstruction *newLiterals; for (i = 0; i < nextLiteralIndex; i += 1) { litInst = literalInstructionAt(i); if (((((litInst->operands))[0]) == aLiteral) && (((assert(((litInst->opcode)) == Literal), ((litInst->operands))[1])) && (literalInstructionInRange(litInst)))) { return litInst; } } if (nextLiteralIndex >= literalsSize) { /* begin allocateLiterals: */ initialNumLiterals = literalsSize + 8; if (initialNumLiterals > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(initialNumLiterals, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i1 = 0; i1 < nextLiteralIndex; i1 += 1) { existingInst = literalInstructionAt(i1); newInst = (&(newLiterals[i1])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i1 = 0, iLimiT = (opcodeIndex - 1); i1 <= iLimiT; i1 += 1) { existingInst = abstractInstructionAt(i1); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = initialNumLiterals; } } litInst = literalInstructionAt(nextLiteralIndex); initializeSharableLiteral(litInst, aLiteral); /* Record the opcodeIndex of the first dependent instruction (the first instruction that references an out-of-line literal) */ nextLiteralIndex += 1; if (firstOpcodeIndex > opcodeIndex) { firstOpcodeIndex = opcodeIndex - 1; } return litInst; } /* OutOfLineLiteralsManager>>#mustDumpLiterals: */ static sqInt NoDbgRegParms mustDumpLiterals(sqInt currentOpcodeIndex) { return (currentOpcodeIndex >= firstOpcodeIndex) && ((currentOpcodeIndex - firstOpcodeIndex) >= (outOfLineLiteralOpcodeLimit(backEnd()))); } /* Compile the jump instruction(s) at the end of the method that dispatch to each block body. */ /* SimpleStackBasedCogit>>#compileBlockDispatch */ static sqInt compileBlockDispatch(void) { AbstractInstruction *anInstruction; AbstractInstruction *jumpSkip; assert(blockCount > 0); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } blockEntryNoContextSwitch = anInstruction; /* begin Jump: */ jumpSkip = genoperand(Jump, ((sqInt)0)); /* begin MoveR:R: */ blockEntryLabel = genoperandoperand(MoveRR, ReceiverResultReg, SendNumArgsReg); jmpTarget(jumpSkip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (blockCount > 1) { genLoadSlotsourceRegdestReg(ClosureStartPCIndex, ReceiverResultReg, TempReg); } compileBlockDispatchFromto(0, blockCount - 1); return 0; } /* After pushing the temporaries but before the stack limit check a primitive method needs to fetch the error code, if any. If the primitive has failed, call the trampoline that will assign it to the last temp. */ /* SimpleStackBasedCogit>>#compileGetErrorCode */ static void compileGetErrorCode(void) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *jmpNoError; /* begin MoveAw:R: */ address = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmpNoError = genConditionalBranchoperand(JumpZero, ((sqInt)0)); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), ClassReg))); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceReapAndResetErrorCodeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(jmpNoError, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* SimpleStackBasedCogit>>#compileInterpreterPrimitive */ static sqInt compileInterpreterPrimitive(void) { void (*primitiveRoutine)(); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); return compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)); } /* Compile a call to an interpreter primitive. Call the C routine with the usual stack-switching dance, test the primFailCode and then either return on success or continue to the method body. */ /* SimpleStackBasedCogit>>#compileInterpreterPrimitive:flags: */ static sqInt NoDbgRegParms compileInterpreterPrimitiveflags(void (*primitiveRoutine)(void), sqInt flags) { sqInt address; sqInt address1; sqInt address10; sqInt address11; sqInt address12; sqInt address13; sqInt address3; sqInt address4; sqInt address5; sqInt address6; sqInt address8; sqInt address9; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *continuePostSampleNonPrim; AbstractInstruction *continuePostSamplePrim; AbstractInstruction *jmp; AbstractInstruction *jmpSampleNonPrim; AbstractInstruction *jmpSamplePrim; sqInt offset; sqInt offset1; sqInt offset2; sqInt operand1; sqInt operand3; sqInt reg; sqInt retpc; /* Save processor fp, sp and return pc in the interpreter's frame stack and instruction pointers */ continuePostSampleNonPrim = ((AbstractInstruction *) 0); continuePostSamplePrim = ((AbstractInstruction *) 0); jmpSampleNonPrim = ((AbstractInstruction *) 0); jmpSamplePrim = ((AbstractInstruction *) 0); genExternalizePointersForPrimitiveCall(); genLoadCStackPointersForPrimCall(); if (flags & PrimCallCollectsProfileSamples) { /* Test nextProfileTick for being non-zero and call checkProfileTick if so */ /* begin MoveAw:R: */ address = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin MoveAw:R: */ address1 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSampleNonPrim = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSampleNonPrim = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } if (recordPrimTrace()) { genFastPrimTraceUsingand(ClassReg, SendNumArgsReg); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(0)); } /* begin MoveR:Aw: */ address11 = primFailCodeAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address11, genoperandoperand(MoveRAw, TempReg, address11)); if (methodOrBlockNumArgs != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, methodOrBlockNumArgs, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(methodOrBlockNumArgs)); } } /* begin MoveR:Aw: */ address12 = argumentCountAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address12, genoperandoperand(MoveRAw, TempReg, address12)); if (flags & PrimCallNeedsPrimitiveFunction) { /* begin MoveCw:R: */ checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperandoperand(MoveCwR, ((sqInt)primitiveRoutine), TempReg)); /* begin MoveR:Aw: */ address3 = primitiveFunctionPointerAddress(); /* begin gen:operand:literal: */ primSetFunctionLabel = checkLiteralforInstruction(address3, genoperandoperand(MoveRAw, TempReg, address3)); } if (flags & (PrimCallNeedsNewMethod + PrimCallMayCallBack)) { /* The ceActivateFailingPrimitiveMethod: machinery can't handle framelessness. */ if (flags & PrimCallMayCallBack) { needsFrame = 1; } addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), ClassReg))); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodObject); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset)); } /* begin MoveR:Aw: */ address4 = newMethodAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address4, genoperandoperand(MoveRAw, TempReg, address4)); } /* begin PrefetchAw: */ address13 = primFailCodeAddress(); /* begin gen:literal: */ checkLiteralforInstruction(address13, genoperand(PrefetchAw, address13)); if (flags & PrimCallMayCallBack) { /* Sideways call the C primitive routine so that we return through cePrimReturnEnterCogCode. */ /* On Spur ceActivateFailingPrimitiveMethod: would like to retry if forwarders are found. So insist on PrimCallNeedsPrimitiveFunction being set too. */ assert(flags & PrimCallNeedsPrimitiveFunction); /* begin genMarshallNArgs:arg:arg:arg:arg: */ ((AbstractInstruction *) backEnd); goto l33; genoperandoperand(MoveRR, 0, CArg0Reg); genoperandoperand(MoveRR, 0, CArg1Reg); genoperandoperand(MoveRR, 0, CArg2Reg); genoperandoperand(MoveRR, 0, CArg3Reg); ((AbstractInstruction *) backEnd); l33: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin genSubstituteReturnAddress: */ retpc = (flags & PrimCallCollectsProfileSamples ? cePrimReturnEnterCogCodeProfiling : cePrimReturnEnterCogCode); /* begin gen:literal:operand: */ checkLiteralforInstruction(retpc, genoperandoperand(MoveCwR, retpc, LR)); /* begin gen:literal: */ primInvokeInstruction = checkLiteralforInstruction(((sqInt)(((sqInt)primitiveRoutine))), genoperand(JumpFull, ((sqInt)(((sqInt)primitiveRoutine))))); jmp = (jmpSamplePrim = (continuePostSamplePrim = null)); } else { /* Call the C primitive routine. */ /* begin genMarshallNArgs:arg:arg:arg:arg: */ ((AbstractInstruction *) backEnd); goto l38; genoperandoperand(MoveRR, 0, CArg0Reg); genoperandoperand(MoveRR, 0, CArg1Reg); genoperandoperand(MoveRR, 0, CArg2Reg); genoperandoperand(MoveRR, 0, CArg3Reg); ((AbstractInstruction *) backEnd); l38: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ primInvokeInstruction = checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperand(CallFull, ((sqInt)primitiveRoutine))); /* begin genRemoveNArgsFromStack: */ assert(0 <= 4); if (flags & PrimCallCollectsProfileSamples) { assert(flags & PrimCallNeedsNewMethod); /* begin MoveAw:R: */ address5 = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address5, genoperandoperand(MoveAwR, address5, TempReg)); /* begin MoveAw:R: */ address6 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address6, genoperandoperand(MoveAwR, address6, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSamplePrim = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSamplePrim = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } maybeCompileRetryOnPrimitiveFail(primitiveIndex); maybeCompileAllocFillerCheck(); /* begin MoveAw:R: */ address8 = instructionPointerAddress(); reg = LinkReg; /* begin gen:literal:operand: */ checkLiteralforInstruction(address8, genoperandoperand(MoveAwR, address8, reg)); genLoadStackPointers(backEnd); /* begin MoveAw:R: */ address9 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address9, genoperandoperand(MoveAwR, address9, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset1 = 0; /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveMwrR, offset1, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(offset1)); } /* begin RetN: */ genoperand(RetN, BytesPerWord); } if (flags & PrimCallCollectsProfileSamples) { /* The sample is collected by cePrimReturnEnterCogCode for external calls */ if (!(jmpSamplePrim == null)) { /* Call ceCheckProfileTick: to record sample and then continue. */ jmpTarget(jmpSamplePrim, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); assert(flags & PrimCallNeedsNewMethod); /* begin gen:literal: */ operand1 = ((usqIntptr_t)ceCheckProfileTick); checkLiteralforInstruction(operand1, genoperand(CallFull, operand1)); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSamplePrim)); } jmpTarget(jmpSampleNonPrim, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(0)); } /* begin MoveR:Aw: */ address10 = newMethodAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address10, genoperandoperand(MoveRAw, TempReg, address10)); /* begin gen:literal: */ operand3 = ((usqIntptr_t)ceCheckProfileTick); checkLiteralforInstruction(operand3, genoperand(CallFull, operand3)); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSampleNonPrim)); } if (!(jmp == null)) { /* Jump to restore of receiver reg and proceed to frame build for failure. */ jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin MoveMw:r:R: */ offset2 = BytesPerWord * (methodOrBlockNumArgs + (0)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveMwrR, offset2, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(offset2)); } } return 0; } /* Compile a call to a machine-code convention interpreter primitive. Call the C routine on the Smalltalk stack, assuming it consumes little or no stack space. */ /* for now handle functions with less than 4 arguments; our C call marshalling machinery extends up to 4 arguments only, and the first argument of an mcprim is the receiver. */ /* SimpleStackBasedCogit>>#compileMachineCodeInterpreterPrimitive: */ static sqInt NoDbgRegParms compileMachineCodeInterpreterPrimitive(void (*primitiveRoutine)(void)) { AbstractInstruction *anInstruction; AbstractInstruction * jmpFail; sqInt liveRegsMask; sqInt n; sqInt offset; sqInt reg1; assert(methodOrBlockNumArgs <= 3); if ((methodOrBlockNumArgs > 2 /* numRegArgs */) || (methodOrBlockNumArgs == 0)) { /* begin registerMaskFor: */ liveRegsMask = 1U << ReceiverResultReg; } else { if (methodOrBlockNumArgs > 1) { /* begin registerMaskFor:and:and: */ liveRegsMask = ((1U << ReceiverResultReg) | (1U << Arg0Reg)) | (1U << Arg1Reg); } else { /* begin registerMaskFor:and: */ liveRegsMask = (1U << ReceiverResultReg) | (1U << Arg0Reg); } } /* begin genSaveRegs: */ if ((liveRegsMask & CallerSavedRegisterMask) == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, liveRegsMask & CallerSavedRegisterMask); } if (methodOrBlockNumArgs > 2 /* numRegArgs */) { /* Wrangle args into Arg0Reg, Arg1Reg, SendNumArgsReg & ClassReg */ /* offset := self bitCountOf: (liveRegsMask bitAnd: CallerSavedRegisterMask). */ error("shouldBeImplemented"); } /* begin genMarshallNArgs:arg:arg:arg:arg: */ if ((methodOrBlockNumArgs + 1) == 0) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, ReceiverResultReg, CArg0Reg); if ((methodOrBlockNumArgs + 1) == 1) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, Arg0Reg, CArg1Reg); if ((methodOrBlockNumArgs + 1) == 2) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, Arg1Reg, CArg2Reg); if ((methodOrBlockNumArgs + 1) == 3) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, SendNumArgsReg, CArg3Reg); ((AbstractInstruction *) backEnd); l12: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperand(CallFull, ((sqInt)primitiveRoutine))); /* begin genRemoveNArgsFromStack: */ n = methodOrBlockNumArgs + 1; assert(n <= 4); /* begin genRestoreRegs: */ if ((liveRegsMask & CallerSavedRegisterMask) == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PopLDM, liveRegsMask & CallerSavedRegisterMask); } /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, 0, R0); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmpFail = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ reg1 = R0; genoperandoperand(MoveRR, reg1, ReceiverResultReg); /* begin RetN: */ offset = (methodOrBlockNumArgs > 2 /* numRegArgs */ ? (methodOrBlockNumArgs + 1) * BytesPerWord : 0); genoperand(RetN, offset); jmpTarget(jmpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Compile one method cache probe in an OpenPIC's lookup of selector. Answer the jump taken if the selector probe fails. The class tag of the receiver must be in SendNumArgsReg. ClassReg and TempReg are used as scratch registers. On a hit, the offset of the entry is in ClassReg. */ /* SimpleStackBasedCogit>>#compileOpenPICMethodCacheProbeFor:withShift:baseRegOrNone: */ static AbstractInstruction * NoDbgRegParms compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selector, sqInt shift, sqInt baseRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpSelectorMiss; sqInt offset; sqInt offset1; /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ClassReg); maybeShiftClassTagRegisterForMethodCacheProbe(ClassReg); annotateobjRef(gXorCwR(selector, ClassReg), selector); assert(shift <= (shiftForWord())); if (shift < (shiftForWord())) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - shift, ClassReg); } /* begin AndCq:R: */ anInstruction4 = genoperandoperand(AndCqR, ((int)((usqInt)(MethodCacheMask) << (shiftForWord()))), ClassReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(((int)((usqInt)(MethodCacheMask) << (shiftForWord()))))); } if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheSelector) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } else { /* begin AddR:R: */ genoperandoperand(AddRR, baseRegOrNone, ClassReg); /* begin MoveMw:r:R: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))))); } } annotateobjRef(checkLiteralforInstruction(selector, genoperandoperand(CmpCwR, selector, TempReg)), selector); /* begin JumpNonZero: */ jumpSelectorMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset1 = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheClass) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset1, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset1)); } } else { /* begin MoveMw:r:R: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheClass) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(((int)((usqInt)(MethodCacheClass) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, SendNumArgsReg, TempReg); return jumpSelectorMiss; } /* Compile the code for an open PIC. Perform a probe of the first-level method lookup cache followed by a call of ceSendFromInLineCacheMiss: if the probe fails. */ /* SimpleStackBasedCogit>>#compileOpenPIC:numArgs: */ static void NoDbgRegParms compileOpenPICnumArgs(sqInt selector, sqInt numArgs) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt cacheBaseReg; AbstractInstruction *itsAHit; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpClassMiss; AbstractInstruction *jumpSelectorMiss; sqInt offset; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compilePICAbort(numArgs); entry = genGetClassTagOfintoscratchReg(ReceiverResultReg, SendNumArgsReg, TempReg); flag("lookupInMethodCacheSel:classTag:"); cacheBaseReg = NoReg; jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 0, cacheBaseReg); /* begin JumpNonZero: */ jumpClassMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset = (cacheBaseReg == NoReg ? (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))) : ((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } itsAHit = anInstruction1; genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); jmpTarget(jumpBCMethod, picInterpretAbort); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, cmNoCheckEntryOffset, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(cmNoCheckEntryOffset)); } /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpSelectorMiss, jmpTarget(jumpClassMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 1, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 2, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); genSmalltalkToCStackSwitch(1); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), SendNumArgsReg))); compileCallFornumArgsargargargargresultRegregsToSave(ceSendFromInLineCacheMiss, 1, SendNumArgsReg, null, null, null, NoReg, 0 /* emptyRegisterMask */); } /* Compile one method cache probe in a perform: primitive's lookup of selector. Answer the jump taken if the selector probe fails. */ /* SimpleStackBasedCogit>>#compilePerformMethodCacheProbeFor:withShift:baseRegOrNone: */ static AbstractInstruction * NoDbgRegParms compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selectorReg, sqInt shift, sqInt baseRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpSelectorMiss; sqInt offset; sqInt offset1; /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ClassReg); maybeShiftClassTagRegisterForMethodCacheProbe(ClassReg); /* begin XorR:R: */ genoperandoperand(XorRR, selectorReg, ClassReg); assert(shift <= (shiftForWord())); if (shift < (shiftForWord())) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - shift, ClassReg); } /* begin AndCq:R: */ anInstruction4 = genoperandoperand(AndCqR, ((int)((usqInt)(MethodCacheMask) << (shiftForWord()))), ClassReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(((int)((usqInt)(MethodCacheMask) << (shiftForWord()))))); } if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheSelector) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } else { /* begin AddR:R: */ genoperandoperand(AddRR, baseRegOrNone, ClassReg); /* begin MoveMw:r:R: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, selectorReg, TempReg); /* begin JumpNonZero: */ jumpSelectorMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset1 = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheClass) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset1, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset1)); } } else { /* begin MoveMw:r:R: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheClass) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(((int)((usqInt)(MethodCacheClass) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, SendNumArgsReg, TempReg); return jumpSelectorMiss; } /* Compile a primitive. If possible, performance-critical primtiives will be generated by their own routines (primitiveGenerator). Otherwise, if there is a primitive at all, we call the C routine with the usual stack-switching dance, test the primFailCode and then either return on success or continue to the method body. */ /* SimpleStackBasedCogit>>#compilePrimitive */ static sqInt compilePrimitive(void) { sqInt code; sqInt flags; sqInt opcodeIndexAtPrimitive; PrimitiveDescriptor *primitiveDescriptor; void (*primitiveRoutine)(void); if (primitiveIndex == 0) { return 0; } /* Note opcodeIndex so that compileFallbackToInterpreterPrimitive: can discard arg load instructions for unimplemented primitives. */ code = 0; /* If a descriptor specifies an argument count (by numArgs >= 0) then it must match for the generated code to be correct. For example for speed many primitives use ResultReceiverReg instead of accessing the stack, so the receiver better be at numArgs down the stack. Use the interpreter version if not. */ opcodeIndexAtPrimitive = opcodeIndex; if ((((primitiveDescriptor = primitiveGeneratorOrNil())) != null) && ((((primitiveDescriptor->primitiveGenerator)) != null) && ((((primitiveDescriptor->primNumArgs)) < 0) || (((primitiveDescriptor->primNumArgs)) == (argumentCountOf(methodObj)))))) { code = ((primitiveDescriptor->primitiveGenerator))(); } if ((code < 0) && (code != UnimplementedPrimitive)) { /* Generator failed, so no point continuing... */ return code; } if (code == UnfailingPrimitive) { return 0; } if ((code == CompletePrimitive) && (!(((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))))) { return 0; } if (code == UnimplementedPrimitive) { opcodeIndex = opcodeIndexAtPrimitive; } flags = primitivePropertyFlags(primitiveIndex); if (flags & PrimCallDoNotJIT) { return ShouldNotJIT; } if (flags & PrimCallOnSmalltalkStack) { assert(flags == PrimCallOnSmalltalkStack); return compileMachineCodeInterpreterPrimitive(mcprimFunctionForPrimitiveIndex(primitiveIndex)); } if ((((primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex))) == 0) || (primitiveRoutine == primitiveFail)) { return genFastPrimFail(); } minValidCallAddress = ((minValidCallAddress < (((usqInt)primitiveRoutine))) ? minValidCallAddress : (((usqInt)primitiveRoutine))); return compileInterpreterPrimitiveflags(primitiveRoutine, flags); } /* SimpleStackBasedCogit>>#extendedPushBytecode */ static sqInt extendedPushBytecode(void) { sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genPushReceiverVariable(variableIndex); } if (variableType == 1) { return genPushTemporaryVariable(variableIndex); } if (variableType == 2) { return genPushLiteralIndex(variableIndex); } return genPushLiteralVariable(variableIndex); } /* SimpleStackBasedCogit>>#extendedStoreAndPopBytecode */ static sqInt extendedStoreAndPopBytecode(void) { AbstractInstruction *abstractInstruction; sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } if (variableType == 1) { genStorePopTemporaryVariable(1, variableIndex); # if IMMUTABILITY /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); # endif /* IMMUTABILITY */ return 0; } if (variableType == 3) { return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(1, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#extendedStoreBytecode */ static sqInt extendedStoreBytecode(void) { AbstractInstruction *abstractInstruction; sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } if (variableType == 1) { genStorePopTemporaryVariable(0, variableIndex); # if IMMUTABILITY /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); # endif /* IMMUTABILITY */ return 0; } if (variableType == 3) { return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#frameOffsetOfTemporary: */ static sqInt NoDbgRegParms frameOffsetOfTemporary(sqInt index) { return (index < methodOrBlockNumArgs ? FoxCallerSavedIP + ((methodOrBlockNumArgs - index) * BytesPerWord) : (FoxMFReceiver - BytesPerWord) + ((methodOrBlockNumArgs - index) * BytesPerWord)); } /* Implemented with SistaCogit only */ /* SimpleStackBasedCogit>>#genCallMappedInlinedPrimitive */ static sqInt genCallMappedInlinedPrimitive(void) { return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#genDoubleFailIfZeroArgRcvr:arg: */ static AbstractInstruction * NoDbgRegParms genDoubleFailIfZeroArgRcvrarg(int rcvrReg, int argReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, TempReg, DPFPReg2); /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg2, argReg); return gJumpFPEqual(0); } /* Can use any of the first 32 literals for the selector and pass up to 7 arguments. */ /* SimpleStackBasedCogit>>#genExtendedSendBytecode */ static sqInt genExtendedSendBytecode(void) { return genSendnumArgs(byte1 & 0x1F, ((usqInt) byte1) >> 5); } /* SimpleStackBasedCogit>>#genExtendedSuperBytecode */ static sqInt genExtendedSuperBytecode(void) { return genSendSupernumArgs(byte1 & 0x1F, ((usqInt) byte1) >> 5); } /* 244 11110100 i i i i i i i i Pop and Jump 0n False i i i i i i i i (+ Extend B * 256, where Extend B >= 0) */ /* SimpleStackBasedCogit>>#genExtJumpIfFalse */ static sqInt genExtJumpIfFalse(void) { sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongForwardBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; return genJumpIfto(falseObject(), target); } /* 243 11110011 i i i i i i i i Pop and Jump 0n True i i i i i i i i (+ Extend B * 256, where Extend B >= 0) */ /* SimpleStackBasedCogit>>#genExtJumpIfTrue */ static sqInt genExtJumpIfTrue(void) { sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongForwardBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; return genJumpIfto(trueObject(), target); } /* NewspeakV4: 221 11011101 Nop */ /* SistaV1: 91 01011011' Nop */ /* SimpleStackBasedCogit>>#genExtNopBytecode */ static sqInt genExtNopBytecode(void) { extA = (numExtB = (extB = 0)); return 0; } /* SistaV1: 233 11101001 iiiiiiii Push Character #iiiiiiii (+ Extend B * 256) */ /* SimpleStackBasedCogit>>#genExtPushCharacterBytecode */ static sqInt genExtPushCharacterBytecode(void) { sqInt value; value = byte1 + (((sqInt)((usqInt)(extB) << 8))); extB = 0; numExtB = 0; return genPushLiteral(characterObjectOf(value)); } /* NewsqueakV4: 229 11100101 iiiiiiii Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) SistaV1: 232 11101000 iiiiiiii Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#genExtPushIntegerBytecode */ static sqInt genExtPushIntegerBytecode(void) { sqInt value; value = byte1 + (((sqInt)((usqInt)(extB) << 8))); extB = 0; numExtB = 0; return genPushLiteral((((usqInt)value << 1) | 1)); } /* 228 11100100 i i i i i i i i Push Literal #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushLiteralBytecode */ static sqInt genExtPushLiteralBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genPushLiteralIndex(index); } /* 227 11100011 i i i i i i i i Push Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushLiteralVariableBytecode */ static sqInt genExtPushLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genPushLiteralVariable(index); } /* SistaV1: * 82 01010010 Push thisContext, (then Extend B = 1 => push thisProcess) */ /* SimpleStackBasedCogit>>#genExtPushPseudoVariable */ static sqInt genExtPushPseudoVariable(void) { sqInt ext; ext = extB; extB = 0; numExtB = 0; switch (ext) { case 0: return genPushActiveContextBytecode(); default: /* begin unknownBytecode */ return EncounteredUnknownBytecode; } return 0; } /* 226 11100010 i i i i i i i i Push Receiver Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushReceiverVariableBytecode */ static sqInt genExtPushReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isReadMediatedContextInstVarIndex(index) ? genPushMaybeContextReceiverVariable(index) : genPushReceiverVariable(index)); } /* 238 11101110 i i i i i j j j Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments */ /* SimpleStackBasedCogit>>#genExtSendBytecode */ static sqInt genExtSendBytecode(void) { sqInt litIndex; sqInt nArgs; litIndex = (((usqInt) byte1) >> 3) + (((sqInt)((usqInt)(extA) << 5))); extA = 0; nArgs = (byte1 & 7) + (((sqInt)((usqInt)(extB) << 3))); extB = 0; numExtB = 0; return genSendnumArgs(litIndex, nArgs); } /* 239 11101111 i i i i i j j j Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments */ /* SimpleStackBasedCogit>>#genExtSendSuperBytecode */ static sqInt genExtSendSuperBytecode(void) { int isDirected; sqInt litIndex; sqInt nArgs; if ((isDirected = extB >= 64)) { extB = extB & 0x3F; } litIndex = (((usqInt) byte1) >> 3) + (((sqInt)((usqInt)(extA) << 5))); extA = 0; nArgs = (byte1 & 7) + (((sqInt)((usqInt)(extB) << 3))); extB = 0; numExtB = 0; return (isDirected ? genSendDirectedSupernumArgs(litIndex, nArgs) : genSendSupernumArgs(litIndex, nArgs)); } /* 236 11101100 i i i i i i i i Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreAndPopLiteralVariableBytecode */ static sqInt genExtStoreAndPopLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* 235 11101011 i i i i i i i i Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreAndPopReceiverVariableBytecode */ static sqInt genExtStoreAndPopReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isWriteMediatedContextInstVarIndex(index) ? genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1) : genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1)); } /* 233 11101001 i i i i i i i i Store Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreLiteralVariableBytecode */ static sqInt genExtStoreLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* 232 11101000 i i i i i i i i Store Receiver Variable #iiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreReceiverVariableBytecode */ static sqInt genExtStoreReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isWriteMediatedContextInstVarIndex(index) ? genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1) : genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1)); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#genExtUnconditionalJump */ static sqInt genExtUnconditionalJump(void) { AbstractInstruction *abstractInstruction; sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; if (distance < 0) { return genJumpBackTo(target); } genJumpTo(target); /* begin annotateBytecode: */ abstractInstruction = lastOpcode(); (abstractInstruction->annotation = HasBytecodePC); return 0; } /* SimpleStackBasedCogit>>#genFastPrimFail */ static sqInt genFastPrimFail(void) { primitiveIndex = 0; return UnfailingPrimitive; } /* Suport for compileInterpreterPrimitive. Generate inline code so as to record the primitive trace as fast as possible. */ /* SimpleStackBasedCogit>>#genFastPrimTraceUsing:and: */ static void NoDbgRegParms genFastPrimTraceUsingand(sqInt r1, sqInt r2) { sqInt address; sqInt address1; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt offset; sqInt wordConstant; /* begin MoveAb:R: */ address = primTraceLogIndexAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAbR, address, r2)); /* begin MoveR:R: */ genoperandoperand(MoveRR, r2, r1); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, 1, r1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } /* begin MoveR:Ab: */ address1 = primTraceLogIndexAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAb, r1, address1)); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), r1))); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, selector); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset, r1, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset)); } /* begin MoveCw:R: */ wordConstant = ((sqInt)(primTraceLogAddress())); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, r1)); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, r2, r1); } /* SimpleStackBasedCogit>>#genLongJumpIfFalse */ static sqInt genLongJumpIfFalse(void) { sqInt distance; sqInt target; distance = v3LongForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 2) + bytecodePC; return genJumpIfto(falseObject(), target); } /* SimpleStackBasedCogit>>#genLongJumpIfTrue */ static sqInt genLongJumpIfTrue(void) { sqInt distance; sqInt target; distance = v3LongForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 2) + bytecodePC; return genJumpIfto(trueObject(), target); } /* 230 11100110 i i i i i i i i Push Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongPushTemporaryVariableBytecode */ static sqInt genLongPushTemporaryVariableBytecode(void) { return genPushTemporaryVariable(byte1); } /* 237 11101101 i i i i i i i i Pop and Store Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongStoreAndPopTemporaryVariableBytecode */ static sqInt genLongStoreAndPopTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(1, byte1); } /* 234 11101010 i i i i i i i i Store Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongStoreTemporaryVariableBytecode */ static sqInt genLongStoreTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(0, byte1); } /* SimpleStackBasedCogit>>#genLongUnconditionalBackwardJump */ static sqInt genLongUnconditionalBackwardJump(void) { sqInt distance; distance = v3LongBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); assert(distance < 0); return genJumpBackTo((distance + 2) + bytecodePC); } /* SimpleStackBasedCogit>>#genLongUnconditionalForwardJump */ static sqInt genLongUnconditionalForwardJump(void) { sqInt distance; sqInt targetpc; distance = v3LongBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); assert(distance >= 0); targetpc = (distance + 2) + bytecodePC; return genJumpTo(targetpc); } /* Compile the code for a probe of the first-level method cache for a perform primtiive. The selector is assumed to be in Arg0Reg. Defer to adjustArgumentsForPerform: to adjust the arguments before the jump to the method. */ /* SimpleStackBasedCogit>>#genLookupForPerformNumArgs: */ static sqInt NoDbgRegParms genLookupForPerformNumArgs(sqInt numArgs) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt cacheBaseReg; AbstractInstruction *itsAHit; AbstractInstruction *jumpClassMiss; AbstractInstruction *jumpInterpret; AbstractInstruction *jumpSelectorMiss; sqInt offset; /* N.B. Can't assume TempReg already contains the tag because a method can of course be invoked via the unchecked entry-point, e.g. as does perform:. */ genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, SendNumArgsReg, 0); flag("lookupInMethodCacheSel:classTag:"); cacheBaseReg = NoReg; jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 0, cacheBaseReg); /* begin JumpNonZero: */ jumpClassMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset = (cacheBaseReg == NoReg ? (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))) : ((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } itsAHit = anInstruction1; genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); /* Adjust arguments and jump to the method's unchecked entry-point. */ jumpInterpret = genJumpImmediate(ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, cmNoCheckEntryOffset, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(cmNoCheckEntryOffset)); } adjustArgumentsForPerform(numArgs); /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpSelectorMiss, jmpTarget(jumpClassMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 1, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 2, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, jmpTarget(jumpInterpret, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* If the objectMemory allows it, generates a quick constant move, else generates a word constant move */ /* SimpleStackBasedCogit>>#genMoveConstant:R: */ static AbstractInstruction * NoDbgRegParms genMoveConstantR(sqInt constant, sqInt reg) { AbstractInstruction *anInstruction; return (shouldAnnotateObjectReference(constant) ? annotateobjRef(gMoveCwR(constant, reg), constant) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction = genoperandoperand(MoveCqR, constant, reg)), (usesOutOfLineLiteral(anInstruction) ? (anInstruction->dependent = locateLiteral(constant)) : 0), anInstruction)); } /* SimpleStackBasedCogit>>#genMustBeBooleanTrampolineFor:called: */ static sqInt NoDbgRegParms genMustBeBooleanTrampolineForcalled(sqInt boolean, char *trampolineName) { AbstractInstruction *anInstruction; zeroOpcodeIndex(); assert(!(shouldAnnotateObjectReference(boolean))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, boolean, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(boolean)); } return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceSendMustBeBoolean, trampolineName, 1, TempReg, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); } /* Implement 28-bit hashMultiply for SmallInteger and LargePositiveInteger receivers. */ /* SimpleStackBasedCogit>>#genPrimitiveHashMultiply */ static sqInt genPrimitiveHashMultiply(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction * jmpFailImm; AbstractInstruction * jmpFailNonImm; AbstractInstruction * jmpNotSmallInt; AbstractInstruction * reenter; jmpNotSmallInt = genJumpNotSmallInteger(ReceiverResultReg); genConvertSmallIntegerToIntegerInReg(ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, HashMultiplyConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(HashMultiplyConstant)); } reenter = anInstruction; /* begin MulR:R: */ genMulRR(backEnd, TempReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, HashMultiplyMask, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(HashMultiplyMask)); } genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jmpNotSmallInt, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jmpFailImm = genJumpImmediate(ReceiverResultReg); genGetCompactClassIndexNonImmOfinto(ReceiverResultReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, ClassLargePositiveIntegerCompactIndex, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(ClassLargePositiveIntegerCompactIndex)); } /* begin JumpNonZero: */ jmpFailNonImm = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, ReceiverResultReg, ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)reenter)); jmpTarget(jmpFailImm, jmpTarget(jmpFailNonImm, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the substitute return code for an external or FFI primitive call. On success simply return, extracting numArgs from newMethod. On primitive failure call ceActivateFailingPrimitiveMethod: newMethod. */ /* SimpleStackBasedCogit>>#genPrimReturnEnterCogCodeEnilopmart: */ static void NoDbgRegParms genPrimReturnEnterCogCodeEnilopmart(sqInt profiling) { sqInt address; sqInt address1; sqInt address3; sqInt address6; sqInt address7; sqInt address8; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction7; sqInt callTarget; AbstractInstruction *continuePostSample; AbstractInstruction * inst; AbstractInstruction *jmpFail; AbstractInstruction *jmpSample; sqInt quickConstant; sqInt reg; continuePostSample = ((AbstractInstruction *) 0); jmpSample = ((AbstractInstruction *) 0); zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } if (profiling) { /* Test nextProfileTick for being non-zero and call checkProfileTick: if so. N.B. nextProfileTick is 64-bits so 32-bit systems need to test both halves. */ /* begin MoveAw:R: */ address = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin MoveAw:R: */ address1 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSample = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSample = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } maybeCompileAllocFillerCheck(); /* begin MoveAw:R: */ address6 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address6, genoperandoperand(MoveAwR, address6, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jmpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadStackPointers(backEnd); /* begin PopR: */ genoperand(PopR, ReceiverResultReg); /* begin MoveAw:R: */ address3 = instructionPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address3, genoperandoperand(MoveAwR, address3, PCReg)); jmpTarget(jmpFail, gMoveAwR(newMethodAddress(), SendNumArgsReg)); /* begin MoveAw:R: */ address7 = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address7, genoperandoperand(MoveAwR, address7, SPReg)); compileCallFornumArgsargargargargresultRegregsToSave(ceActivateFailingPrimitiveMethod, 1, SendNumArgsReg, null, null, null, NoReg, 0 /* emptyRegisterMask */); /* begin MoveAw:R: */ address8 = instructionPointerAddress(); reg = LinkReg; /* begin gen:literal:operand: */ checkLiteralforInstruction(address8, genoperandoperand(MoveAwR, address8, reg)); genLoadStackPointers(backEnd); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveMwrR, 0, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin RetN: */ genoperand(RetN, BytesPerWord); if (profiling) { /* Call ceCheckProfileTick: to record sample and then continue. newMethod should be up-to-date. Need to save and restore the link reg around this call. */ jmpTarget(jmpSample, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallFullRT: */ callTarget = (usqIntptr_t)ceCheckProfileTick; /* begin gen:literal: */ checkLiteralforInstruction(callTarget, genoperand(CallFull, callTarget)); genoperand(PopR, LinkReg); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSample)); } } /* SistaV1: 230 11100110 iiiiiiii PushNClosureTemps iiiiiiii */ /* SimpleStackBasedCogit>>#genPushClosureTempsBytecode */ static sqInt genPushClosureTempsBytecode(void) { sqInt i; for (i = 1; i <= byte1; i += 1) { genPushLiteral(nilObject()); } return 0; } /* SimpleStackBasedCogit>>#genPushConstantFalseBytecode */ static sqInt genPushConstantFalseBytecode(void) { return genPushLiteral(falseObject()); } /* SimpleStackBasedCogit>>#genPushConstantNilBytecode */ static sqInt genPushConstantNilBytecode(void) { return genPushLiteral(nilObject()); } /* 79 01001111 Push 1 */ /* SimpleStackBasedCogit>>#genPushConstantOneBytecode */ static sqInt genPushConstantOneBytecode(void) { return genPushLiteral((((usqInt)1 << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushConstantTrueBytecode */ static sqInt genPushConstantTrueBytecode(void) { return genPushLiteral(trueObject()); } /* 78 01001110 Push 0 */ /* SimpleStackBasedCogit>>#genPushConstantZeroBytecode */ static sqInt genPushConstantZeroBytecode(void) { return genPushLiteral((((usqInt)0 << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushLiteralConstantBytecode */ static sqInt genPushLiteralConstantBytecode(void) { return genPushLiteralIndex(byte0 & 0x1F); } /* 16-31 0001 i i i i Push Literal Variable #iiii */ /* SimpleStackBasedCogit>>#genPushLiteralVariable16CasesBytecode */ static sqInt genPushLiteralVariable16CasesBytecode(void) { return genPushLiteralVariable(byte0 & 15); } /* SimpleStackBasedCogit>>#genPushLiteralVariableBytecode */ static sqInt genPushLiteralVariableBytecode(void) { return genPushLiteralVariable(byte0 & 0x1F); } /* SimpleStackBasedCogit>>#genPushQuickIntegerConstantBytecode */ static sqInt genPushQuickIntegerConstantBytecode(void) { return genPushLiteral((((usqInt)(byte0 - 117) << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushReceiverVariableBytecode */ static sqInt genPushReceiverVariableBytecode(void) { return genPushReceiverVariable(byte0 & 15); } /* SimpleStackBasedCogit>>#genPushTemporaryVariableBytecode */ static sqInt genPushTemporaryVariableBytecode(void) { return genPushTemporaryVariable(byte0 & 15); } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnConst */ sqInt genQuickReturnConst(void) { AbstractInstruction *anInstruction; sqInt constant; constant = quickPrimitiveConstantFor(primitiveIndex); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } genUpArrowReturn(); return UnfailingPrimitive; } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnInstVar */ sqInt genQuickReturnInstVar(void) { sqInt index; index = quickPrimitiveInstVarIndexFor(primitiveIndex); genLoadSlotsourceRegdestReg(index, ReceiverResultReg, ReceiverResultReg); genUpArrowReturn(); return UnfailingPrimitive; } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnSelf */ sqInt genQuickReturnSelf(void) { genUpArrowReturn(); return UnfailingPrimitive; } /* SimpleStackBasedCogit>>#genReturnFalse */ static sqInt genReturnFalse(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveFalseR: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* SimpleStackBasedCogit>>#genReturnNil */ static sqInt genReturnNil(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* SimpleStackBasedCogit>>#genReturnNilFromBlock */ static sqInt genReturnNilFromBlock(void) { AbstractInstruction *anInstruction; sqInt constant; assert(inBlock > 0); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genBlockReturn(); } /* SimpleStackBasedCogit>>#genReturnTrue */ static sqInt genReturnTrue(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveTrueR: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* Can use any of the first 64 literals for the selector and pass up to 3 arguments. */ /* SimpleStackBasedCogit>>#genSecondExtendedSendBytecode */ static sqInt genSecondExtendedSendBytecode(void) { return genSendnumArgs(byte1 & 0x3F, ((usqInt) byte1) >> 6); } /* SimpleStackBasedCogit>>#genSendLiteralSelector0ArgsBytecode */ static sqInt genSendLiteralSelector0ArgsBytecode(void) { return genSendnumArgs(byte0 & 15, 0); } /* SimpleStackBasedCogit>>#genSendLiteralSelector1ArgBytecode */ static sqInt genSendLiteralSelector1ArgBytecode(void) { return genSendnumArgs(byte0 & 15, 1); } /* SimpleStackBasedCogit>>#genSendLiteralSelector2ArgsBytecode */ static sqInt genSendLiteralSelector2ArgsBytecode(void) { return genSendnumArgs(byte0 & 15, 2); } /* SimpleStackBasedCogit>>#genShortJumpIfFalse */ static sqInt genShortJumpIfFalse(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpIfto(falseObject(), target); } /* SimpleStackBasedCogit>>#genShortJumpIfTrue */ static sqInt genShortJumpIfTrue(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpIfto(trueObject(), target); } /* SimpleStackBasedCogit>>#genShortUnconditionalJump */ static sqInt genShortUnconditionalJump(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpTo(target); } /* SimpleStackBasedCogit>>#genSpecialSelectorEqualsEquals */ static sqInt genSpecialSelectorEqualsEquals(void) { return genInlinedIdenticalOrNotIf(0); } /* SimpleStackBasedCogit>>#genSpecialSelectorNotEqualsEquals */ static sqInt genSpecialSelectorNotEqualsEquals(void) { return genInlinedIdenticalOrNotIf(1); } /* SimpleStackBasedCogit>>#genSpecialSelectorSend */ static sqInt genSpecialSelectorSend(void) { sqInt index; sqInt numArgs; index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); numArgs = specialSelectorNumArgs(index); return genSendnumArgs((-index) - 1, numArgs); } /* SimpleStackBasedCogit>>#genStoreAndPopReceiverVariableBytecode */ static sqInt genStoreAndPopReceiverVariableBytecode(void) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, byte0 & 7, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* SimpleStackBasedCogit>>#genStoreAndPopRemoteTempLongBytecode */ static sqInt genStoreAndPopRemoteTempLongBytecode(void) { return genStorePopRemoteTempAtneedsStoreCheck(1, byte1, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant))))); } /* SimpleStackBasedCogit>>#genStoreAndPopTemporaryVariableBytecode */ static sqInt genStoreAndPopTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(1, byte0 & 7); } /* SimpleStackBasedCogit>>#genStoreRemoteTempLongBytecode */ static sqInt genStoreRemoteTempLongBytecode(void) { return genStorePopRemoteTempAtneedsStoreCheck(0, byte1, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant))))); } /* SistaV1: * 217 Trap */ /* SimpleStackBasedCogit>>#genUnconditionalTrapBytecode */ static sqInt genUnconditionalTrapBytecode(void) { return EncounteredUnknownBytecode; } /* Collect the branch and send data for cogMethod, storing it into arrayObj. */ /* SimpleStackBasedCogit>>#mapPCDataFor:into: */ sqInt mapPCDataForinto(CogMethod *cogMethod, sqInt arrayObj) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; CogBlockMethod *cogMethod1; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; sqInt errCode; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt startbcpc; sqInt targetPC; latestContinuation = 0; introspectionDataIndex = 0; introspectionData = arrayObj; if (((cogMethod->stackCheckOffset)) == 0) { assert(introspectionDataIndex == 0); if ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock)) { storePointerUncheckedofObjectwithValue(0, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(1, introspectionData, (((usqInt)cbNoSwitchEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(3, introspectionData, (((usqInt)cbEntryOffset << 1) | 1)); } else { storePointerUncheckedofObjectwithValue(0, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(1, introspectionData, (((usqInt)cmEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(3, introspectionData, (((usqInt)cmNoCheckEntryOffset << 1) | 1)); } return 4; } /* begin mapFor:bcpc:performUntil:arg: */ cogMethod1 = ((CogBlockMethod *) cogMethod); startbcpc = startPCOfMethod((cogMethod->methodObject)); assert(((cogMethod1->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogMethod1)) + ((cogMethod1->stackCheckOffset)); result = pcDataForAnnotationMcpcBcpcMethod(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc)), startbcpc, (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogMethod1->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod1->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod1); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogMethod1->startpc))); homeMethod = cmHomeMethod(cogMethod1); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod1)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { errCode = 0; goto l7; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { errCode = 0; goto l7; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = pcDataForAnnotationMcpcBcpcMethod(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } errCode = 0; l7: /* end mapFor:bcpc:performUntil:arg: */; if (errCode != 0) { assert(errCode == PrimErrNoMemory); return -1; } if (((cogMethod->blockEntryOffset)) != 0) { errCode = blockDispatchTargetsForperformarg(cogMethod, pcDataForBlockEntryMethod, ((sqInt)cogMethod)); if (errCode != 0) { assert(errCode == PrimErrNoMemory); return -1; } } return introspectionDataIndex; } /* If allocCheckFiller is true, words in newSpace from freeStart to scavengeThreshold are filled with their address, and after each call of a plugin primitive, the VM checks that freeStart points to a word containing the value of freeStart. This is a simple check for primitives overwriting the ends of an object. */ /* SimpleStackBasedCogit>>#maybeCompileAllocFillerCheck */ static void maybeCompileAllocFillerCheck(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmpOk; if (getCheckAllocFiller()) { /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); /* begin JumpZero: */ jmpOk = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, PrimErrWritePastObject, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(PrimErrWritePastObject)); } /* begin MoveR:Aw: */ address1 = primFailCodeAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); jmpTarget(jmpOk, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } } /* SimpleStackBasedCogit>>#numSpecialSelectors */ static sqInt numSpecialSelectors(void) { return # if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltNumSpecialSelectors : NumSpecialSelectors) # else /* MULTIPLEBYTECODESETS */ NumSpecialSelectors # endif /* MULTIPLEBYTECODESETS */ ; } /* Collect the branch and send data for the block method starting at blockEntryMcpc, storing it into picData. */ /* SimpleStackBasedCogit>>#pcDataForBlockEntry:Method: */ static usqInt NoDbgRegParms pcDataForBlockEntryMethod(sqInt blockEntryMcpc, sqInt cogMethod) { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)(blockEntryMcpc - blockNoContextSwitchOffset) << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)blockEntryMcpc << 1) | 1)); introspectionDataIndex += 4; return 0; } /* SimpleStackBasedCogit>>#pcDataFor:Annotation:Mcpc:Bcpc:Method: */ static sqInt NoDbgRegParms pcDataForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg) { sqInt actualBcpc; sqInt actualMcpc; if (!(descriptor)) { /* this is the stackCheck offset */ assert(introspectionDataIndex == 0); if (((((CogMethod *) cogMethodArg))->cpicHasMNUCaseOrCMIsFullBlock)) { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)cbNoSwitchEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)cbEntryOffset << 1) | 1)); } else { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)cmEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)cmNoCheckEntryOffset << 1) | 1)); } storePointerUncheckedofObjectwithValue(introspectionDataIndex + 4, introspectionData, (((usqInt)(bcpc + 1) << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 5, introspectionData, (((((((CogMethod *) cogMethodArg))->stackCheckOffset)) << 1) | 1)); introspectionDataIndex += 6; return 0; } if ((((usqInt) isBackwardBranchAndAnnotation) >> 1) >= HasBytecodePC) { actualBcpc = (isBackwardBranchAndAnnotation & 1 ? bcpc + 1 : (bcpc + ((descriptor->numBytes))) + 1); actualMcpc = (((usqInt)mcpc)) - (((usqInt)cogMethodArg)); storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, (((usqInt)actualBcpc << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)actualMcpc << 1) | 1)); introspectionDataIndex += 2; } return 0; } /* If there is a generator for the current primitive then answer it; otherwise answer nil. */ /* SimpleStackBasedCogit>>#primitiveGeneratorOrNil */ static PrimitiveDescriptor * primitiveGeneratorOrNil(void) { PrimitiveDescriptor *primitiveDescriptor; static PrimitiveDescriptor primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1] = { { 0, -1 }, { genPrimitiveAdd, 1 }, { genPrimitiveSubtract, 1 }, { genPrimitiveLessThan, 1 }, { genPrimitiveGreaterThan, 1 }, { genPrimitiveLessOrEqual, 1 }, { genPrimitiveGreaterOrEqual, 1 }, { genPrimitiveEqual, 1 }, { genPrimitiveNotEqual, 1 }, { genPrimitiveMultiply, 1 }, { genPrimitiveDivide, 1 }, { genPrimitiveMod, 1 }, { genPrimitiveDiv, 1 }, { genPrimitiveQuo, 1 }, { genPrimitiveBitAnd, 1 }, { genPrimitiveBitOr, 1 }, { genPrimitiveBitXor, 1 }, { genPrimitiveBitShift, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveAsFloat, 0 }, { genPrimitiveFloatAdd, 1 }, { genPrimitiveFloatSubtract, 1 }, { genPrimitiveFloatLessThan, 1 }, { genPrimitiveFloatGreaterThan, 1 }, { genPrimitiveFloatLessOrEqual, 1 }, { genPrimitiveFloatGreaterOrEqual, 1 }, { genPrimitiveFloatEqual, 1 }, { genPrimitiveFloatNotEqual, 1 }, { genPrimitiveFloatMultiply, 1 }, { genPrimitiveFloatDivide, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveFloatSquareRoot, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveAt, 1 }, { genPrimitiveAtPut, 2 }, { genPrimitiveSize, 0 }, { genPrimitiveStringAt, 1 }, { genPrimitiveStringAtPut, 2 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { genPrimitiveObjectAt, 1 }, { 0, -1 }, { genPrimitiveNew, 0 }, { genPrimitiveNewWithArg, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentityHash, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveNewMethod, 2 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitivePerform, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveStringReplace, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentical, 1 }, { genPrimitiveClass, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveShallowCopy, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveStringCompareWith, 1 }, { genPrimitiveHashMultiply, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIntegerAt, 1 }, { genPrimitiveIntegerAtPut, 2 }, { 0, -1 }, { 0, -1 }, { genPrimitiveNotIdentical, 1 }, { genPrimitiveAsCharacter, -1 }, { genPrimitiveImmediateAsInteger, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentityHash, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { 0, -1 }, { genPrimitiveClosureValue, 0 }, { genPrimitiveClosureValue, 1 }, { genPrimitiveClosureValue, 2 }, { genPrimitiveClosureValue, 3 }, { genPrimitiveClosureValue, 4 }, { 0, -1 }, { genPrimitiveFullClosureValue, -1 }, { 0, -1 }, { genPrimitiveFullClosureValue, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveClosureValue, 0 }, { genPrimitiveClosureValue, 1 } }; if (isQuickPrimitiveIndex(primitiveIndex)) { /* an unused one */ primitiveDescriptor = (&(primitiveGeneratorTable[0])); (primitiveDescriptor->primitiveGenerator = quickPrimitiveGeneratorFor(primitiveIndex)); return primitiveDescriptor; } if (((primitiveIndex >= 1) && (primitiveIndex <= MaxCompiledPrimitiveIndex))) { return (&(primitiveGeneratorTable[primitiveIndex])); } return null; } /* SimpleStackBasedCogit>>#recordCallOffsetIn: */ void recordCallOffsetIn(CogMethod *cogMethod) { sqInt offset; sqInt *offsetTable; offset = ((primSetFunctionLabel->address)) - (((sqInt)cogMethod)); if ((externalSetPrimOffsets[(cogMethod->cmNumArgs)]) == null) { externalSetPrimOffsets[(cogMethod->cmNumArgs)] = offset; } else { assert((externalSetPrimOffsets[(cogMethod->cmNumArgs)]) == offset); } offsetTable = (isJump(primInvokeInstruction) ? externalPrimJumpOffsets : externalPrimCallOffsets); offset = (((primInvokeInstruction->address)) + ((primInvokeInstruction->machineCodeSize))) - (((sqInt)cogMethod)); if ((offsetTable[(cogMethod->cmNumArgs)]) == null) { offsetTable[(cogMethod->cmNumArgs)] = offset; } else { assert((offsetTable[(cogMethod->cmNumArgs)]) == offset); } } /* SimpleStackBasedCogit>>#rewritePrimInvocationIn:to: */ void rewritePrimInvocationInto(CogMethod *cogMethod, void (*primFunctionPointer)(void)) { usqInt address; sqInt callTargetAddress; sqInt callTargetAddress1; sqInt extent; sqInt flags; sqInt primIndex; assert(((cogMethod->cmType)) == CMMethod); primIndex = primitiveIndexOfMethodheader((cogMethod->methodObject), (cogMethod->methodHeader)); flags = primitivePropertyFlags(primIndex); if (flags & PrimCallNeedsPrimitiveFunction) { storeLiteralbeforeFollowingAddress(backEnd, ((usqInt)primFunctionPointer), (((usqInt)cogMethod)) + (externalSetPrimOffsets[(cogMethod->cmNumArgs)])); } if (flags & PrimCallMayCallBack) { address = (((usqInt)cogMethod)) + (externalPrimJumpOffsets[(cogMethod->cmNumArgs)]); /* begin rewriteJumpFullAt:target: */ callTargetAddress = ((usqInt)primFunctionPointer); extent = rewriteFullTransferAttargetexpectedInstruction(((AbstractInstruction *) backEnd), address, callTargetAddress, 3778019100U); } else { address = (((usqInt)cogMethod)) + (externalPrimCallOffsets[(cogMethod->cmNumArgs)]); /* begin rewriteCallFullAt:target: */ callTargetAddress1 = ((usqInt)primFunctionPointer); extent = rewriteFullTransferAttargetexpectedInstruction(((AbstractInstruction *) backEnd), address, callTargetAddress1, 3778019132U); } flushICacheFromto(processor, (((usqInt)cogMethod)) + cmNoCheckEntryOffset, (((usqInt)address)) + extent); } /* Answers if the code is installed in a class instantiating objects with the format. Used in primitive generation to make a quick path based on where the method is installed. This method cannot be used as a guarantee as there can be false positive, it's just a heuristic. Tries to interpret the last literal of the method as a behavior (more than 3 fields, 3rd field a Smi). If it can be interpreted as a behavior, answers if instSpec matches the format, else answers false. */ /* SimpleStackBasedCogit>>#seemsToBeInstantiating: */ static sqInt NoDbgRegParms seemsToBeInstantiating(sqInt format) { return maybeMethodClassOfseemsToBeInstantiating(methodObj, format); } /* SimpleStackBasedCogit>>#v3:Block:Code:Size: */ static sqInt NoDbgRegParms v3BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts <= 0); return (((sqInt)((usqInt)((fetchByteofObject(pc + 2, aMethodObj))) << 8))) + (fetchByteofObject(pc + 3, aMethodObj)); } /* Answer the distance of a two byte forward long jump. */ /* SimpleStackBasedCogit>>#v3:LongForward:Branch:Distance: */ static sqInt NoDbgRegParms v3LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return (((sqInt)((usqInt)(((fetchByteofObject(pc, aMethodObj)) & 3)) << 8))) + (fetchByteofObject(pc + 1, aMethodObj)); } /* Answer the distance of a two byte forward long jump. */ /* SimpleStackBasedCogit>>#v3:Long:Branch:Distance: */ static sqInt NoDbgRegParms v3LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return (((sqInt)((usqInt)((((fetchByteofObject(pc, aMethodObj)) & 7) - 4)) << 8))) + (fetchByteofObject(pc + 1, aMethodObj)); } /* N.B. This serves for both BlueBook/V3 and V4 short jumps. */ /* SimpleStackBasedCogit>>#v3:ShortForward:Branch:Distance: */ static sqInt NoDbgRegParms v3ShortForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return ((fetchByteofObject(pc, aMethodObj)) & 7) + 1; } /* 253 11111101 eei i i kkk jjjjjjjj Push Closure Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8) BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions */ /* SimpleStackBasedCogit>>#v4:Block:Code:Size: */ static sqInt NoDbgRegParms v4BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt byteOne; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; /* If nExts < 0 it isn't known and we rely on the number of extensions encoded in the eeiiikkk byte. */ byteOne = fetchByteofObject(pc + 1, aMethodObj); assert((nExts < 0) || (nExts == (((usqInt) byteOne) >> 6))); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - (((usqInt) byteOne) >> 6)) - (((usqInt) byteOne) >> 6); while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 2, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* 243 11110011 i i i i i i i i Pop and Jump 0n True i i i i i i i i (+ Extend A * 256) */ /* 244 11110100 i i i i i i i i Pop and Jump 0n False i i i i i i i i (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#v4:LongForward:Branch:Distance: */ static sqInt NoDbgRegParms v4LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; assert(nExts >= 0); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - nExts) - nExts; while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 1, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#v4:Long:Branch:Distance: */ static sqInt NoDbgRegParms v4LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; assert(nExts >= 0); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - nExts) - nExts; while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 1, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* SimpleStackBasedCogit>>#voidCogCompiledCode */ void voidCogCompiledCode(void) { sqInt i; clearCogCompiledCode(); for (i = 0; i <= MaxNumArgs; i += 1) { externalPrimJumpOffsets[i] = null; externalPrimCallOffsets[i] = null; externalSetPrimOffsets[i] = null; } } /* Add a blockStart for an embedded block. For a binary tree walk block dispatch blocks must be compiled in pc/depth-first order but are scanned in breadth-first order, so do an insertion sort (which of course is really a bubble sort because we have to move everything higher to make room). */ /* StackToRegisterMappingCogit>>#addBlockStartAt:numArgs:numCopied:span: */ static BlockStart * NoDbgRegParms addBlockStartAtnumArgsnumCopiedspan(sqInt bytecodepc, sqInt numArgs, sqInt numCopied, sqInt span) { BlockStart *blockStart; sqInt i; sqInt j; /* Transcript ensureCr; nextPutAll: 'addBlockStartAt: '; print: bytecodepc; cr; flush. */ if (blockCount > 0) { 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; } for (j = blockCount; j >= (i + 1); j += -1) { blockStarts[j] = (blockStarts[j - 1]); } blockStart = (&(blockStarts[i + 1])); } else { blockStart = (&(blockStarts[blockCount])); } blockCount += 1; (blockStart->startpc = bytecodepc); (blockStart->numArgs = numArgs); (blockStart->numCopied = numCopied); (blockStart->numInitialNils = 0); (blockStart->stackCheckLabel = null); (blockStart->hasInstVarRef = 0); (blockStart->span = span); return blockStart; } /* e.g. Receiver Receiver or Receiver Receiver (RISC) Selector/Arg0 => Arg1 Selector/Arg0 => Arg1 Arg1 Arg2 Arg1 Arg2 Arg2 Arg3 Arg2 sp-> Arg3 Arg3 sp-> retpc sp-> Arg3 sp-> retpc */ /* Generate code to adjust the possibly stacked arguments immediately before jumping to a method looked up by a perform primitive. */ /* StackToRegisterMappingCogit>>#adjustArgumentsForPerform: */ static void NoDbgRegParms adjustArgumentsForPerform(sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction3; sqInt index; assert((numRegArgs()) <= 2); assert(numArgs >= 1); if (numArgs <= 2 /* numRegArgs */) { if (numArgs == 2) { /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, Arg0Reg); } return; } if ((2 /* numRegArgs */ + 1) == numArgs) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, SPReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, BytesPerWord, SPReg, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AddCqR, (numArgs + 1) * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral((numArgs + 1) * BytesPerWord)); } return; } for (index = (numArgs - 2); index >= 0; index += -1) { /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveMwrR, index * BytesPerWord, SPReg, TempReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(index * BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveRMwr, TempReg, (index + 1) * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral((index + 1) * BytesPerWord)); } } /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(BytesPerWord)); } } /* If the stack entry is already in a register not conflicting with regMask, answers it, else allocate a new register not conflicting with reg mask */ /* StackToRegisterMappingCogit>>#allocateRegForStackEntryAt:notConflictingWith: */ static sqInt NoDbgRegParms allocateRegForStackEntryAtnotConflictingWith(sqInt index, sqInt regMask) { sqInt mask; CogSimStackEntry *stackEntry; stackEntry = ssValue(index); mask = registerMaskOrNone(stackEntry); if ((mask != 0) && ((mask & regMask) == 0)) { flag("TODO"); return registerOrNone(stackEntry); } return allocateRegNotConflictingWith(regMask); } /* if there's a free register, use it */ /* StackToRegisterMappingCogit>>#allocateRegNotConflictingWith: */ static sqInt NoDbgRegParms allocateRegNotConflictingWith(sqInt regMask) { sqInt reg; reg = availableRegisterOrNoneFor(backEnd, (liveRegisters()) | regMask); if (reg == NoReg) { /* No free register, choose one that does not conflict with regMask */ reg = freeAnyRegNotConflictingWith(regMask); } if (reg == ReceiverResultReg) { /* If we've allocated RcvrResultReg, it's not live anymore */ voidReceiverResultRegContainsSelf(); } return reg; } /* StackToRegisterMappingCogit>>#anyReferencesToRegister:inTopNItems: */ static sqInt NoDbgRegParms anyReferencesToRegisterinTopNItems(sqInt reg, sqInt n) { sqInt i; sqInt regMask; /* begin registerMaskFor: */ regMask = 1U << reg; for (i = simStackPtr; i >= ((simStackPtr - n) + 1); i += -1) { if ((registerMask(simStackAt(i))) & regMask) { return 1; } } return 0; } /* This is a static version of ceCallCogCodePopReceiverArg0Regs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* StackToRegisterMappingCogit>>#callCogCodePopReceiverArg0Regs */ void callCogCodePopReceiverArg0Regs(void) { realCECallCogCodePopReceiverArg0Regs(); } /* This is a static version of ceCallCogCodePopReceiverArg1Arg0Regs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* StackToRegisterMappingCogit>>#callCogCodePopReceiverArg1Arg0Regs */ void callCogCodePopReceiverArg1Arg0Regs(void) { realCECallCogCodePopReceiverArg1Arg0Regs(); } /* Loop over bytecodes, dispatching to the generator for each bytecode, handling fixups in due course. */ /* StackToRegisterMappingCogit>>#compileAbstractInstructionsFrom:through: */ static sqInt NoDbgRegParms compileAbstractInstructionsFromthrough(sqInt start, sqInt end) { BytecodeDescriptor *descriptor; BytecodeFixup *fixup; sqInt nExts; sqInt nextOpcodeIndex; sqInt result; traceSimStack(); bytecodePC = start; nExts = (result = 0); descriptor = null; deadCode = 0; while (1) { maybeHaltIfDebugPC(); mergeWithFixupIfRequired((fixup = fixupAt(bytecodePC))); descriptor = loadBytesAndGetDescriptor(); nextOpcodeIndex = opcodeIndex; result = (deadCode ? mapDeadDescriptorIfNeeded(descriptor) : ((descriptor->generator))()); if (result == 0) { /* begin assertExtsAreConsumed: */ if (!((descriptor->isExtension))) { assert((extA == 0) && ((extB == 0) && (numExtB == 0))); } } traceDescriptor(descriptor); traceSimStack(); /* begin patchFixupTargetIfNeeded:nextOpcodeIndex: */ if ((((((usqInt)((fixup->targetInstruction)))) >= NeedsNonMergeFixupFlag) && ((((usqInt)((fixup->targetInstruction)))) <= NeedsMergeFixupFlag))) { /* There is a fixup for this bytecode. It must point to the first generated instruction for this bytecode. If there isn't one we need to add a label. */ if (opcodeIndex == nextOpcodeIndex) { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (fixup->targetInstruction = abstractInstructionAt(nextOpcodeIndex)); } /* begin maybeDumpLiterals: */ if ((mustDumpLiterals(opcodeIndex)) || (((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) || ((descriptor->isReturn)))) { dumpLiterals(!(((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) || ((descriptor->isReturn)))); } /* begin nextBytecodePCFor:exts: */ bytecodePC = (bytecodePC + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? ((descriptor->spanFunction))(descriptor, bytecodePC, nExts, methodObj) : 0)); if (!((result == 0) && (bytecodePC <= end))) break; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } /* begin checkEnoughOpcodes */ if (opcodeIndex > numAbstractOpcodes) { error("Cog JIT internal error. Too many abstract opcodes. Num opcodes heuristic is too optimistic."); } return result; } /* StackToRegisterMappingCogit>>#compileBlockBodies */ static sqInt compileBlockBodies(void) { BlockStart *blockStart; sqInt compiledBlocksCount; sqInt initialCounterIndex; sqInt initialOpcodeIndex; sqInt initialStackPtr; sqInt (* const pushNilSizeFunction)(sqInt,sqInt) = squeakV3orSistaV1PushNilSizenumInitialNils; sqInt result; sqInt savedFirstOpcodeIndex; sqInt savedLastDumpedLiteralIndex; sqInt savedNeedsFrame; sqInt savedNextLiteralIndex; sqInt savedNumArgs; sqInt savedNumTemps; assert(blockCount > 0); savedNeedsFrame = needsFrame; savedNumArgs = methodOrBlockNumArgs; savedNumTemps = methodOrBlockNumTemps; inBlock = InVanillaBlock; compiledBlocksCount = 0; while (compiledBlocksCount < blockCount) { compilationPass = 1; blockStart = blockStartAt(compiledBlocksCount); if (((result = scanBlock(blockStart))) < 0) { return result; } initialOpcodeIndex = opcodeIndex; /* for SistaCogit */ initialCounterIndex = 0 /* maybeCounterIndex */; /* begin saveForRecompile */ savedFirstOpcodeIndex = firstOpcodeIndex; savedNextLiteralIndex = nextLiteralIndex; savedLastDumpedLiteralIndex = lastDumpedLiteralIndex; while (1) { compileBlockEntry(blockStart); initialStackPtr = simStackPtr; if (((result = compileAbstractInstructionsFromthrough(((blockStart->startpc)) + (pushNilSizeFunction(methodObj, ((blockStart->numInitialNils)))), (((blockStart->startpc)) + ((blockStart->span))) - 1))) < 0) { return result; } if (initialStackPtr == simStackPtr) break; assert((initialStackPtr > simStackPtr) || (deadCode)); /* for asserts */ compilationPass += 1; (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; /* begin resetForRecompile */ firstOpcodeIndex = savedFirstOpcodeIndex; nextLiteralIndex = savedNextLiteralIndex; lastDumpedLiteralIndex = savedLastDumpedLiteralIndex; } compiledBlocksCount += 1; } needsFrame = savedNeedsFrame; methodOrBlockNumArgs = savedNumArgs; methodOrBlockNumTemps = savedNumTemps; return 0; } /* Build a frame for a block activation. See CoInterpreter class>>initializeFrameIndices. closure (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... 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). */ /* StackToRegisterMappingCogit>>#compileBlockFrameBuild: */ static void NoDbgRegParms compileBlockFrameBuild(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction * cascade0; sqInt constant; sqInt constant1; sqInt i; sqInt ign; /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); cascade0 = (blockStart->fakeHeader); addDependent(cascade0, annotateAbsolutePCRef(gPushCw(((sqInt)((blockStart->fakeHeader)))))); /* begin setLabelOffset: */ ((cascade0->operands))[1] = MFMethodFlagIsBlockFlag; annotateobjRef(gPushCw(nilObject()), nilObject()); if ((blockStart->hasInstVarRef)) { /* Use ReceiverResultReg for Context to agree with store check trampoline */ genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ClassReg, ReceiverResultReg); genLoadSlotsourceRegdestReg(ReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, ReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } else { genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ClassReg, Arg0Reg); genLoadSlotsourceRegdestReg(ReceiverIndex, Arg0Reg, ReceiverResultReg); } /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = 0; i < ((blockStart->numCopied)); i += 1) { genLoadSlotsourceRegdestReg(i + ClosureFirstCopiedValueIndex, ClassReg, TempReg); /* begin PushR: */ genoperand(PushR, TempReg); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); (blockStart->stackCheckLabel = annotateBytecode(genoperandoperand(Label, (labelCounter += 1), bytecodePC))); methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); initSimStackForFramefulMethod((blockStart->startpc)); if (((blockStart->numInitialNils)) > 0) { if (((blockStart->numInitialNils)) > 1) { /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } for (ign = 1; ign <= ((blockStart->numInitialNils)); ign += 1) { /* begin PushR: */ genoperand(PushR, TempReg); } } else { /* begin genPushConstant: */ constant1 = nilObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gPushCw(constant1), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperand(PushCq, constant1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } } } } /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg. We must annotate the first instruction in vanilla blocks 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 */ /* StackToRegisterMappingCogit>>#compileBlockFramelessEntry: */ static void NoDbgRegParms compileBlockFramelessEntry(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); initSimStackForFramelessBlock((blockStart->startpc)); if (!(((blockStart->entryLabel)) == null)) { /* begin annotateBytecode: */ abstractInstruction = (blockStart->entryLabel); (abstractInstruction->annotation = HasBytecodePC); /* begin annotateBytecode: */ abstractInstruction1 = (blockStart->entryLabel); (abstractInstruction1->annotation = HasBytecodePC); } if ((blockStart->hasInstVarRef)) { /* Use ReceiverResultReg for Context to agree with store check trampoline */ genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, ReceiverResultReg); genLoadSlotsourceRegdestReg(ReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, ReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } else { genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, TempReg); genLoadSlotsourceRegdestReg(ReceiverIndex, TempReg, ReceiverResultReg); } } /* StackToRegisterMappingCogit>>#compileCogFullBlockMethod: */ static CogMethod * NoDbgRegParms compileCogFullBlockMethod(sqInt numCopied) { sqInt allocBytes; sqInt fixupBytes; sqInt numBlocks; sqInt numBytecodes; sqInt numberOfAbstractOpcodes; sqInt numCleanBlocks; sqInt opcodeBytes; sqInt result; methodOrBlockNumTemps = tempCountOf(methodObj); hasYoungReferent = isYoungObject(methodObj); methodOrBlockNumArgs = argumentCountOf(methodObj); inBlock = InFullBlock; postCompileHook = null; maxLitIndex = -1; assert((primitiveIndexOf(methodObj)) == 0); /* initial estimate. Actual endPC is determined in scanMethod. */ initialPC = startPCOfMethod(methodObj); endPC = numBytesOf(methodObj); numBytecodes = (endPC - initialPC) + 1; primitiveIndex = 0; /* begin allocateOpcodes:bytecodes:ifFail: */ numberOfAbstractOpcodes = (numBytecodes + 10) * 10 /* estimateOfAbstractOpcodesPerBytecodes */; numAbstractOpcodes = numberOfAbstractOpcodes; opcodeBytes = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupBytes = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; /* Document the fact that the MaxStackAllocSize ensures that the number of abstract opcodes fits in a 16 bit integer (e.g. CogBytecodeFixup's instructionIndex). */ allocBytes = opcodeBytes + fixupBytes; assert((((sizeof(CogAbstractInstruction)) + (sizeof(CogBytecodeFixup))) * 49152) > MaxStackAllocSize); if (allocBytes > MaxStackAllocSize) { return ((CogMethod *) MethodTooBig); goto l1; } abstractOpcodes = alloca(allocBytes); bzero(abstractOpcodes, allocBytes); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeBytes)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; l1: /* end allocateOpcodes:bytecodes:ifFail: */; flag("TODO"); if (((numBlocks = scanMethod())) < 0) { return ((CogMethod *) numBlocks); } assert(numBlocks == 0); numCleanBlocks = scanForCleanBlocks(); assert(numCleanBlocks == 0); allocateBlockStarts(numBlocks + numCleanBlocks); blockCount = 0; if (numCleanBlocks > 0) { addCleanBlockStarts(); } if (!(maybeAllocAndInitIRCs())) { /* Inaccurate error code, but it'll do. This will likely never fail. */ return ((CogMethod *) InsufficientCodeSpace); } blockEntryLabel = null; (methodLabel->dependent = null); if (((result = compileEntireFullBlockMethod(numCopied))) < 0) { return ((CogMethod *) result); } return generateCogFullBlock(); } /* StackToRegisterMappingCogit>>#compileCogMethod: */ static CogMethod * NoDbgRegParms compileCogMethod(sqInt selector) { sqInt allocBytes; int extra; sqInt fixupBytes; sqInt numBlocks; sqInt numBytecodes; sqInt numberOfAbstractOpcodes; sqInt numCleanBlocks; sqInt opcodeBytes; sqInt result; methodOrBlockNumTemps = tempCountOf(methodObj); hasYoungReferent = (isYoungObject(methodObj)) || (isYoung(selector)); methodOrBlockNumArgs = argumentCountOf(methodObj); inBlock = 0; postCompileHook = null; maxLitIndex = -1; extra = ((((primitiveIndex = primitiveIndexOf(methodObj))) > 0) && (!(isQuickPrimitiveIndex(primitiveIndex))) ? 30 : 10); /* initial estimate. Actual endPC is determined in scanMethod. */ initialPC = startPCOfMethod(methodObj); endPC = (isQuickPrimitiveIndex(primitiveIndex) ? initialPC - 1 : numBytesOf(methodObj)); numBytecodes = (endPC - initialPC) + 1; /* begin allocateOpcodes:bytecodes:ifFail: */ numberOfAbstractOpcodes = (numBytecodes + extra) * 10 /* estimateOfAbstractOpcodesPerBytecodes */; numAbstractOpcodes = numberOfAbstractOpcodes; opcodeBytes = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupBytes = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; /* Document the fact that the MaxStackAllocSize ensures that the number of abstract opcodes fits in a 16 bit integer (e.g. CogBytecodeFixup's instructionIndex). */ allocBytes = opcodeBytes + fixupBytes; assert((((sizeof(CogAbstractInstruction)) + (sizeof(CogBytecodeFixup))) * 49152) > MaxStackAllocSize); if (allocBytes > MaxStackAllocSize) { return ((CogMethod *) MethodTooBig); goto l1; } abstractOpcodes = alloca(allocBytes); bzero(abstractOpcodes, allocBytes); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeBytes)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; l1: /* end allocateOpcodes:bytecodes:ifFail: */; if (((numBlocks = scanMethod())) < 0) { return ((CogMethod *) numBlocks); } numCleanBlocks = scanForCleanBlocks(); if (methodFoundInvalidPostScan()) { return ((CogMethod *) ShouldNotJIT); } allocateBlockStarts(numBlocks + numCleanBlocks); blockCount = 0; if (numCleanBlocks > 0) { addCleanBlockStarts(); } if (!(maybeAllocAndInitIRCs())) { /* Inaccurate error code, but it'll do. This will likely never fail. */ return ((CogMethod *) InsufficientCodeSpace); } blockEntryLabel = null; (methodLabel->dependent = null); if (((result = compileEntireMethod())) < 0) { return ((CogMethod *) result); } return generateCogMethod(selector); } /* Compile the abstract instructions for the entire method, including blocks. */ /* Compile the abstract instructions for the entire method, including blocks. */ /* StackToRegisterMappingCogit>>#compileEntireMethod */ static sqInt compileEntireMethod(void) { sqInt result; regArgsHaveBeenPushed = 0; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compileAbort(); compileEntry(); if (((result = compilePrimitive())) < 0) { return result; } compileFrameBuild(); if (((result = compileMethodBody())) < 0) { return result; } if (blockCount == 0) { return 0; } if (((result = compileBlockBodies())) < 0) { return result; } return compileBlockDispatch(); } /* Build a frame for a CogMethod activation. See CoInterpreter class>>initializeFrameIndices. receiver (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp If there is a primitive and an error code the Nth temp is the error code. 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. */ /* StackToRegisterMappingCogit>>#compileFrameBuild */ static void compileFrameBuild(void) { sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt constant; sqInt i; sqInt iLimiT; AbstractInstruction *jumpSkip; # if IMMUTABILITY if (useTwoPaths) { compileTwoPathFrameBuild(); return; } # endif /* IMMUTABILITY */ if (!needsFrame) { if (useTwoPaths) { compileTwoPathFramelessInit(); } initSimStackForFramelessMethod(initialPC); return; } assert(!(useTwoPaths)); genPushRegisterArgs(); if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = (methodOrBlockNumArgs + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } if (((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))) { compileGetErrorCode(); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); if (canContextSwitchIfActivatingheader(methodObj, methodHeader)) { /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin Label */ stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { /* begin JumpAboveOrEqual: */ jumpSkip = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin Jump: */ genoperand(Jump, ((sqInt)stackOverflowCall)); jmpTarget(jumpSkip, (stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } /* begin annotateBytecode: */ (stackCheckLabel->annotation = HasBytecodePC); initSimStackForFramefulMethod(initialPC); } /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg. */ /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg */ /* StackToRegisterMappingCogit>>#compileFullBlockFramelessEntry: */ static void NoDbgRegParms compileFullBlockFramelessEntry(sqInt numCopied) { initSimStackForFramelessBlock(initialPC); flag("TODO"); genLoadSlotsourceRegdestReg(FullClosureReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, FullClosureReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } /* Build a frame for a block activation. See CoInterpreter class>>initializeFrameIndices. closure (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp Avoid use of SendNumArgsReg which is the flag determining whether context switch is allowed on stack-overflow. */ /* StackToRegisterMappingCogit>>#compileFullBlockMethodFrameBuild: */ static void NoDbgRegParms compileFullBlockMethodFrameBuild(sqInt numCopied) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; sqInt constant; sqInt i; sqInt iLimiT; if (useTwoPaths) { /* method with only inst var store, we compile only slow path for now */ useTwoPaths = 0; # if IMMUTABILITY needsFrame = 1; # endif /* IMMUTABILITY */ } if (!needsFrame) { assert(numCopied == 0); compileFullBlockFramelessEntry(numCopied); initSimStackForFramelessBlock(initialPC); return; } if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin setLabelOffset: */ (((((AbstractInstruction *) methodLabel))->operands))[1] = MFMethodFlagIsBlockFlag; /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); flag("TODO"); genLoadSlotsourceRegdestReg(FullClosureReceiverIndex, ClassReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, FullClosureReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = 0; i < numCopied; i += 1) { genLoadSlotsourceRegdestReg(i + FullClosureFirstCopiedValueIndex, ClassReg, TempReg); /* begin PushR: */ genoperand(PushR, TempReg); } for (i = ((methodOrBlockNumArgs + numCopied) + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); stackCheckLabel = abstractInstruction; initSimStackForFramefulMethod(initialPC); } /* Build a frame for a CogMethod activation. See CoInterpreter class>>initializeFrameIndices. receiver (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp If there is a primitive and an error code the Nth temp is the error code. Ensure SendNumArgsReg is set early on (incidentally to nilObj) because it is the flag determining whether context switch is allowed on stack-overflow. */ /* We are in a method where the frame is needed *only* for instance variable store, typically a setter method. This case has 20% overhead with Immutability compared to setter without immutability because of the stack frame creation. We compile two path, one where the object is immutable, one where it isn't. At the beginning of the frame build, we take one path or the other depending on the receiver mutability. Note: this specific case happens only where there are only instance variabel stores. We could do something similar for literal variable stores, but we don't as it's too uncommon. */ /* StackToRegisterMappingCogit>>#compileTwoPathFrameBuild */ #if IMMUTABILITY static void compileTwoPathFrameBuild(void) { sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt constant; sqInt i; sqInt iLimiT; AbstractInstruction * jumpImmutable; AbstractInstruction * jumpOld; AbstractInstruction *jumpSkip; sqInt quickConstant; assert(useTwoPaths); assert(blockCount == 0); jumpImmutable = genJumpImmutablescratchReg(ReceiverResultReg, TempReg); /* first path. The receiver is mutable */ /* N.B. FLAGS := destReg - scratchReg */ /* begin CmpCq:R: */ quickConstant = storeCheckBoundary(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); assert(!needsFrame); initSimStackForFramelessMethod(initialPC); /* begin compileMethodBody */ if (endPC < initialPC) { goto l8; } compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); l8: /* end compileMethodBody */; /* reset because it impacts inst var store compilation */ useTwoPaths = 0; needsFrame = 1; jmpTarget(jumpOld, jmpTarget(jumpImmutable, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genPushRegisterArgs(); if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = (methodOrBlockNumArgs + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } if (((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))) { compileGetErrorCode(); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); if (canContextSwitchIfActivatingheader(methodObj, methodHeader)) { /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin Label */ stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { /* begin JumpAboveOrEqual: */ jumpSkip = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin Jump: */ genoperand(Jump, ((sqInt)stackOverflowCall)); jmpTarget(jumpSkip, (stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } /* begin annotateBytecode: */ (stackCheckLabel->annotation = HasBytecodePC); initSimStackForFramefulMethod(initialPC); } #endif /* IMMUTABILITY */ /* We are in a frameless method with at least two inst var stores. We compile two paths, one where the object is in new space, and one where it isn't. At the beginning of the method, we take one path or the other depending on the receiver being in newSpace. */ /* StackToRegisterMappingCogit>>#compileTwoPathFramelessInit */ static void compileTwoPathFramelessInit(void) { AbstractInstruction *anInstruction; AbstractInstruction * jumpOld; sqInt quickConstant; assert(!(IMMUTABILITY)); assert(!(needsFrame)); assert(useTwoPaths); /* first path. The receiver is young */ /* N.B. FLAGS := destReg - scratchReg */ /* begin CmpCq:R: */ quickConstant = storeCheckBoundary(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); initSimStackForFramelessMethod(initialPC); /* begin compileMethodBody */ if (endPC < initialPC) { goto l1; } compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); l1: /* end compileMethodBody */; /* reset because it impacts inst var store compilation */ useTwoPaths = 0; jmpTarget(jumpOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* StackToRegisterMappingCogit>>#cPICMissTrampolineFor: */ static sqInt NoDbgRegParms cPICMissTrampolineFor(sqInt numArgs) { return picMissTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* Replaces the Blue Book double-extended send [132], in which the first byte was wasted on 8 bits of argument count. Here we use 3 bits for the operation sub-type (opType), and the remaining 5 bits for argument count where needed. The last byte give access to 256 instVars or literals. See also secondExtendedSendBytecode */ /* StackToRegisterMappingCogit>>#doubleExtendedDoAnythingBytecode */ static sqInt doubleExtendedDoAnythingBytecode(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; sqInt opType; opType = ((usqInt) byte1) >> 5; if (opType == 0) { return genSendnumArgs(byte2, byte1 & 0x1F); } if (opType == 1) { return genSendSupernumArgs(byte2, byte1 & 0x1F); } switch (opType) { case 2: if (isReadMediatedContextInstVarIndex(byte2)) { genPushMaybeContextReceiverVariable(byte2); } else { genPushReceiverVariable(byte2); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); return 0; } break; case 3: genPushLiteralIndex(byte2); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction1 = gen(Nop); } else { /* begin Label */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction1->annotation = HasBytecodePC); return 0; case 4: genPushLiteralVariable(byte2); break; case 7: genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); # if IMMUTABILITY /* genStorePop:LiteralVariable: annotates; don't annotate twice */ return 0; # endif /* IMMUTABILITY */ break; default: /* 5 & 6 */ if (isWriteMediatedContextInstVarIndex(byte2)) { genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(opType == 6, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } else { genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(opType == 6, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } # if IMMUTABILITY /* genStorePop:...ReceiverVariable: annotate; don't annotate twice */ return 0; # endif /* IMMUTABILITY */ ; } assert(needsFrame); assert(!(prevInstIsPCAnnotated())); /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); return 0; } /* StackToRegisterMappingCogit>>#duplicateTopBytecode */ static sqInt duplicateTopBytecode(void) { SimStackEntry desc; /* begin ssTopDescriptor */ desc = simStack[simStackPtr]; return ssPushDesc(desc); } /* Make sure there's a flagged fixup at the target pc in fixups. Initially a fixup's target is just a flag. Later on it is replaced with a proper instruction. */ /* StackToRegisterMappingCogit>>#ensureFixupAt: */ static BytecodeFixup * NoDbgRegParms ensureFixupAt(sqInt targetPC) { BytecodeFixup *fixup; /* begin fixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); traceFixupmerge(fixup, 1); if ((((usqInt)((fixup->targetInstruction)))) <= NeedsNonMergeFixupFlag) { /* convert a non-merge into a merge */ /* begin becomeMergeFixup */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); (fixup->simStackPtr = simStackPtr); } else { if ((fixup->isTargetOfBackwardBranch)) { /* this is the target of a backward branch and so doesn't have a simStackPtr assigned yet. */ (fixup->simStackPtr = simStackPtr); } else { assert(((fixup->simStackPtr)) == simStackPtr); } } /* begin recordBcpc: */ return fixup; } /* Make sure there's a flagged fixup at the target pc in fixups. Initially a fixup's target is just a flag. Later on it is replaced with a proper instruction. */ /* StackToRegisterMappingCogit>>#ensureNonMergeFixupAt: */ static BytecodeFixup * NoDbgRegParms ensureNonMergeFixupAt(sqInt targetPC) { BytecodeFixup *fixup; /* begin fixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); traceFixupmerge(fixup, 1); if (((fixup->targetInstruction)) == 0) { /* begin becomeNonMergeFixup */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsNonMergeFixupFlag); } /* begin recordBcpc: */ return fixup; } /* StackToRegisterMappingCogit>>#ensureReceiverResultRegContainsSelf */ static void ensureReceiverResultRegContainsSelf(void) { if (needsFrame) { if (!((((simSelf())->liveRegister)) == ReceiverResultReg)) { /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); ((simSelf())->liveRegister = ReceiverResultReg); } } else { assert(((((simSelf())->type)) == SSRegister) && (((((simSelf())->registerr)) == ReceiverResultReg) && (receiverIsInReceiverResultReg()))); } } /* StackToRegisterMappingCogit>>#evaluate:at: */ static void NoDbgRegParms evaluateat(BytecodeDescriptor *descriptor, sqInt pc) { byte0 = fetchByteofObject(pc, methodObj); assert(descriptor == (generatorAt(bytecodeSetOffset + byte0))); loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } /* Attempt to follow a branch to a pc. Handle branches to unconditional jumps and branches to push: aBoolean; conditional branch pairs. If the branch cannot be followed answer targetBytecodePC. It is not possible to follow jumps to conditional branches because the stack changes depth. That following is left to the genJumpIf:to: clients. */ /* StackToRegisterMappingCogit>>#eventualTargetOf: */ static sqInt NoDbgRegParms eventualTargetOf(sqInt targetBytecodePC) { sqInt cond; sqInt currentTarget; BytecodeDescriptor *descriptor; sqInt nExts; sqInt nextPC; sqInt span; cond = 0; nextPC = (currentTarget = targetBytecodePC); while(1) { nExts = 0; while (1) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC, methodObj))); if ((descriptor->isReturn)) { return currentTarget; } if (!((descriptor->isExtension))) break; nExts += 1; nextPC += (descriptor->numBytes); } if ((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) { /* begin spanFor:at:exts:in: */ span = ((descriptor->spanFunction))(descriptor, nextPC, nExts, methodObj); if (span < 0) { /* Do *not* follow backward branches; these are interrupt points and should not be elided. */ return currentTarget; } nextPC = (nextPC + ((descriptor->numBytes))) + span; } else { if (((descriptor->generator)) == genPushConstantTrueBytecode) { cond = 1; } else { if (((descriptor->generator)) == genPushConstantFalseBytecode) { cond = 0; } else { return currentTarget; } } if (((fixupAt(nextPC))->isTargetOfBackwardBranch)) { return currentTarget; } nextPC = eventualTargetOf(nextPC + ((descriptor->numBytes))); nExts = 0; while (1) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC, methodObj))); if ((descriptor->isReturn)) { return currentTarget; } if (!((descriptor->isExtension))) break; nExts += 1; nextPC += (descriptor->numBytes); } if (!(isBranch(descriptor))) { return currentTarget; } if ((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) { return currentTarget; } nextPC = (cond == ((descriptor->isBranchTrue)) ? (nextPC + ((descriptor->numBytes))) + (((descriptor->spanFunction))(descriptor, nextPC, nExts, methodObj)) : nextPC + ((descriptor->numBytes))); } currentTarget = nextPC; } return 0; } /* Spill the closest register on stack not conflicting with regMask. Assertion Failure if regMask has already all the registers */ /* StackToRegisterMappingCogit>>#freeAnyRegNotConflictingWith: */ static sqInt NoDbgRegParms freeAnyRegNotConflictingWith(sqInt regMask) { CogSimStackEntry *desc; sqInt index; sqInt reg; assert(needsFrame); reg = NoReg; index = ((simSpillBase < 0) ? 0 : simSpillBase); while ((reg == NoReg) && (index < simStackPtr)) { desc = simStackAt(index); if (((desc->type)) == SSRegister) { if (!(regMask & (1U << ((desc->registerr))))) { reg = (desc->registerr); } } index += 1; } assert(!((reg == NoReg))); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << reg, simStackPtr, simNativeStackPtr); return reg; } /* Return from block, assuming result already loaded into ReceiverResultReg. */ /* Return from block, assuming result already loaded into ReceiverResultReg. */ /* StackToRegisterMappingCogit>>#genBlockReturn */ static sqInt genBlockReturn(void) { if (needsFrame) { /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, SPReg); /* begin PopR: */ genoperand(PopR, FPReg); /* begin PopR: */ genoperand(PopR, LinkReg); } /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); /* can't fall through */ deadCode = 1; return 0; } /* Generate special versions of the ceCallCogCodePopReceiverAndClassRegs enilopmart that also pop register args from the stack to undo the pushing of register args in the abort/miss trampolines. */ /* StackToRegisterMappingCogit>>#genCallPICEnilopmartNumArgs: */ static void (*genCallPICEnilopmartNumArgs(sqInt numArgs))(void) { AbstractInstruction *anInstruction; sqInt endAddress; sqInt enilopmart; sqInt quickConstant; sqInt reg; sqInt size; zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } genLoadStackPointers(backEnd); /* begin PopR: */ genoperand(PopR, ClassReg); /* begin PopR: */ genoperand(PopR, TempReg); /* begin PopR: */ reg = LinkReg; genoperand(PopR, reg); if (numArgs > 0) { if (numArgs > 1) { /* begin PopR: */ genoperand(PopR, Arg1Reg); assert((numRegArgs()) == 2); } /* begin PopR: */ genoperand(PopR, Arg0Reg); } /* begin PopR: */ genoperand(PopR, ReceiverResultReg); /* begin JumpR: */ genoperand(JumpR, TempReg); computeMaximumSizes(); size = generateInstructionsAt(methodZoneBase); endAddress = outputInstructionsAt(methodZoneBase); assert((methodZoneBase + size) == endAddress); enilopmart = methodZoneBase; methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(backEnd, endAddress, methodZoneBase - 1); recordGeneratedRunTimeaddress(trampolineNamenumRegArgs("ceCallPIC", numArgs), enilopmart); return ((void (*)(void)) enilopmart); } /* SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution. See EncoderForSistaV1's class comment and StackInterpreter>>#inlinePrimitiveBytecode: */ /* StackToRegisterMappingCogit>>#genCallPrimitiveBytecode */ static sqInt genCallPrimitiveBytecode(void) { sqInt prim; sqInt primSet; if (byte2 < 128) { return (bytecodePC == initialPC ? 0 : EncounteredUnknownBytecode); } prim = (((sqInt)((usqInt)((byte2 - 128)) << 8))) + byte1; primSet = (((usqInt) prim) >> 13) & 3; prim = prim & 0x1FFF; return EncounteredUnknownBytecode; } /* Override to push the register receiver and register arguments, if any. */ /* StackToRegisterMappingCogit>>#genExternalizePointersForPrimitiveCall */ static sqInt genExternalizePointersForPrimitiveCall(void) { sqInt address; sqInt address1; sqInt address4; genPushRegisterArgs(); /* begin MoveR:Aw: */ address4 = framePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address4, genoperandoperand(MoveRAw, FPReg, address4)); /* Set coInterpreter stackPointer to the topmost argument, skipping the return address. */ /* begin MoveR:Aw: */ address = stackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, SPReg, address)); /* begin MoveR:Aw: */ address1 = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, LinkReg, address1)); return 0; } /* Block compilation. At this point in the method create the block. Note its start and defer generating code for it until after the method and any other preceding blocks. The block's actual code will be compiled later. */ /* 253 11111101 eei i i kkk jjjjjjjj Push Closure Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8) BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions */ /* StackToRegisterMappingCogit>>#genExtPushClosureBytecode */ static sqInt genExtPushClosureBytecode(void) { sqInt i; sqInt numArgs; sqInt numCopied; sqInt reg; sqInt startpc; assert(needsFrame); startpc = bytecodePC + (((generatorAt(byte0))->numBytes)); addBlockStartAtnumArgsnumCopiedspan(startpc, (numArgs = (byte1 & 7) + ((extA % 16) * 8)), (numCopied = ((((usqInt) byte1) >> 3) & 7) + ((extA / 16) * 8)), byte2 + (((sqInt)((usqInt)(extB) << 8)))); extA = (numExtB = (extB = 0)); /* begin genInlineClosure:numArgs:numCopied: */ assert(getActiveContextAllocatesInMachineCode()); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(startpc + 1, numArgs, numCopied, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (ClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } ssPushRegister(ReceiverResultReg); return 0; } /* Full Block creation compilation. The block's actual code will be compiled separatedly. */ /* * 255 11111111 xxxxxxxx siyyyyyy push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1 */ /* StackToRegisterMappingCogit>>#genExtPushFullClosureBytecode */ static sqInt genExtPushFullClosureBytecode(void) { sqInt compiledBlock; sqInt i; int ignoreContext; sqInt numCopied; int receiverIsOnStack; sqInt reg; assert(needsFrame); compiledBlock = getLiteral(byte1 + (((sqInt)((usqInt)(extA) << 8)))); extA = 0; numCopied = byte2 & ((1U << 6) - 1); receiverIsOnStack = byte2 & (1U << 7); ignoreContext = byte2 & (1U << 6); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(compiledBlock, argumentCountOf(compiledBlock), numCopied, ignoreContext, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (FullClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } if (receiverIsOnStack) { reg = ssStorePoptoPreferredReg(1, TempReg); } else { storeToReg(simSelf(), (reg = TempReg)); } genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, FullClosureReceiverIndex, ReceiverResultReg); ssPushRegister(ReceiverResultReg); return 0; } /* 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. */ /* StackToRegisterMappingCogit>>#generateEnilopmarts */ static void generateEnilopmarts(void) { # if Debug /* begin genEnilopmartFor:forCall:called: */ realCEEnterCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 0, "realCEEnterCogCodePopReceiverReg"); ceEnterCogCodePopReceiverReg = enterCogCodePopReceiver; /* begin genEnilopmartFor:forCall:called: */ realCECallCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 1, "realCEEnterCogCodePopReceiverReg"); ceCallCogCodePopReceiverReg = callCogCodePopReceiver; /* begin genEnilopmartFor:and:forCall:called: */ realCECallCogCodePopReceiverAndClassRegs = genEnilopmartForandandforCallcalled(ReceiverResultReg, ClassReg, NoReg, 1, "realCECallCogCodePopReceiverAndClassRegs"); ceCallCogCodePopReceiverAndClassRegs = callCogCodePopReceiverAndClassRegs; # else /* Debug */ /* begin genEnilopmartFor:forCall:called: */ ceEnterCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 0, "ceEnterCogCodePopReceiverReg"); /* begin genEnilopmartFor:forCall:called: */ ceCallCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 1, "ceCallCogCodePopReceiverReg"); /* begin genEnilopmartFor:and:forCall:called: */ ceCallCogCodePopReceiverAndClassRegs = genEnilopmartForandandforCallcalled(ReceiverResultReg, ClassReg, NoReg, 1, "ceCallCogCodePopReceiverAndClassRegs"); # endif /* Debug */ genPrimReturnEnterCogCodeEnilopmart(0); cePrimReturnEnterCogCode = methodZoneBase; outputInstructionsForGeneratedRuntimeAt(cePrimReturnEnterCogCode); recordGeneratedRunTimeaddress("cePrimReturnEnterCogCode", cePrimReturnEnterCogCode); genPrimReturnEnterCogCodeEnilopmart(1); cePrimReturnEnterCogCodeProfiling = methodZoneBase; outputInstructionsForGeneratedRuntimeAt(cePrimReturnEnterCogCodeProfiling); recordGeneratedRunTimeaddress("cePrimReturnEnterCogCodeProfiling", cePrimReturnEnterCogCodeProfiling); # if Debug /* begin genEnilopmartFor:and:forCall:called: */ realCECallCogCodePopReceiverArg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, NoReg, 1, "realCECallCogCodePopReceiverArg0Regs"); ceCallCogCodePopReceiverArg0Regs = callCogCodePopReceiverArg0Regs; realCECallCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, 1, "realCECallCogCodePopReceiverArg1Arg0Regs"); ceCallCogCodePopReceiverArg1Arg0Regs = callCogCodePopReceiverArg1Arg0Regs; # else /* Debug */ /* begin genEnilopmartFor:and:forCall:called: */ ceCallCogCodePopReceiverArg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, NoReg, 1, "ceCallCogCodePopReceiverArg0Regs"); ceCallCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, 1, "ceCallCogCodePopReceiverArg1Arg0Regs"); # endif /* Debug */ ceCall0ArgsPIC = genCallPICEnilopmartNumArgs(0); ceCall1ArgsPIC = genCallPICEnilopmartNumArgs(1); ceCall2ArgsPIC = genCallPICEnilopmartNumArgs(2); assert((numRegArgs()) == 2); } /* Size pc-dependent instructions and assign eventual addresses to all instructions. Answer the size of the code. Compute forward branches based on virtual address (abstract code starts at 0), assuming that any branches branched over are long. Compute backward branches based on actual address. Reuse the fixups array to record the pc-dependent instructions that need to have their code generation postponed until after the others. Override to andd handling for null branches (branches to the immediately following instruction) occasioned by StackToRegisterMapping's following of jumps. */ /* StackToRegisterMappingCogit>>#generateInstructionsAt: */ static sqInt NoDbgRegParms generateInstructionsAt(sqInt eventualAbsoluteAddress) { sqInt absoluteAddress; AbstractInstruction *abstractInstruction; BytecodeFixup *fixup; sqInt i; sqInt j; sqInt pcDependentIndex; absoluteAddress = eventualAbsoluteAddress; pcDependentIndex = 0; for (i = 0; i < opcodeIndex; i += 1) { maybeBreakGeneratingAt(absoluteAddress); abstractInstruction = abstractInstructionAt(i); if (isPCDependent(abstractInstruction)) { sizePCDependentInstructionAt(abstractInstruction, absoluteAddress); if ((isJump(abstractInstruction)) && ((((i + 1) < opcodeIndex) && ((((AbstractInstruction *) (((abstractInstruction->operands))[0]))) == (abstractInstructionAt(i + 1)))) || (((i + 2) < opcodeIndex) && (((((AbstractInstruction *) (((abstractInstruction->operands))[0]))) == (abstractInstructionAt(i + 2))) && ((((abstractInstructionAt(i + 1))->opcode)) == Nop))))) { (abstractInstruction->opcode = Nop); concretizeAt(abstractInstruction, absoluteAddress); } else { fixup = fixupAtIndex(pcDependentIndex); pcDependentIndex += 1; (fixup->instructionIndex = i); } absoluteAddress += (abstractInstruction->machineCodeSize); } else { absoluteAddress = concretizeAt(abstractInstruction, absoluteAddress); } } for (j = 0; j < pcDependentIndex; j += 1) { fixup = fixupAtIndex(j); abstractInstruction = abstractInstructionAt((fixup->instructionIndex)); maybeBreakGeneratingAt((abstractInstruction->address)); concretizeAt(abstractInstruction, (abstractInstruction->address)); } return absoluteAddress - eventualAbsoluteAddress; } /* Generate the run-time entries for the various method and PIC entry misses and aborts. Read the class-side method trampolines for documentation on the various trampolines */ /* StackToRegisterMappingCogit>>#generateMissAbortTrampolines */ static void generateMissAbortTrampolines(void) { sqInt numArgs; sqInt numArgsLimiT; for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { methodAbortTrampolines[numArgs] = (genMethodAbortTrampolineFor(numArgs)); } for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { picAbortTrampolines[numArgs] = (genPICAbortTrampolineFor(numArgs)); } for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { picMissTrampolines[numArgs] = (genPICMissTrampolineFor(numArgs)); } ceReapAndResetErrorCodeTrampoline = genTrampolineForcalledarg(ceReapAndResetErrorCodeFor, "ceReapAndResetErrorCodeTrampoline", ClassReg); } /* Override to generate code to push the register arg(s) for <= numRegArg arity sends. */ /* StackToRegisterMappingCogit>>#generateSendTrampolines */ static void generateSendTrampolines(void) { sqInt numArgs; for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { ordinarySendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSend", numArgs), ClassReg, trampolineArgConstant(0), ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { directedSuperSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendabovetonumArgs, numArgs, trampolineNamenumArgs("ceDirectedSuperSend", numArgs), ClassReg, TempReg, ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); directedSuperBindingSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendaboveClassBindingtonumArgs, numArgs, trampolineNamenumArgs("ceDirectedSuperBindingSend", numArgs), ClassReg, TempReg, ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { superSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSuperSend", numArgs), ClassReg, trampolineArgConstant(1), ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } firstSend = ordinarySendTrampolines[0]; lastSend = superSendTrampolines[NumSendTrampolines - 1]; } /* Generate trampolines for tracing. In the simulator we can save a lot of time and avoid noise instructions in the lastNInstructions log by short-cutting these trampolines, but we need them in the real vm. */ /* StackToRegisterMappingCogit>>#generateTracingTrampolines */ static void generateTracingTrampolines(void) { ceTraceLinkedSendTrampoline = genTrampolineForcalledargregsToSave(ceTraceLinkedSend, "ceTraceLinkedSendTrampoline", ReceiverResultReg, CallerSavedRegisterMask); ceTraceBlockActivationTrampoline = genTrampolineForcalledregsToSave(ceTraceBlockActivation, "ceTraceBlockActivationTrampoline", CallerSavedRegisterMask); ceTraceStoreTrampoline = genTrampolineForcalledargargregsToSave(ceTraceStoreOfinto, "ceTraceStoreTrampoline", TempReg, ReceiverResultReg, CallerSavedRegisterMask); } /* StackToRegisterMappingCogit>>#genForwardersInlinedIdenticalOrNotIf: */ static sqInt NoDbgRegParms genForwardersInlinedIdenticalOrNotIf(sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt argReg; sqInt argReg1; BytecodeDescriptor *branchDescriptor; BytecodeDescriptor *branchDescriptor1; sqInt constant; sqInt constant1; BytecodeFixup * fixup; sqInt i; void *jumpTarget; void *jumpTarget1; AbstractInstruction *label; sqInt nExts; sqInt nextPC; sqInt nextPC1; sqInt postBranchPC; sqInt postBranchPC1; BytecodeDescriptor *primDescriptor; sqInt rcvrReg; sqInt rcvrReg1; sqInt reg; sqInt rNext1; sqInt rTop1; sqInt targetBytecodePC; sqInt targetBytecodePC1; sqInt topRegistersMask; int unforwardArg; int unforwardRcvr; /* begin extractMaybeBranchDescriptorInto: */ primDescriptor = generatorAt(byte0); nextPC1 = bytecodePC + ((primDescriptor->numBytes)); nExts = 0; while (1) { while (1) { /* begin generatorForPC: */ branchDescriptor1 = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC1, methodObj))); if (!((branchDescriptor1->isExtension))) break; nExts += 1; nextPC1 += (branchDescriptor1->numBytes); } /* begin isUnconditionalBranch */ if (!((isBranch(branchDescriptor1)) && (!(((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse)))))) break; nextPC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); } targetBytecodePC1 = (postBranchPC1 = 0); if (((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse))) { targetBytecodePC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); postBranchPC1 = eventualTargetOf(nextPC1 + ((branchDescriptor1->numBytes))); } else { nextPC1 = bytecodePC + ((primDescriptor->numBytes)); } branchDescriptor = branchDescriptor1; nextPC = nextPC1; postBranchPC = postBranchPC1; targetBytecodePC = targetBytecodePC1; unforwardRcvr = !(isUnannotatableConstant(ssValue(1))); unforwardArg = !(isUnannotatableConstant(ssTop())); /* begin allocateEqualsEqualsRegistersArgNeedsReg:rcvrNeedsReg:into: */ assert(unforwardArg || (unforwardRcvr)); argReg1 = (rcvrReg1 = NoReg); if (unforwardArg) { if (unforwardRcvr) { /* begin allocateRegForStackTopTwoEntriesInto: */ topRegistersMask = 0; rTop1 = (rNext1 = NoReg); if ((registerOrNone(ssTop())) != NoReg) { rTop1 = registerOrNone(ssTop()); } if ((registerOrNone(ssValue(1))) != NoReg) { /* begin registerMaskFor: */ reg = (rNext1 = registerOrNone(ssValue(1))); topRegistersMask = 1U << reg; } if (rTop1 == NoReg) { rTop1 = allocateRegNotConflictingWith(topRegistersMask); } if (rNext1 == NoReg) { rNext1 = allocateRegNotConflictingWith(1U << rTop1); } assert(!(((rTop1 == NoReg) || (rNext1 == NoReg)))); argReg1 = rTop1; rcvrReg1 = rNext1; popToReg(ssTop(), argReg1); popToReg(ssValue(1), rcvrReg1); } else { argReg1 = allocateRegForStackEntryAtnotConflictingWith(0, 0); popToReg(ssTop(), argReg1); if (((ssValue(1))->spilled)) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(BytesPerWord)); } } } } else { assert(unforwardRcvr); assert(!((((ssTop())->spilled)))); rcvrReg1 = allocateRegForStackEntryAtnotConflictingWith(1, 0); popToReg(ssValue(1), rcvrReg1); } assert(!((unforwardArg && (argReg1 == NoReg)))); assert(!((unforwardRcvr && (rcvrReg1 == NoReg)))); rcvrReg = rcvrReg1; argReg = argReg1; if (!(((branchDescriptor->isBranchTrue)) || ((branchDescriptor->isBranchFalse)))) { return genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(!unforwardArg, !unforwardRcvr, argReg, rcvrReg, orNot); } /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } /* begin Label */ label = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin genCmpArgIsConstant:rcvrIsConstant:argReg:rcvrReg: */ assert((argReg != NoReg) || (rcvrReg != NoReg)); if (!unforwardArg) { /* begin genCmpConstant:R: */ constant = ((ssTop())->constant); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(checkLiteralforInstruction(constant, genoperandoperand(CmpCwR, constant, rcvrReg)), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, constant, rcvrReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } } else { if (!unforwardRcvr) { /* begin genCmpConstant:R: */ constant1 = ((ssValue(1))->constant); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(checkLiteralforInstruction(constant1, genoperandoperand(CmpCwR, constant1, argReg)), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, constant1, argReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, argReg, rcvrReg); } } ssPop(2); if ((((fixupAt(nextPC))->targetInstruction)) == 0) { /* The next instruction is dead. we can skip it. */ deadCode = 1; ensureFixupAt(targetBytecodePC); ensureFixupAt(postBranchPC); } else { assert(!(deadCode)); } assert(unforwardArg || (unforwardRcvr)); if (orNot == ((branchDescriptor->isBranchTrue))) { /* a == b ifFalse: ... or a ~~ b ifTrue: ... jump on equal to post-branch pc */ fixup = ensureNonMergeFixupAt(targetBytecodePC); /* begin JumpZero: */ jumpTarget = ensureNonMergeFixupAt(postBranchPC); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget)); } else { /* orNot is true for ~~ */ /* a == b ifTrue: ... or a ~~ b ifFalse: ... jump on equal to target pc */ fixup = ensureNonMergeFixupAt(postBranchPC); /* begin JumpZero: */ jumpTarget1 = ensureNonMergeFixupAt(targetBytecodePC); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget1)); } if (unforwardArg && (unforwardRcvr)) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(argReg, TempReg, label, 0); } genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder((unforwardRcvr ? rcvrReg : argReg), TempReg, label, fixup); if (!deadCode) { ssPushConstant(trueObject()); } return 0; } /* Generates the machine code for #== in the case where the instruction is not followed by a branch */ /* StackToRegisterMappingCogit>>#genIdenticalNoBranchArgIsConstant:rcvrIsConstant:argReg:rcvrReg:orNotIf: */ static sqInt NoDbgRegParms genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(sqInt argIsConstant, sqInt rcvrIsConstant, sqInt argReg, sqInt rcvrRegOrNone, sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; sqInt constant; sqInt constant1; sqInt constant11; sqInt constant2; sqInt constant3; sqInt constant4; AbstractInstruction *jumpEqual; AbstractInstruction *jumpNotEqual; AbstractInstruction *label; sqInt resultReg; /* begin Label */ label = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin genCmpArgIsConstant:rcvrIsConstant:argReg:rcvrReg: */ assert((argReg != NoReg) || (rcvrRegOrNone != NoReg)); if (argIsConstant) { /* begin genCmpConstant:R: */ constant4 = ((ssTop())->constant); if (shouldAnnotateObjectReference(constant4)) { annotateobjRef(checkLiteralforInstruction(constant4, genoperandoperand(CmpCwR, constant4, rcvrRegOrNone)), constant4); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, constant4, rcvrRegOrNone); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant4)); } } } else { if (rcvrIsConstant) { /* begin genCmpConstant:R: */ constant11 = ((ssValue(1))->constant); if (shouldAnnotateObjectReference(constant11)) { annotateobjRef(checkLiteralforInstruction(constant11, genoperandoperand(CmpCwR, constant11, argReg)), constant11); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, constant11, argReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant11)); } } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, argReg, rcvrRegOrNone); } } ssPop(2); resultReg = (rcvrRegOrNone == NoReg ? argReg : rcvrRegOrNone); /* begin JumpZero: */ jumpEqual = genConditionalBranchoperand(JumpZero, ((sqInt)0)); if (!argIsConstant) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(argReg, TempReg, label, 0); } if (!rcvrIsConstant) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(rcvrRegOrNone, TempReg, label, 0); } if (orNot) { /* begin genMoveTrueR: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, resultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, constant, resultReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(constant)); } } } else { /* begin genMoveFalseR: */ constant1 = falseObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gMoveCwR(constant1, resultReg), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(MoveCqR, constant1, resultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(constant1)); } } } /* begin Jump: */ jumpNotEqual = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpEqual, (orNot ? (/* begin genMoveFalseR: */ (constant2 = falseObject()), (shouldAnnotateObjectReference(constant2) ? annotateobjRef(gMoveCwR(constant2, resultReg), constant2) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction4 = genoperandoperand(MoveCqR, constant2, resultReg)), (usesOutOfLineLiteral(anInstruction4) ? (anInstruction4->dependent = locateLiteral(constant2)) : 0), anInstruction4))) : (/* begin genMoveTrueR: */ (constant3 = trueObject()), (shouldAnnotateObjectReference(constant3) ? annotateobjRef(gMoveCwR(constant3, resultReg), constant3) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction5 = genoperandoperand(MoveCqR, constant3, resultReg)), (usesOutOfLineLiteral(anInstruction5) ? (anInstruction5->dependent = locateLiteral(constant3)) : 0), anInstruction5))))); jmpTarget(jumpNotEqual, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); ssPushRegister(resultReg); return 0; } /* Decompose code generation for #== into a common constant-folding version, followed by a double dispatch throguh the objectRepresentation to a version that doesn't deal with forwarders and a version that does. */ /* StackToRegisterMappingCogit>>#genInlinedIdenticalOrNotIf: */ static sqInt NoDbgRegParms genInlinedIdenticalOrNotIf(sqInt orNot) { BytecodeDescriptor *primDescriptor; sqInt result; primDescriptor = generatorAt(byte0); if ((isUnannotatableConstant(ssTop())) && (isUnannotatableConstant(ssValue(1)))) { assert(!((primDescriptor->isMapped))); result = ((orNot ? (((ssTop())->constant)) != (((ssValue(1))->constant)) : (((ssTop())->constant)) == (((ssValue(1))->constant))) ? trueObject() : falseObject()); ssPop(2); return ssPushConstant(result); } /* begin genInlinedIdenticalOrNotIfGuts: */ return genForwardersInlinedIdenticalOrNotIf(orNot); } /* StackToRegisterMappingCogit>>#genJumpBackTo: */ static sqInt NoDbgRegParms genJumpBackTo(sqInt targetBytecodePC) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; sqInt address; sqInt i; void *jumpTarget; void *jumpTarget1; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* can't fall through */ deadCode = 1; /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpAboveOrEqual: */ jumpTarget = fixupAtIndex(targetBytecodePC - initialPC); genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)jumpTarget)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceCheckForInterruptTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin annotateBytecode: */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction1->annotation = HasBytecodePC); /* begin Jump: */ jumpTarget1 = fixupAtIndex(targetBytecodePC - initialPC); genoperand(Jump, ((sqInt)jumpTarget1)); return 0; } /* StackToRegisterMappingCogit>>#genJumpIf:to: */ static sqInt NoDbgRegParms genJumpIfto(sqInt boolean, sqInt targetBytecodePC) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; CogSimStackEntry *desc; sqInt eventualTarget; BytecodeFixup *fixup; sqInt i; void *jumpTarget; AbstractInstruction *ok; sqInt quickConstant; eventualTarget = eventualTargetOf(targetBytecodePC); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 1)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 1)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 1))); i < simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 1) + 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 annotate the bytecode for correct pc mapping. */ fixup = ensureFixupAt(eventualTarget); /* begin annotateBytecode: */ if (((desc->constant)) == boolean) { /* begin Jump: */ abstractInstruction = genoperand(Jump, ((sqInt)fixup)); } else { if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } } (abstractInstruction->annotation = HasBytecodePC); extA = 0; return 0; } popToReg(desc, TempReg); assert((objectAfter(falseObject())) == (trueObject())); /* begin genSubConstant:R: */ if (shouldAnnotateObjectReference(boolean)) { annotateobjRef(gSubCwR(boolean, TempReg), TempReg); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, boolean, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(boolean)); } } /* begin JumpZero: */ jumpTarget = ensureFixupAt(eventualTarget); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget)); if (extA & 1) { extA = 0; /* begin annotateBytecode: */ abstractInstruction1 = lastOpcode(); (abstractInstruction1->annotation = HasBytecodePC); return 0; } extA = 0; /* begin CmpCq:R: */ quickConstant = (boolean == (falseObject()) ? (trueObject()) - (falseObject()) : (falseObject()) - (trueObject())); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpZero: */ ok = genConditionalBranchoperand(JumpZero, ((sqInt)0)); genCallMustBeBooleanFor(boolean); jmpTarget(ok, annotateBytecode(genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* StackToRegisterMappingCogit>>#genJumpTo: */ static sqInt NoDbgRegParms genJumpTo(sqInt targetBytecodePC) { sqInt eventualTarget; BytecodeFixup * fixup; BytecodeDescriptor * generator; sqInt i; sqInt i1; eventualTarget = eventualTargetOf(targetBytecodePC); if ((eventualTarget > bytecodePC) && (((simStackPtr >= methodOrBlockNumArgs) && (stackEntryIsBoolean(ssTop()))) && ((((generator = generatorForPC(eventualTarget))->isBranchTrue)) || (((generator = generatorForPC(eventualTarget))->isBranchFalse))))) { eventualTarget = (eventualTarget + ((generator->numBytes))) + ((((generator->isBranchTrue)) == ((((ssTop())->constant)) == (trueObject())) ? (/* begin spanFor:at:exts:in: */ ((generator->spanFunction))(generator, eventualTarget, 0, methodObj)) : 0)); ssPop(1); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } fixup = ensureFixupAt(eventualTarget); ssPop(-1); } else { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } fixup = ensureFixupAt(eventualTarget); } /* can't fall through */ deadCode = 1; /* begin Jump: */ genoperand(Jump, ((sqInt)fixup)); return 0; } /* StackToRegisterMappingCogit>>#genMarshalledSend:numArgs:sendTable: */ static sqInt NoDbgRegParms genMarshalledSendnumArgssendTable(sqInt selectorIndex, sqInt numArgs, sqInt *sendTable) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt annotation; assert(needsFrame); /* begin annotationForSendTable: */ if (sendTable == ordinarySendTrampolines) { annotation = IsSendCall; goto l2; } if (sendTable == directedSuperSendTrampolines) { annotation = IsDirectedSuperSend; goto l2; } if (sendTable == directedSuperBindingSendTrampolines) { annotation = IsDirectedSuperBindingSend; goto l2; } assert(sendTable == superSendTrampolines); annotation = IsSuperSend; l2: /* end annotationForSendTable: */; if ((annotation == IsSuperSend) || (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend)))) { genEnsureOopInRegNotForwardedscratchReg(ReceiverResultReg, TempReg); } if (numArgs >= (NumSendTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, numArgs, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(numArgs)); } } if (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend))) { /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(tempOop)) { annotateobjRef(gMoveCwR(tempOop, TempReg), tempOop); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, tempOop, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(tempOop)); } } } genLoadInlineCacheWithSelector(selectorIndex); ((genoperand(Call, sendTable[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]))->annotation = annotation); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); 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 stack overflow. It distinguishes the two by testing ResultReceiverReg. If the register is zero then this is a stack-overflow because a) the receiver has already been pushed and so can be set to zero before calling the abort, and b) the receiver must always contain an object (and hence be non-zero) on SIC miss. */ /* StackToRegisterMappingCogit>>#genMethodAbortTrampolineFor: */ static sqInt NoDbgRegParms genMethodAbortTrampolineFor(sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpSICMiss; zeroOpcodeIndex(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpSICMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveR:Mw:r: */ anInstruction = genoperandoperandoperand(MoveRMwr, LinkReg, 0, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceStackOverflow, 1, SendNumArgsReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg); jmpTarget(jumpSICMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genPushRegisterArgsForAbortMissNumArgs(backEnd, numArgs); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceSICMiss, trampolineNamenumRegArgs("ceMethodAbort", numArgs), 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Generate the abort for a PIC. This abort performs either a call of ceInterpretMethodFromPIC:receiver: to handle invoking an uncogged target or a call of ceMNUFromPICMNUMethod:receiver: to handle an MNU dispatch in a closed PIC. It distinguishes the two by testing ClassReg. If the register is zero then this is an MNU. */ /* StackToRegisterMappingCogit>>#genPICAbortTrampolineFor: */ static sqInt NoDbgRegParms genPICAbortTrampolineFor(sqInt numArgs) { zeroOpcodeIndex(); genPushRegisterArgsForAbortMissNumArgs(backEnd, numArgs); return genInnerPICAbortTrampoline(trampolineNamenumRegArgs("cePICAbort", numArgs)); } /* StackToRegisterMappingCogit>>#genPICMissTrampolineFor: */ static sqInt NoDbgRegParms genPICMissTrampolineFor(sqInt numArgs) { sqInt startAddress; startAddress = methodZoneBase; zeroOpcodeIndex(); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceCPICMissreceiver, trampolineNamenumRegArgs("cePICMiss", numArgs), 2, ClassReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); return startAddress; } /* StackToRegisterMappingCogit>>#genPopStackBytecode */ static sqInt genPopStackBytecode(void) { AbstractInstruction *anInstruction; if (((ssTop())->spilled)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BytesPerWord)); } } ssPop(1); return 0; } /* 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. */ /* 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. */ /* StackToRegisterMappingCogit>>#genPrimitiveClosureValue */ static sqInt genPrimitiveClosureValue(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpFail1; AbstractInstruction *jumpFail2; AbstractInstruction *jumpFail3; AbstractInstruction *jumpFail4; AbstractInstruction *jumpFailNArgs; sqInt literal; sqInt offset; void (*primitiveRoutine)(); sqInt quickConstant; sqInt result; genPushRegisterArgs(); genLoadSlotsourceRegdestReg(ClosureNumArgsIndex, ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)methodOrBlockNumArgs << 1) | 1); anInstruction1 = genoperandoperand(CmpCqR, (((usqInt)methodOrBlockNumArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpFailNArgs = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, ClassReg); jumpFail1 = genJumpImmediate(ClassReg); genGetCompactClassIndexNonImmOfinto(ClassReg, TempReg); genCmpClassMethodContextCompactIndexR(TempReg); /* begin JumpNonZero: */ jumpFail2 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(MethodIndex, ClassReg, SendNumArgsReg); jumpFail3 = genJumpImmediate(SendNumArgsReg); genGetFormatOfinto(SendNumArgsReg, TempReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpFail4 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); /* begin MoveM16:r:R: */ offset = offsetof(CogMethod, blockEntryOffset); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveM16rR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(offset)); } /* begin AddR:R: */ genoperandoperand(AddRR, ClassReg, TempReg); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); if (primitiveRoutine == primitiveClosureValueNoContextSwitch) { if (blockNoContextSwitchOffset == null) { return NotFullyInitialized; } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, blockNoContextSwitchOffset, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(blockNoContextSwitchOffset)); } } /* begin JumpR: */ genoperand(JumpR, TempReg); jmpTarget(jumpBCMethod, jmpTarget(jumpFail1, jmpTarget(jumpFail2, jmpTarget(jumpFail3, jmpTarget(jumpFail4, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); if (((result = compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)))) < 0) { return result; } jmpTarget(jumpFailNArgs, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* 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. */ /* StackToRegisterMappingCogit>>#genPrimitiveFullClosureValue */ static sqInt genPrimitiveFullClosureValue(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpFail4; AbstractInstruction *jumpFailImmediateMethod; AbstractInstruction *jumpFailNArgs; sqInt literal; void (*primitiveRoutine)(); sqInt quickConstant; sqInt quickConstant1; sqInt result; genPushRegisterArgs(); genLoadSlotsourceRegdestReg(ClosureNumArgsIndex, ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)methodOrBlockNumArgs << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)methodOrBlockNumArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpFailNArgs = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(FullClosureCompiledBlockIndex, ReceiverResultReg, SendNumArgsReg); jumpFailImmediateMethod = genJumpImmediate(SendNumArgsReg); genGetFormatOfinto(SendNumArgsReg, TempReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpFail4 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); /* begin AddCq:R: */ quickConstant1 = (primitiveRoutine == primitiveFullClosureValueNoContextSwitch ? fullBlockNoContextSwitchEntryOffset() : fullBlockEntryOffset()); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant1, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpBCMethod, jmpTarget(jumpFailImmediateMethod, jmpTarget(jumpFail4, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (((result = compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)))) < 0) { return result; } jmpTarget(jumpFailNArgs, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* Generate an in-line perform primitive. The lookup code requires the selector to be in Arg0Reg. adjustArgumentsForPerform: adjusts the arguments once genLookupForPerformNumArgs: has generated the code for the lookup. */ /* StackToRegisterMappingCogit>>#genPrimitivePerform */ static sqInt genPrimitivePerform(void) { AbstractInstruction *anInstruction; sqInt offset; if (methodOrBlockNumArgs > 2 /* numRegArgs */) { /* begin MoveMw:r:R: */ offset = (methodOrBlockNumArgs - 1) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, SPReg, Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } return genLookupForPerformNumArgs(methodOrBlockNumArgs); } /* StackToRegisterMappingCogit>>#genPushActiveContextBytecode */ static sqInt genPushActiveContextBytecode(void) { assert(needsFrame); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genGetActiveContextNumArgslargeinBlock(methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); return ssPushRegister(ReceiverResultReg); } /* Block compilation. At this point in the method create the block. Note its start and defer generating code for it until after the method and any other preceding blocks. The block's actual code will be compiled later. */ /* 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii */ /* StackToRegisterMappingCogit>>#genPushClosureCopyCopiedValuesBytecode */ static sqInt genPushClosureCopyCopiedValuesBytecode(void) { sqInt i; sqInt numArgs; sqInt numCopied; sqInt reg; sqInt startpc; assert(needsFrame); startpc = bytecodePC + (((generatorAt(byte0))->numBytes)); addBlockStartAtnumArgsnumCopiedspan(startpc, (numArgs = byte1 & 15), (numCopied = ((usqInt) byte1) >> 4), (((sqInt)((usqInt)(byte2) << 8))) + byte3); /* begin genInlineClosure:numArgs:numCopied: */ assert(getActiveContextAllocatesInMachineCode()); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(startpc + 1, numArgs, numCopied, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (ClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } ssPushRegister(ReceiverResultReg); return 0; } /* <SmallInteger> */ /* Override to avoid the BytecodeSetHasDirectedSuperSend check, which is unnecessary here given the simulation stack. */ /* StackToRegisterMappingCogit>>#genPushLiteralIndex: */ static sqInt NoDbgRegParms genPushLiteralIndex(sqInt literalIndex) { sqInt literal; literal = getLiteral(literalIndex); return genPushLiteral(literal); } /* StackToRegisterMappingCogit>>#genPushLiteralVariable: */ static sqInt NoDbgRegParms genPushLiteralVariable(sqInt literalIndex) { AbstractInstruction *anInstruction; sqInt association; sqInt bcpc; BytecodeDescriptor *descriptor1; sqInt eA; sqInt eB; sqInt freeReg; sqInt savedB0; sqInt savedB1; sqInt savedB2; sqInt savedB3; sqInt savedEA; sqInt savedEB; sqInt savedNEB; /* If followed by a directed super send bytecode, avoid generating any code yet. The association will be passed to the directed send trampoline in a register and fully dereferenced only when first linked. It will be ignored in later sends. */ association = getLiteral(literalIndex); assert(!(directedSendUsesBinding)); /* begin nextDescriptorExtensionsAndNextPCInto: */ descriptor1 = generatorAt(byte0); savedB0 = byte0; savedB1 = byte1; savedB2 = byte2; savedB3 = byte3; savedEA = extA; savedEB = extB; savedNEB = numExtB; bcpc = bytecodePC + ((descriptor1->numBytes)); do { if (bcpc > endPC) { goto l1; } byte0 = (fetchByteofObject(bcpc, methodObj)) + bytecodeSetOffset; descriptor1 = generatorAt(byte0); loadSubsequentBytesForDescriptorat(descriptor1, bcpc); if (!((descriptor1->isExtension))) { eA = extA; eB = extB; extA = savedEA; extB = savedEB; numExtB = savedNEB; byte0 = savedB0; byte1 = savedB1; byte2 = savedB2; byte3 = savedB3; if ((descriptor1 != null) && ((((descriptor1->generator)) == genExtSendSuperBytecode) && (eB >= 64))) { ssPushConstant(association); directedSendUsesBinding = 1; return 0; } goto l1; } ((descriptor1->generator))(); bcpc += (descriptor1->numBytes); } while(1); l1: /* end nextDescriptorExtensionsAndNextPCInto: */; /* 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-of-evaluation issue if we defer the dereference. */ freeReg = allocateRegNotConflictingWith(0); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(association)) { annotateobjRef(gMoveCwR(association, TempReg), association); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, association, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(association)); } } genEnsureObjInRegNotForwardedscratchReg(TempReg, freeReg); genLoadSlotsourceRegdestReg(ValueIndex, TempReg, freeReg); ssPushRegister(freeReg); return 0; } /* StackToRegisterMappingCogit>>#genPushLiteral: */ static sqInt NoDbgRegParms genPushLiteral(sqInt literal) { return ssPushConstant(literal); } /* StackToRegisterMappingCogit>>#genPushMaybeContextReceiverVariable: */ static sqInt NoDbgRegParms genPushMaybeContextReceiverVariable(sqInt slotIndex) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmpDone; AbstractInstruction *jmpSingle; /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << ReceiverResultReg) | (1U << SendNumArgsReg)), simStackPtr, simNativeStackPtr); ensureReceiverResultRegContainsSelf(); /* begin genPushMaybeContextSlotIndex: */ assert(needsFrame); if (CallerSavedRegisterMask & (1U << ReceiverResultReg)) { /* We have no way of reloading ReceiverResultReg since we need the inst var value as the result. */ voidReceiverResultRegContainsSelf(); } if (slotIndex == InstructionPointerIndex) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceFetchContextInstVarTrampoline); (abstractInstruction->annotation = IsRelativeCall); return ssPushRegister(SendNumArgsReg); } genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); jmpSingle = genJumpNotSmallIntegerInScratchReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceFetchContextInstVarTrampoline); (abstractInstruction1->annotation = IsRelativeCall); /* begin Jump: */ jmpDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jmpSingle, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genLoadSlotsourceRegdestReg(slotIndex, ReceiverResultReg, SendNumArgsReg); jmpTarget(jmpDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return ssPushRegister(SendNumArgsReg); } /* StackToRegisterMappingCogit>>#genPushNewArrayBytecode */ static sqInt genPushNewArrayBytecode(void) { sqInt i; sqInt i1; int popValues; sqInt size; assert(needsFrame); voidReceiverResultRegContainsSelf(); if ((popValues = byte1 > 0x7F)) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } } else { /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << SendNumArgsReg) | (1U << ReceiverResultReg)), simStackPtr, simNativeStackPtr); } size = byte1 & 0x7F; if (!popValues) { if (tryCollapseTempVectorInitializationOfSize(size)) { return 0; } } genNewArrayOfSizeinitialized(size, !popValues); if (popValues) { for (i = (size - 1); i >= 0; i += -1) { /* begin PopR: */ genoperand(PopR, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(TempReg, i, ReceiverResultReg); } ssPop(size); } return ssPushRegister(ReceiverResultReg); } /* StackToRegisterMappingCogit>>#genPushReceiverBytecode */ static sqInt genPushReceiverBytecode(void) { if ((((simSelf())->liveRegister)) == ReceiverResultReg) { return ssPushRegister(ReceiverResultReg); } return ssPushDesc(ssSelfDescriptor()); } /* StackToRegisterMappingCogit>>#genPushReceiverVariable: */ static sqInt NoDbgRegParms genPushReceiverVariable(sqInt index) { ensureReceiverResultRegContainsSelf(); return ssPushBaseoffset(ReceiverResultReg, slotOffsetOfInstVarIndex(index)); } /* 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. */ /* StackToRegisterMappingCogit>>#genPushRegisterArgs */ static void genPushRegisterArgs(void) { if (!(regArgsHaveBeenPushed || (methodOrBlockNumArgs > 2 /* numRegArgs */))) { genPushRegisterArgsForNumArgsscratchReg(backEnd, methodOrBlockNumArgs, SendNumArgsReg); regArgsHaveBeenPushed = 1; } } /* StackToRegisterMappingCogit>>#genPushRemoteTempLongBytecode */ static sqInt genPushRemoteTempLongBytecode(void) { AbstractInstruction *anInstruction; sqInt offset; sqInt regMask; sqInt remoteTempReg; sqInt tempVectReg; tempVectReg = allocateRegNotConflictingWith(0); /* begin MoveMw:r:R: */ offset = frameOffsetOfTemporary(byte2); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, FPReg, tempVectReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin availableRegOrNoneNotConflictingWith: */ regMask = 1U << tempVectReg; remoteTempReg = availableRegisterOrNoneFor(backEnd, (liveRegisters()) | regMask); if (remoteTempReg == NoReg) { remoteTempReg = tempVectReg; } genLoadSlotsourceRegdestReg(byte1, tempVectReg, remoteTempReg); return ssPushRegister(remoteTempReg); } /* If a frameless method (not a block), only argument temps can be accessed. This is assured by the use of needsFrameIfMod16GENumArgs: in pushTemp. */ /* StackToRegisterMappingCogit>>#genPushTemporaryVariable: */ static sqInt NoDbgRegParms genPushTemporaryVariable(sqInt index) { assert((inBlock > 0) || (needsFrame || (index < methodOrBlockNumArgs))); return ssPushDesc(simStack[index + 1]); } /* In a frameless method ReceiverResultReg already contains self. In a frameful method, ReceiverResultReg /may/ contain self. */ /* StackToRegisterMappingCogit>>#genReturnReceiver */ static sqInt genReturnReceiver(void) { if (needsFrame) { if (!((((simSelf())->liveRegister)) == ReceiverResultReg)) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } } return genUpArrowReturn(); } /* StackToRegisterMappingCogit>>#genReturnTopFromBlock */ static sqInt genReturnTopFromBlock(void) { assert(inBlock > 0); popToReg(ssTop(), ReceiverResultReg); ssPop(1); return genBlockReturn(); } /* StackToRegisterMappingCogit>>#genReturnTopFromMethod */ static sqInt genReturnTopFromMethod(void) { popToReg(ssTop(), ReceiverResultReg); ssPop(1); return genUpArrowReturn(); } /* StackToRegisterMappingCogit>>#genSendDirectedSuper:numArgs: */ static sqInt NoDbgRegParms genSendDirectedSupernumArgs(sqInt selectorIndex, sqInt numArgs) { sqInt result; assert((((ssTop())->type)) == SSConstant); tempOop = ((ssTop())->constant); ssPop(1); marshallSendArguments(numArgs); result = genMarshalledSendnumArgssendTable(selectorIndex, numArgs, (directedSendUsesBinding ? directedSuperBindingSendTrampolines : directedSuperSendTrampolines)); directedSendUsesBinding = 0; return result; } /* StackToRegisterMappingCogit>>#genSendSuper:numArgs: */ static sqInt NoDbgRegParms genSendSupernumArgs(sqInt selectorIndex, sqInt numArgs) { marshallSendArguments(numArgs); return genMarshalledSendnumArgssendTable(selectorIndex, numArgs, superSendTrampolines); } /* Generate a trampoline with four arguments. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* StackToRegisterMappingCogit>>#genSendTrampolineFor:numArgs:called:arg:arg:arg:arg: */ static sqInt NoDbgRegParms genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3) { sqInt routine; sqInt startAddress; startAddress = methodZoneBase; zeroOpcodeIndex(); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); /* begin selectorIndexDereferenceRoutine */ routine = null; if (!(routine == null)) { /* begin Call: */ genoperand(Call, routine); } genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 4, regOrConst0, regOrConst1, regOrConst2, regOrConst3, 0 /* emptyRegisterMask */, 1, NoReg, 1); return startAddress; } /* StackToRegisterMappingCogit>>#genSend:numArgs: */ static sqInt NoDbgRegParms genSendnumArgs(sqInt selectorIndex, sqInt numArgs) { marshallSendArguments(numArgs); return genMarshalledSendnumArgssendTable(selectorIndex, numArgs, ordinarySendTrampolines); } /* StackToRegisterMappingCogit>>#genSpecialSelectorArithmetic */ static sqInt genSpecialSelectorArithmetic(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; sqInt argInt; int argIsConst; sqInt argIsInt; sqInt i; sqInt index; AbstractInstruction *jumpContinue; AbstractInstruction *jumpNotSmallInts; BytecodeDescriptor *primDescriptor; sqInt rcvrInt; int 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))) || ((mclassIsSmallInteger()) && (isSameEntryAs(ssValue(1), simSelf()))); if (argIsInt && (rcvrIsInt && (rcvrIsConst))) { 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)) { /* Must annotate the bytecode for correct pc mapping. */ return (ssPop(2), ssPushAnnotatedConstant((((usqInt)result << 1) | 1))); } return genSpecialSelectorSend(); } if ((rcvrIsConst && (!rcvrIsInt)) || (argIsConst && (!argIsInt))) { return genSpecialSelectorSend(); } if (!(argIsInt || (rcvrIsInt))) { return genSpecialSelectorSend(); } if (argIsInt) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } popToReg(ssValue(1), ReceiverResultReg); ssPop(2); } else { marshallSendArguments(1); } jumpNotSmallInts = (!(rcvrIsInt && (argIsInt)) ? (argIsInt ? genJumpNotSmallInteger(ReceiverResultReg) : (rcvrIsInt ? genJumpNotSmallInteger(Arg0Reg) : (/* begin genJumpNotSmallIntegersIn:and:scratch: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg), /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, TempReg), genJumpNotSmallIntegerInScratchReg(TempReg)))) : 0); switch ((primDescriptor->opcode)) { case AddRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(argInt - ConstZero)); } /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(argInt - ConstZero)); } } else { genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); if (rcvrIsInt && (rcvrIsConst)) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, rcvrInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(rcvrInt)); } } else { /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, ReceiverResultReg); genSetSmallIntegerTagsIn(ReceiverResultReg); } } break; case SubRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(argInt - ConstZero)); } /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(argInt - ConstZero)); } } else { genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, ReceiverResultReg); /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); genSetSmallIntegerTagsIn(Arg0Reg); } break; case AndRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AndCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(argInt)); } } else { /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, ReceiverResultReg); } jumpContinue = (!(jumpNotSmallInts == null) ? (/* begin Jump: */ genoperand(Jump, ((sqInt)0))) : 0); break; case OrRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(OrCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(argInt)); } } else { /* begin OrR:R: */ genoperandoperand(OrRR, Arg0Reg, ReceiverResultReg); } jumpContinue = (!(jumpNotSmallInts == null) ? (/* begin Jump: */ genoperand(Jump, ((sqInt)0))) : 0); break; default: error("Case not found and no otherwise clause"); } if (jumpNotSmallInts == null) { if (!(jumpContinue)) { /* overflow cannot happen */ /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); ssPushRegister(ReceiverResultReg); return 0; } } else { jmpTarget(jumpNotSmallInts, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(MoveCqR, argInt, Arg0Reg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(argInt)); } } index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); genMarshalledSendnumArgssendTable((-index) - 1, 1, ordinarySendTrampolines); jmpTarget(jumpContinue, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* StackToRegisterMappingCogit>>#genSpecialSelectorClass */ static sqInt genSpecialSelectorClass(void) { sqInt requiredReg1; sqInt topReg; topReg = registerOrNone(ssTop()); ssPop(1); if ((topReg == NoReg) || (topReg == ClassReg)) { /* begin ssAllocateRequiredReg:and: */ requiredReg1 = (topReg = SendNumArgsReg); ssAllocateRequiredRegMaskupThroughupThroughNative((1U << requiredReg1) | (1U << ClassReg), simStackPtr, simNativeStackPtr); } else { /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr, simNativeStackPtr); } ssPush(1); popToReg(ssTop(), topReg); genGetClassObjectOfintoscratchReginstRegIsReceiver(topReg, ClassReg, TempReg, 0); return (ssPop(1), ssPushRegister(ClassReg)); } /* StackToRegisterMappingCogit>>#genSpecialSelectorComparison */ static sqInt genSpecialSelectorComparison(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt argInt; sqInt argIsIntConst; BytecodeDescriptor *branchDescriptor; BytecodeDescriptor *branchDescriptor1; sqInt i; sqInt index; sqInt inlineCAB; AbstractInstruction *jumpNotSmallInts; void *jumpTarget; sqInt nExts; sqInt nextPC; sqInt nextPC1; sqInt postBranchPC; sqInt postBranchPC1; BytecodeDescriptor *primDescriptor; BytecodeDescriptor *primDescriptor1; int rcvrIsConst; sqInt rcvrIsInt; sqInt targetBytecodePC; sqInt targetPC; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } primDescriptor = generatorAt(byte0); argIsIntConst = ((((ssTop())->type)) == SSConstant) && ((((argInt = ((ssTop())->constant))) & 1)); rcvrIsInt = (((rcvrIsConst = (((ssValue(1))->type)) == SSConstant)) && (((((ssValue(1))->constant)) & 1))) || ((mclassIsSmallInteger()) && (isSameEntryAs(ssValue(1), simSelf()))); if (argIsIntConst && (rcvrIsInt && (rcvrIsConst))) { return genStaticallyResolvedSpecialSelectorComparison(); } /* begin extractMaybeBranchDescriptorInto: */ primDescriptor1 = generatorAt(byte0); nextPC1 = bytecodePC + ((primDescriptor1->numBytes)); nExts = 0; while (1) { while (1) { /* begin generatorForPC: */ branchDescriptor1 = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC1, methodObj))); if (!((branchDescriptor1->isExtension))) break; nExts += 1; nextPC1 += (branchDescriptor1->numBytes); } /* begin isUnconditionalBranch */ if (!((isBranch(branchDescriptor1)) && (!(((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse)))))) break; nextPC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); } targetBytecodePC = (postBranchPC1 = 0); if (((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse))) { targetBytecodePC = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); postBranchPC1 = eventualTargetOf(nextPC1 + ((branchDescriptor1->numBytes))); } else { nextPC1 = bytecodePC + ((primDescriptor1->numBytes)); } branchDescriptor = branchDescriptor1; nextPC = nextPC1; postBranchPC = postBranchPC1; targetPC = targetBytecodePC; /* Further, only interested in inlining = and ~= if there's a SmallInteger constant involved. The relational operators successfully statically predict SmallIntegers; the equality operators do not. */ inlineCAB = ((branchDescriptor->isBranchTrue)) || ((branchDescriptor->isBranchFalse)); if (inlineCAB && ((((primDescriptor->opcode)) == JumpZero) || (((primDescriptor->opcode)) == JumpNonZero))) { inlineCAB = argIsIntConst || (rcvrIsInt); } if (!inlineCAB) { return genSpecialSelectorSend(); } if (argIsIntConst) { popToReg(ssValue(1), ReceiverResultReg); ssPop(2); } else { marshallSendArguments(1); } jumpNotSmallInts = (!(rcvrIsInt && (argIsIntConst)) ? (argIsIntConst ? genJumpNotSmallInteger(ReceiverResultReg) : (rcvrIsInt ? genJumpNotSmallInteger(Arg0Reg) : (/* begin genJumpNotSmallIntegersIn:and:scratch: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg), /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, TempReg), genJumpNotSmallIntegerInScratchReg(TempReg)))) : 0); if (argIsIntConst) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(argInt)); } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); } genConditionalBranchoperand(((branchDescriptor->isBranchTrue) ? (primDescriptor->opcode) : inverseBranchFor((primDescriptor->opcode))), ((usqInt)(ensureNonMergeFixupAt(targetPC)))); /* begin Jump: */ jumpTarget = ensureNonMergeFixupAt(postBranchPC); genoperand(Jump, ((sqInt)jumpTarget)); if (!(jumpNotSmallInts)) { /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); ensureFixupAt(postBranchPC); ensureFixupAt(targetPC); deadCode = 1; return 0; } jmpTarget(jumpNotSmallInts, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (argIsIntConst) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, argInt, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(argInt)); } } index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); return genMarshalledSendnumArgssendTable((-index) - 1, 1, ordinarySendTrampolines); } /* Assumes both operands are ints */ /* StackToRegisterMappingCogit>>#genStaticallyResolvedSpecialSelectorComparison */ static sqInt genStaticallyResolvedSpecialSelectorComparison(void) { sqInt argInt; BytecodeDescriptor *primDescriptor; sqInt rcvrInt; int result; primDescriptor = generatorAt(byte0); argInt = ((ssTop())->constant); rcvrInt = ((ssValue(1))->constant); 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"); } ssPop(2); return ssPushAnnotatedConstant((result ? trueObject() : falseObject())); } /* We need a frame because the association has to be in ReceiverResultReg for the various trampolines and ReceiverResultReg holds only the receiver in frameless methods. */ /* StackToRegisterMappingCogit>>#genStorePop:LiteralVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt litVarIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { AbstractInstruction *anInstruction; sqInt association; sqInt i; sqInt topReg; assert(needsFrame); /* begin genLoadLiteralVariable:in: */ association = getLiteral(litVarIndex); voidReceiverResultRegContainsSelf(); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(association)) { annotateobjRef(gMoveCwR(association, ReceiverResultReg), association); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, association, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(association)); } } genEnsureObjInRegNotForwardedscratchReg(ReceiverResultReg, TempReg); /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ # if IMMUTABILITY if (needsImmCheck) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr - 1, simNativeStackPtr); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } return genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(ClassReg, ValueIndex, ReceiverResultReg, TempReg, needsStoreCheck, 0); } # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, ValueIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck); } /* The reason we need a frame here is that assigning to an inst var of a context may involve wholesale reorganization of stack pages, and the only way to preserve the execution state of an activation in that case is if it has a frame. */ /* StackToRegisterMappingCogit>>#genStorePop:MaybeContextReceiverVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt i; AbstractInstruction *immutabilityFailure; AbstractInstruction *mutableJump; immutabilityFailure = ((AbstractInstruction *) 0); assert(needsFrame); ssFlushUpThroughReceiverVariable(slotIndex); ensureReceiverResultRegContainsSelf(); /* begin genGenericStorePop:MaybeContextSlotIndex:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ assert(needsFrame); # if IMMUTABILITY if (needsImmCheck) { mutableJump = genJumpMutablescratchReg(ReceiverResultReg, TempReg); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (slotIndex >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, slotIndex, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction3->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[slotIndex]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); /* begin Jump: */ immutabilityFailure = genoperand(Jump, ((sqInt)0)); jmpTarget(mutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } # endif /* IMMUTABILITY */ ssPop(1); /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << ClassReg) | (1U << SendNumArgsReg)), simStackPtr, simNativeStackPtr); ssPush(1); genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreContextInstVarTrampoline); (abstractInstruction->annotation = IsRelativeCall); # if IMMUTABILITY if (needsImmCheck) { jmpTarget(immutabilityFailure, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } # endif /* IMMUTABILITY */ return 0; } /* StackToRegisterMappingCogit>>#genStorePop:ReceiverVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { sqInt i; sqInt needsImmCheck1; sqInt needsStoreCheck1; sqInt topReg; ssFlushUpThroughReceiverVariable(slotIndex); ensureReceiverResultRegContainsSelf(); /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ needsStoreCheck1 = (!useTwoPaths) && (needsStoreCheck); needsImmCheck1 = needsImmCheck && (!useTwoPaths); # if IMMUTABILITY if (needsImmCheck1) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr - 1, simNativeStackPtr); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } return genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(ClassReg, slotIndex, ReceiverResultReg, TempReg, needsStoreCheck1, 1); } # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, slotIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck1); } /* The only reason we assert needsFrame here is that in a frameless method ReceiverResultReg must and does contain only self, but the ceStoreCheck trampoline expects the target of the store to be in ReceiverResultReg. So in a frameless method we would have a conflict between the receiver and the temote temp store, unless we we smart enough to realise that ReceiverResultReg was unused after the literal variable store, unlikely given that methods return self by default. */ /* StackToRegisterMappingCogit>>#genStorePop:RemoteTemp:At:needsStoreCheck: */ static sqInt NoDbgRegParms genStorePopRemoteTempAtneedsStoreCheck(sqInt popBoolean, sqInt slotIndex, sqInt remoteTempIndex, sqInt needsStoreCheck) { AbstractInstruction *anInstruction; sqInt offset; sqInt topReg; assert(needsFrame); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); voidReceiverResultRegContainsSelf(); /* begin MoveMw:r:R: */ offset = frameOffsetOfTemporary(remoteTempIndex); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, FPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ # if IMMUTABILITY # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, slotIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck); } /* StackToRegisterMappingCogit>>#genStorePop:TemporaryVariable: */ static sqInt NoDbgRegParms genStorePopTemporaryVariable(sqInt popBoolean, sqInt tempIndex) { AbstractInstruction *anInstruction; sqInt offset; sqInt reg; ssFlushUpThroughTemporaryVariable(tempIndex); reg = ssStorePoptoPreferredReg(popBoolean, TempReg); /* begin MoveR:Mw:r: */ offset = frameOffsetOfTemporary(tempIndex); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, reg, offset, FPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } ((simStackAt(tempIndex + 1))->bcptr = bytecodePC); return 0; } /* Generate a method return from within a method or a block. Frameless method activation looks like CISCs (x86): receiver args sp-> ret pc. RISCs (ARM): receiver args ret pc in LR. A fully framed activation is described in CoInterpreter class>initializeFrameIndices. Return pops receiver and arguments off the stack. Callee pushes the result. */ /* StackToRegisterMappingCogit>>#genUpArrowReturn */ static sqInt genUpArrowReturn(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; sqInt i; sqInt offset; /* can't fall through */ deadCode = 1; if (inBlock > 0) { assert(needsFrame); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceNonLocalReturnTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin annotateBytecode: */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction1->annotation = HasBytecodePC); return 0; } if ( # if IMMUTABILITY needsFrame && (!useTwoPaths) # else /* IMMUTABILITY */ needsFrame # endif /* IMMUTABILITY */ ) { /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, SPReg); /* begin PopR: */ genoperand(PopR, FPReg); /* begin PopR: */ genoperand(PopR, LinkReg); /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } else { /* begin RetN: */ offset = ((methodOrBlockNumArgs > 2 /* numRegArgs */) || (regArgsHaveBeenPushed) ? (methodOrBlockNumArgs + 1) * BytesPerWord : 0); genoperand(RetN, offset); } return 0; } /* StackToRegisterMappingCogit>>#initSimStackForFramefulMethod: */ static void NoDbgRegParms initSimStackForFramefulMethod(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; /* N.B. Includes num args */ simStackPtr = methodOrBlockNumTemps; simSpillBase = methodOrBlockNumTemps + 1; cascade0 = simSelf(); (cascade0->type = SSBaseOffset); (cascade0->spilled = 1); (cascade0->registerr = FPReg); (cascade0->offset = FoxMFReceiver); (cascade0->liveRegister = NoReg); for (i = 1; i <= methodOrBlockNumArgs; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = FPReg); (desc->offset = FoxCallerSavedIP + (((methodOrBlockNumArgs - i) + 1) * BytesPerWord)); (desc->bcptr = startpc); } for (i = (methodOrBlockNumArgs + 1); i <= simStackPtr; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = FPReg); (desc->offset = FoxMFReceiver - ((i - methodOrBlockNumArgs) * BytesPerWord)); (desc->bcptr = startpc); } } /* The register receiver (the 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 ReceiverResultReg by the block entry. */ /* StackToRegisterMappingCogit>>#initSimStackForFramelessBlock: */ static void NoDbgRegParms initSimStackForFramelessBlock(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; cascade0 = simSelf(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = ReceiverResultReg); (cascade0->liveRegister = ReceiverResultReg); assert(methodOrBlockNumTemps >= methodOrBlockNumArgs); for (i = 1; i <= methodOrBlockNumTemps; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = SPReg); (desc->offset = (methodOrBlockNumArgs - i) * BytesPerWord); (desc->bcptr = startpc); } /* N.B. Includes num args */ simStackPtr = methodOrBlockNumTemps; simSpillBase = methodOrBlockNumTemps + 1; } /* StackToRegisterMappingCogit>>#initSimStackForFramelessMethod: */ static void NoDbgRegParms initSimStackForFramelessMethod(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; cascade0 = simSelf(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = ReceiverResultReg); (cascade0->liveRegister = ReceiverResultReg); assert(methodOrBlockNumTemps == methodOrBlockNumArgs); assert((numRegArgs()) <= 2); if (((methodOrBlockNumArgs >= 1) && (methodOrBlockNumArgs <= 2 /* numRegArgs */))) { desc = simStackAt(1); (desc->type = SSRegister); (desc->spilled = 0); (desc->registerr = Arg0Reg); (desc->bcptr = startpc); if (methodOrBlockNumArgs > 1) { desc = simStackAt(2); (desc->type = SSRegister); (desc->spilled = 0); (desc->registerr = Arg1Reg); (desc->bcptr = startpc); } } else { for (i = 1; i <= methodOrBlockNumArgs; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->registerr = SPReg); (desc->spilled = 1); (desc->offset = (methodOrBlockNumArgs - i) * BytesPerWord); (desc->bcptr = startpc); } } simStackPtr = methodOrBlockNumArgs; simSpillBase = methodOrBlockNumArgs + 1; } /* StackToRegisterMappingCogit>>#liveRegisters */ static sqInt liveRegisters(void) { sqInt i; sqInt regsSet; if (needsFrame) { regsSet = 0; } else { /* begin registerMaskFor: */ regsSet = 1U << ReceiverResultReg; if ((methodOrBlockNumArgs <= 2 /* numRegArgs */) && (methodOrBlockNumArgs > 0)) { regsSet = regsSet | (1U << Arg0Reg); if (methodOrBlockNumArgs > 1) { regsSet = regsSet | (1U << Arg1Reg); } } } for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= simStackPtr; i += 1) { regsSet = regsSet | (registerMask(simStackAt(i))); } return regsSet; } /* insert nops for dead code that is mapped so that bc to mc mapping is not many to one */ /* StackToRegisterMappingCogit>>#mapDeadDescriptorIfNeeded: */ static sqInt NoDbgRegParms mapDeadDescriptorIfNeeded(BytecodeDescriptor *descriptor) { AbstractInstruction *abstractInstruction; flag("annotateInstruction"); if (((descriptor->isMapped)) || ((inBlock > 0) && ((descriptor->isMappedInBlock)))) { /* begin annotateBytecode: */ abstractInstruction = gen(Nop); (abstractInstruction->annotation = HasBytecodePC); } 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. */ /* StackToRegisterMappingCogit>>#marshallSendArguments: */ static void NoDbgRegParms marshallSendArguments(sqInt numArgs) { sqInt anyRefs; CogSimStackEntry * cascade0; sqInt i; sqInt i1; sqInt i2; sqInt numSpilled; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= ((simStackPtr - numArgs) - 1)) { for (i2 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < ((simStackPtr - numArgs) - 1)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : ((simStackPtr - numArgs) - 1))); i2 < (simStackPtr - numArgs); i2 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i2), frameOffsetOfTemporary(i2 - 1), FPReg); } simSpillBase = ((simStackPtr - numArgs) - 1) + 1; } if (numArgs > 2 /* numRegArgs */) { /* If there are no spills and no references to ReceiverResultReg the fetch of ReceiverResultReg from the stack can be avoided by assigning directly to ReceiverResultReg and pushing it. */ numSpilled = numberOfSpillsInTopNItems(numArgs + 1); anyRefs = anyReferencesToRegisterinTopNItems(ReceiverResultReg, numArgs + 1); if ((numSpilled > 0) || (anyRefs)) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } storeToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); } else { cascade0 = simStackAt(simStackPtr - numArgs); storeToReg(cascade0, ReceiverResultReg); (cascade0->type = SSRegister); (cascade0->registerr = ReceiverResultReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } } } else { /* Move the args to the register arguments, being careful to do so last to first so e.g. previous contents don't get overwritten. Also check for any arg registers in use by other args. */ if (numArgs > 0) { if (numArgs > 1) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg0Reg, simStackPtr - 2, simNativeStackPtr); /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg1Reg, simStackPtr - 1, simNativeStackPtr); } else { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg0Reg, simStackPtr - 1, simNativeStackPtr); } } if (numArgs > 1) { popToReg(simStackAt(simStackPtr), Arg1Reg); } if (numArgs > 0) { popToReg(simStackAt((simStackPtr - numArgs) + 1), Arg0Reg); } popToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); } ssPop(numArgs + 1); } /* For assert checking; or rather for avoiding assert fails when dealing with the hack for block temps in the SqueakV3PlusClosures bytecode set. */ /* StackToRegisterMappingCogit>>#maybeCompilingFirstPassOfBlockWithInitialPushNil */ static sqInt maybeCompilingFirstPassOfBlockWithInitialPushNil(void) { return (inBlock == InVanillaBlock) && ((methodOrBlockNumTemps > methodOrBlockNumArgs) && (compilationPass == 1)); } /* If this bytecode has a fixup, some kind of merge needs to be done. There are 4 cases: 1) the bytecode has no fixup (fixup isNotAFixup) do nothing 2) the bytecode has a non merge fixup the fixup has needsNonMergeFixup. The code generating non merge fixup (currently only special selector code) is responsible for the merge so no need to do it. We set deadCode to false as the instruction can be reached from jumps. 3) the bytecode has a merge fixup, but execution flow *cannot* fall through to the merge point. the fixup has needsMergeFixup and deadCode = true. ignores the current simStack as it does not mean anything restores the simStack to the state the jumps to the merge point expects it to be. 4) the bytecode has a merge fixup and execution flow *can* fall through to the merge point. the fixup has needsMergeFixup and deadCode = false. flushes the stack to the stack pointer so the fall through execution path simStack is in the state the merge point expects it to be. restores the simStack to the state the jumps to the merge point expects it to be. In addition, if this is a backjump merge point, we patch the fixup to hold the current simStackPtr for later assertions. */ /* StackToRegisterMappingCogit>>#mergeWithFixupIfRequired: */ static sqInt NoDbgRegParms mergeWithFixupIfRequired(BytecodeFixup *fixup) { CogSimStackEntry * cascade0; sqInt i; sqInt i1; /* begin assertCorrectSimStackPtr */ assert((simSpillBase >= methodOrBlockNumTemps) || ((maybeCompilingFirstPassOfBlockWithInitialPushNil()) && (simSpillBase > methodOrBlockNumArgs))); if (needsFrame && (simSpillBase > 0)) { assert((((simStackAt(simSpillBase - 1))->spilled)) == 1); assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); } if (((fixup->targetInstruction)) == 0) { return 0; } if ((((usqInt)((fixup->targetInstruction)))) == NeedsNonMergeFixupFlag) { deadCode = 0; return 0; } assert(isMergeFixup(fixup)); traceMerge(fixup); if (deadCode) { /* case 3 */ /* Would like to assert fixup simStackPtr >= methodOrBlockNumTemps but can't because of the initialNils hack. */ assert((((fixup->simStackPtr)) >= methodOrBlockNumTemps) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); simStackPtr = (fixup->simStackPtr); } else { /* case 4 */ /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } } deadCode = 0; if ((fixup->isTargetOfBackwardBranch)) { (fixup->simStackPtr = simStackPtr); } (fixup->targetInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); assert(simStackPtr == ((fixup->simStackPtr))); /* begin restoreSimStackAtMergePoint: */ ((simSelf())->liveRegister = NoReg); for (i1 = (methodOrBlockNumTemps + 1); i1 <= simStackPtr; i1 += 1) { cascade0 = simStackAt(i1); (cascade0->type = SSSpill); (cascade0->offset = FoxMFReceiver - ((i1 - methodOrBlockNumArgs) * BytesPerOop)); (cascade0->registerr = FPReg); (cascade0->spilled = 1); } simSpillBase = simStackPtr + 1; return 0; } /* StackToRegisterMappingCogit>>#methodAbortTrampolineFor: */ static sqInt NoDbgRegParms methodAbortTrampolineFor(sqInt numArgs) { return methodAbortTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* This is a hook for subclasses to filter out methods they can't deal with. */ /* Frameless methods with local temporaries cause problems, mostly in asserts, and yet they matter not at all for performance. Shun them. */ /* StackToRegisterMappingCogit>>#methodFoundInvalidPostScan */ static sqInt methodFoundInvalidPostScan(void) { if (!needsFrame) { return methodOrBlockNumTemps > methodOrBlockNumArgs; } return 0; } /* StackToRegisterMappingCogit>>#needsFrameIfMod16GENumArgs: */ static sqInt NoDbgRegParms needsFrameIfMod16GENumArgs(sqInt stackDelta) { return (byte0 % 16) >= methodOrBlockNumArgs; } /* As of August 2013, the code generator can't deal with spills in frameless methods (the issue is to do with the stack offset to get at an argument, which is changed when there's a spill). In e.g. TextColor>>#dominates: other ^other class == self class the second send of class needs also rto allocate a register that the first one used, but the first one's register can't be spilled. So avoid this by only allowing class to be sent if the stack contains a single element. */ /* StackToRegisterMappingCogit>>#needsFrameIfStackGreaterThanOne: */ static sqInt NoDbgRegParms needsFrameIfStackGreaterThanOne(sqInt stackDelta) { return stackDelta > 1; } /* StackToRegisterMappingCogit>>#numberOfSpillsInTopNItems: */ static sqInt NoDbgRegParms numberOfSpillsInTopNItems(sqInt n) { sqInt i; for (i = simStackPtr; i >= ((simStackPtr - n) + 1); i += -1) { if ((((simStackAt(i))->type)) == SSSpill) { return n - (simStackPtr - i); } } return 0; } /* StackToRegisterMappingCogit>>#picAbortTrampolineFor: */ static sqInt NoDbgRegParms picAbortTrampolineFor(sqInt numArgs) { return picAbortTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* StackToRegisterMappingCogit>>#prevInstIsPCAnnotated */ static sqInt prevInstIsPCAnnotated(void) { sqInt prevIndex; AbstractInstruction *prevInst; if (!(opcodeIndex > 0)) { return 0; } prevIndex = opcodeIndex - 1; while (1) { if (prevIndex <= 0) { return 0; } prevInst = abstractInstructionAt(prevIndex); if (isPCMappedAnnotation((!((prevInst->annotation)) ? 0 : (prevInst->annotation)))) { return 1; } if (!(((prevInst->opcode)) == Label)) break; prevIndex -= 1; } return 0; } /* Used to mark ReceiverResultReg as dead or not containing simSelf. Used when the simStack has already been flushed, e.g. for sends. */ /* StackToRegisterMappingCogit>>#receiverIsInReceiverResultReg */ static sqInt receiverIsInReceiverResultReg(void) { return (((simSelf())->liveRegister)) == ReceiverResultReg; } /* 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. */ /* StackToRegisterMappingCogit>>#reinitializeFixupsFrom:through: */ static void NoDbgRegParms reinitializeFixupsFromthrough(sqInt start, sqInt end) { BytecodeDescriptor *descriptor; sqInt distance; BytecodeFixup * fixup; sqInt nExts; sqInt pc; BytecodeFixup * self_in_reinitialize; sqInt targetPC; pc = start; nExts = 0; while (pc <= end) { /* begin reinitialize */ self_in_reinitialize = fixupAtIndex(pc - initialPC); (self_in_reinitialize->targetInstruction) = ((self_in_reinitialize->simStackPtr) = 0); byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, pc, nExts, methodObj)) < 0))) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; /* begin initializeFixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); /* begin initializeFixup: */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); /* begin setIsBackwardBranchFixup */ (fixup->isTargetOfBackwardBranch) = 1; } if ((descriptor->isBlockCreation)) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); pc = (pc + ((descriptor->numBytes))) + distance; } else { pc += (descriptor->numBytes); } nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } /* Scan the block to determine if the block needs a frame or not */ /* StackToRegisterMappingCogit>>#scanBlock: */ static sqInt NoDbgRegParms scanBlock(BlockStart *blockStart) { BytecodeDescriptor *descriptor; sqInt end; sqInt framelessStackDelta; sqInt nExts; sqInt numPushNils; sqInt (* const numPushNilsFunction)(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt) = squeakV3orSistaV1NumPushNils; sqInt pc; sqInt pushingNils; needsFrame = 0; prevBCDescriptor = null; methodOrBlockNumArgs = (blockStart->numArgs); inBlock = InVanillaBlock; pc = (blockStart->startpc); end = ((blockStart->startpc)) + ((blockStart->span)); framelessStackDelta = (nExts = (extA = (numExtB = (extB = 0)))); pushingNils = 1; while (pc < end) { byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((descriptor->isExtension)) { loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } if (!needsFrame) { if ((((descriptor->needsFrameFunction)) == null) || (((descriptor->needsFrameFunction))(framelessStackDelta))) { needsFrame = 1; } else { framelessStackDelta += (descriptor->stackDelta); } } /* begin maybeNoteDescriptor:blockStart: */ if ((descriptor->isInstVarRef)) { (blockStart->hasInstVarRef = 1); } if (pushingNils && (!((descriptor->isExtension)))) { /* Count the initial number of pushed nils acting as temp initializers. We can't tell whether an initial pushNil is an operand reference or a temp initializer, except when the pushNil is a jump target (has a fixup), which never happens: self systemNavigation browseAllSelect: [:m| | ebc | (ebc := m embeddedBlockClosures select: [:ea| ea decompile statements first isMessage] thenCollect: [:ea| ea decompile statements first selector]) notEmpty and: [(#(whileTrue whileFalse whileTrue: whileFalse:) intersection: ebc) notEmpty]] or if the bytecode set has a push multiple nils bytecode. We simply count initial nils. Rarely we may end up over-estimating. We will correct by checking the stack depth at the end of the block in compileBlockBodies. */ if (((numPushNils = numPushNilsFunction(descriptor, pc, nExts, methodObj))) > 0) { assert((((descriptor->numBytes)) == 1) || (((descriptor->generator)) == genPushClosureTempsBytecode)); (blockStart->numInitialNils = ((blockStart->numInitialNils)) + numPushNils); } else { pushingNils = 0; } } /* begin nextBytecodePCFor:at:exts:in: */ pc = (pc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj) : 0)); if ((descriptor->isExtension)) { nExts += 1; } else { nExts = (extA = (numExtB = (extB = 0))); } prevBCDescriptor = descriptor; } if (!needsFrame) { assert((framelessStackDelta >= 0) && (((blockStart->numInitialNils)) >= framelessStackDelta)); (blockStart->numInitialNils = ((blockStart->numInitialNils)) - framelessStackDelta); } return 0; } /* Scan the method (and all embedded blocks) to determine - what the last bytecode is; extra bytes at the end of a method are used to encode things like source pointers or temp names - if the method needs a frame or not - what are the targets of any backward branches. - how many blocks it creates Answer the block count or on error a negative error code */ /* StackToRegisterMappingCogit>>#scanMethod */ static sqInt scanMethod(void) { BytecodeDescriptor *descriptor; sqInt distance; BytecodeFixup * fixup; sqInt framelessStackDelta; sqInt latestContinuation; sqInt nExts; sqInt numBlocks; sqInt pc; sqInt seenInstVarStore; sqInt targetPC; needsFrame = (useTwoPaths = (seenInstVarStore = 0)); prevBCDescriptor = null; if ((primitiveIndex > 0) && (isQuickPrimitiveIndex(primitiveIndex))) { return 0; } pc = (latestContinuation = initialPC); numBlocks = (framelessStackDelta = (nExts = (extA = (numExtB = (extB = 0))))); while (pc <= endPC) { byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((descriptor->isExtension)) { if (((descriptor->opcode)) == Nop) { /* unknown bytecode tag; see Cogit class>>#generatorTableFrom: */ return EncounteredUnknownBytecode; } loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } if (((descriptor->isReturn)) && (pc >= latestContinuation)) { endPC = pc; } if (!needsFrame) { if ((((descriptor->needsFrameFunction)) == null) || (((descriptor->needsFrameFunction))(framelessStackDelta))) { /* With immutability we win simply by avoiding a frame build if the receiver is young and not immutable. */ # if IMMUTABILITY if ((descriptor->is1ByteInstVarStore)) { useTwoPaths = 1; } else { needsFrame = 1; useTwoPaths = 0; } # else /* IMMUTABILITY */ needsFrame = 1; useTwoPaths = 0; # endif /* IMMUTABILITY */ } else { /* Without immutability we win if there are two or more stores and the receiver is new. */ framelessStackDelta += (descriptor->stackDelta); # if IMMUTABILITY # else /* IMMUTABILITY */ if ((descriptor->is1ByteInstVarStore)) { if (seenInstVarStore) { useTwoPaths = 1; } else { seenInstVarStore = 1; } } # endif /* IMMUTABILITY */ } } if (isBranch(descriptor)) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; if ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, pc, nExts, methodObj)) < 0)) { /* begin initializeFixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); /* begin initializeFixup: */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); /* begin setIsBackwardBranchFixup */ (fixup->isTargetOfBackwardBranch) = 1; } else { latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } } /* begin maybeDealWithUnsafeJumpForDescriptor:pc:latestContinuation: */ latestContinuation = latestContinuation; if ((descriptor->isBlockCreation)) { numBlocks += 1; /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } pc += (descriptor->numBytes); nExts = ((descriptor->isExtension) ? nExts + 1 : (extA = (numExtB = (extB = 0)))); prevBCDescriptor = descriptor; } return numBlocks; } /* StackToRegisterMappingCogit>>#squeakV3orSistaV1PushNilSize:numInitialNils: */ static sqInt NoDbgRegParms squeakV3orSistaV1PushNilSizenumInitialNils(sqInt aMethodObj, sqInt numInitialNils) { return (methodUsesAlternateBytecodeSet(aMethodObj) ? /* begin sistaV1PushNilSize:numInitialNils: */ numInitialNils : numInitialNils); } /* StackToRegisterMappingCogit>>#squeakV3orSistaV1:Num:Push:Nils: */ static sqInt NoDbgRegParms squeakV3orSistaV1NumPushNils(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { return (bytecodeSetOffset == 0 ? (((descriptor->generator)) == genPushConstantNilBytecode ? 1 : 0) : (/* begin sistaV1:Num:Push:Nils: */ (((descriptor->generator)) == genPushConstantNilBytecode ? 1 : 0))); } /* StackToRegisterMappingCogit>>#ssAllocateRequiredRegMask:upThrough:upThroughNative: */ static void NoDbgRegParms ssAllocateRequiredRegMaskupThroughupThroughNative(sqInt requiredRegsMask, sqInt stackPtr, sqInt nativeStackPtr) { sqInt i; sqInt i1; sqInt lastRequired; sqInt lastRequiredNative; sqInt liveRegs; lastRequired = -1; /* 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. */ lastRequiredNative = -1; /* begin registerMaskFor:and: */ liveRegs = (1U << FPReg) | (1U << SPReg); for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= stackPtr; i += 1) { liveRegs = liveRegs | (registerMask(simStackAt(i))); if ((registerMask(simStackAt(i))) & requiredRegsMask) { lastRequired = i; } } if (liveRegs & requiredRegsMask) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= lastRequired) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < lastRequired) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : lastRequired)); i1 <= lastRequired; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = lastRequired + 1; } assert(!(((liveRegisters()) & requiredRegsMask))); } } /* Any occurrences on the stack of the value being stored (which is the top of stack) must be flushed, and hence any values colder than them stack. */ /* StackToRegisterMappingCogit>>#ssFlushUpThroughReceiverVariable: */ static void NoDbgRegParms ssFlushUpThroughReceiverVariable(sqInt slotIndex) { sqInt i; sqInt index; /* begin ssFlushUpThrough: */ assert(simSpillBase >= 0); for (index = (simStackPtr - 1); index >= simSpillBase; index += -1) { if (((((simStackAt(index))->type)) == SSBaseOffset) && (((((simStackAt(index))->registerr)) == ReceiverResultReg) && ((((simStackAt(index))->offset)) == (slotOffsetOfInstVarIndex(slotIndex))))) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= index) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < index) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : index)); i <= index; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = index + 1; } goto l1; } } l1: /* end ssFlushUpThrough: */; } /* Any occurrences on the stack of the value being stored (which is the top of stack) must be flushed, and hence any values colder than them stack. */ /* StackToRegisterMappingCogit>>#ssFlushUpThroughTemporaryVariable: */ static void NoDbgRegParms ssFlushUpThroughTemporaryVariable(sqInt tempIndex) { sqInt i; sqInt index; sqInt offset; offset = ((simStackAt(tempIndex + 1))->offset); assert(offset == (frameOffsetOfTemporary(tempIndex))); /* begin ssFlushUpThrough: */ assert(simSpillBase >= 0); for (index = (simStackPtr - 1); index >= simSpillBase; index += -1) { if (((((simStackAt(index))->type)) == SSBaseOffset) && (((((simStackAt(index))->registerr)) == FPReg) && ((((simStackAt(index))->offset)) == offset))) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= index) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < index) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : index)); i <= index; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = index + 1; } goto l1; } } l1: /* end ssFlushUpThrough: */; } /* StackToRegisterMappingCogit>>#ssPop: */ static void NoDbgRegParms ssPop(sqInt n) { sqInt i; assert(((simStackPtr - n) >= methodOrBlockNumTemps) || (((!needsFrame) && ((simStackPtr - n) >= 0)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil()))); simStackPtr -= n; /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); } /* StackToRegisterMappingCogit>>#ssPushAnnotatedConstant: */ static sqInt NoDbgRegParms ssPushAnnotatedConstant(sqInt literal) { AbstractInstruction *abstractInstruction; ssPushConstant(literal); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); return 0; } /* StackToRegisterMappingCogit>>#ssPushBase:offset: */ static sqInt NoDbgRegParms ssPushBaseoffset(sqInt reg, sqInt offset) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSBaseOffset); (cascade0->spilled = 0); (cascade0->registerr = reg); (cascade0->offset = offset); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushConstant: */ static sqInt NoDbgRegParms ssPushConstant(sqInt literal) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSConstant); (cascade0->spilled = 0); (cascade0->constant = literal); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushDesc: */ static sqInt NoDbgRegParms ssPushDesc(SimStackEntry simStackEntry) { sqInt i; if (((simStackEntry.type)) == SSSpill) { (simStackEntry.type = SSBaseOffset); } (simStackEntry.spilled = 0); (simStackEntry.bcptr = bytecodePC); simStack[(simStackPtr += 1)] = simStackEntry; /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushRegister: */ static sqInt NoDbgRegParms ssPushRegister(sqInt reg) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = reg); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPush: */ static void NoDbgRegParms ssPush(sqInt n) { simStackPtr += n; } /* StackToRegisterMappingCogit>>#ssSelfDescriptor */ static SimStackEntry ssSelfDescriptor(void) { return simStack[0]; } /* In addition to ssStorePop:toReg:, if this is a store and not a popInto I change the simulated stack to use the register for the top value */ /* StackToRegisterMappingCogit>>#ssStoreAndReplacePop:toReg: */ static void NoDbgRegParms ssStoreAndReplacePoptoReg(sqInt popBoolean, sqInt reg) { char topSpilled; topSpilled = ((ssTop())->spilled); ssStorePoptoReg(popBoolean || (topSpilled), reg); if (!popBoolean) { if (!topSpilled) { ssPop(1); } ssPushRegister(reg); } } /* Store or pop the top simulated stack entry to a register. Use preferredReg if the entry is not itself a register. Answer the actual register the result ends up in. */ /* StackToRegisterMappingCogit>>#ssStorePop:toPreferredReg: */ static sqInt NoDbgRegParms ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg) { sqInt actualReg; actualReg = preferredReg; if ((((ssTop())->type)) == SSRegister) { assert(!(((ssTop())->spilled))); actualReg = ((ssTop())->registerr); } ssStorePoptoReg(popBoolean, actualReg); return actualReg; } /* Store or pop the top simulated stack entry to a register. N.B.: popToReg: and storeToReg: does not generate anything if it moves a register to the same register. */ /* StackToRegisterMappingCogit>>#ssStorePop:toReg: */ static void NoDbgRegParms ssStorePoptoReg(sqInt popBoolean, sqInt reg) { if (popBoolean) { popToReg(ssTop(), reg); ssPop(1); } else { storeToReg(ssTop(), reg); } } /* StackToRegisterMappingCogit>>#ssTop */ static CogSimStackEntry * ssTop(void) { return simStackAt(simStackPtr); } /* StackToRegisterMappingCogit>>#ssValue: */ static CogSimStackEntry * NoDbgRegParms ssValue(sqInt n) { return simStackAt(simStackPtr - n); } /* StackToRegisterMappingCogit>>#stackEntryIsBoolean: */ static sqInt NoDbgRegParms stackEntryIsBoolean(CogSimStackEntry *simStackEntry) { return (((simStackEntry->type)) == SSConstant) && ((((simStackEntry->constant)) == (trueObject())) || (((simStackEntry->constant)) == (falseObject()))); } /* Answer if the stack is valid up to, but not including, simSpillBase. */ /* StackToRegisterMappingCogit>>#tempsValidAndVolatileEntriesSpilled */ static sqInt tempsValidAndVolatileEntriesSpilled(void) { sqInt culprit; sqInt i; culprit = 0; for (i = 1; i <= methodOrBlockNumTemps; i += 1) { if (!(((((simStackAt(i))->type)) == SSBaseOffset) || (maybeCompilingFirstPassOfBlockWithInitialPushNil()))) { if (!(culprit)) { culprit = i; } return 0; } } for (i = (methodOrBlockNumTemps + 1); i < simSpillBase; i += 1) { if (!(((simStackAt(i))->spilled))) { if (!(culprit)) { culprit = i; } return 0; } } return 1; } /* If the sequence of bytecodes is push: (Array new: 1) popIntoTemp: tempIndex pushConstant: const or pushTemp: n popIntoTemp: 0 inVectorAt: tempIndex collapse this into tempAt: tempIndex put: {const or temp} and answer true, otherwise answer false. One might think that we should look for a sequence of more than one pushes and pops but this is extremely rare. Exclude pushRcvr: n to avoid potential complications with context inst vars. */ /* StackToRegisterMappingCogit>>#tryCollapseTempVectorInitializationOfSize: */ static sqInt NoDbgRegParms tryCollapseTempVectorInitializationOfSize(sqInt slots) { sqInt pc; sqInt pc1; sqInt pc2; BytecodeDescriptor *pushArrayDesc; BytecodeDescriptor *pushValueDesc; sqInt reg; sqInt remoteTempIndex; BytecodeDescriptor *storeArrayDesc; BytecodeDescriptor *storeValueDesc; sqInt tempIndex; if (slots != 1) { return 0; } /* begin generatorForPC: */ pushArrayDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(bytecodePC, methodObj))); assert(((pushArrayDesc->generator)) == genPushNewArrayBytecode); /* begin generatorForPC: */ pc = bytecodePC + ((pushArrayDesc->numBytes)); storeArrayDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); if (((storeArrayDesc->generator)) == genStoreAndPopTemporaryVariableBytecode) { tempIndex = (fetchByteofObject(bytecodePC + ((pushArrayDesc->numBytes)), methodObj)) & 7; } else { if (!(((storeArrayDesc->generator)) == genLongStoreAndPopTemporaryVariableBytecode)) { return 0; } tempIndex = fetchByteofObject((bytecodePC + ((pushArrayDesc->numBytes))) + 1, methodObj); } /* begin generatorForPC: */ pc1 = (bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes)); pushValueDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc1, methodObj))); if (!((((pushValueDesc->generator)) == genPushLiteralConstantBytecode) || ((((pushValueDesc->generator)) == genPushQuickIntegerConstantBytecode) || (((pushValueDesc->generator)) == genPushTemporaryVariableBytecode)))) { return 0; } /* begin generatorForPC: */ pc2 = ((bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes)); storeValueDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc2, methodObj))); remoteTempIndex = fetchByteofObject((((bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes))) + 2, methodObj); if (!((((storeValueDesc->generator)) == genStoreAndPopRemoteTempLongBytecode) && (tempIndex == remoteTempIndex))) { return 0; } genNewArrayOfSizeinitialized(1, 0); evaluateat(pushValueDesc, (bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))); reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, 0, ReceiverResultReg); ssPushRegister(ReceiverResultReg); evaluateat(storeArrayDesc, bytecodePC + ((pushArrayDesc->numBytes))); /* + pushArrayDesc numBytes this gets added by nextBytecodePCFor:at:exts:in: */ bytecodePC = ((bytecodePC + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes))) + ((storeValueDesc->numBytes)); return 1; } /* StackToRegisterMappingCogit>>#violatesEnsureSpilledSpillAssert */ static sqInt violatesEnsureSpilledSpillAssert(void) { return 1; } /* Used when ReceiverResultReg is allocated for other than simSelf, and there may be references to ReceiverResultReg which need to be spilled. */ /* StackToRegisterMappingCogit>>#voidReceiverResultRegContainsSelf */ static void voidReceiverResultRegContainsSelf(void) { sqInt i; sqInt i1; sqInt spillIndex; /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); spillIndex = 0; for (i = ((((methodOrBlockNumTemps + 1) < simSpillBase) ? simSpillBase : (methodOrBlockNumTemps + 1))); i <= simStackPtr; i += 1) { if ((registerOrNone(simStackAt(i))) == ReceiverResultReg) { spillIndex = i; } } if (spillIndex > 0) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= spillIndex) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < spillIndex) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : spillIndex)); i1 <= spillIndex; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = spillIndex + 1; } } }
変更されたテキスト
ファイルを開く
cogitARMv5.c 968ed91 [BAD] /* Automatically generated by CCodeGenerator VMMaker.oscog-nice.2501 uuid: 0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8 from StackToRegisterMappingCogit VMMaker.oscog-nice.2501 uuid: 0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8 */ static char __buildInfo[] = "StackToRegisterMappingCogit VMMaker.oscog-nice.2501 uuid: 0a0e26d0-bfc0-8746-ae54-69aaafc3e6c8 " __DATE__ ; char *__cogitBuildInfo = __buildInfo; #include <stddef.h> #include "sq.h" #include "sqCogStackAlignment.h" #include "dispdbg.h" #include "cogmethod.h" #if COGMTVM #include "cointerpmt.h" #else #include "cointerp.h" #endif #include "cogit.h" /*** Constants ***/ #define AddCqR 101 #define AddCwR 109 #define AddOpcode 4 #define AddRdRd 120 #define AddRR 95 #define AL 14 #define AlignmentNops 3 #define AltBlockCreationBytecodeSize 3 #define AltFirstSpecialSelector 96 #define AltNumSpecialSelectors 32 #define AndCqR 103 #define AndCqRR 118 #define AndCwR 111 #define AndOpcode 0 #define AndRR 97 #define AnnotationShift 5 #define Arg0Reg 3 #define Arg1Reg 4 #define ArithmeticShiftRightCqR 86 #define ArithmeticShiftRightRR 87 #define BadRegisterSet 1 #define BicOpcode 14 #define BlockCreationBytecodeSize 4 #define BytecodeSetHasDirectedSuperSend 1 #define CArg0Reg 0 #define CArg1Reg 1 #define CArg2Reg 2 #define CArg3Reg 3 #define Call 6 #define CallerSavedRegisterMask 0x120C #define CallFull 7 #define CC 3 #if !defined(CheckRememberedInTrampoline) /* Allow this to be overridden on the compiler command line */ # define CheckRememberedInTrampoline 0 #endif #define ClassArray 7 #define ClassArrayCompactIndex 51 #define ClassBlockClosureCompactIndex 37 #define ClassFloatCompactIndex 34 #define ClassFullBlockClosureCompactIndex 38 #define ClassLargePositiveIntegerCompactIndex 33 #define ClassMethodContextCompactIndex 36 #define ClassReg 2 #define ClosureFirstCopiedValueIndex 3 #define ClosureIndex 4 #define ClosureNumArgsIndex 2 #define ClosureOuterContextIndex 0 #define ClosureStartPCIndex 1 #define CMBlock 3 #define CMClosedPIC 4 #define CMFree 1 #define CMMaxUsageCount 7 #define CMMethod 2 #define CMOpenPIC 5 #define CMPSMULL 152 #define CmpC32R 108 #define CmpCqR 100 #define CmpCwR 107 #define CmpNotOpcode 11 #define CmpOpcode 10 #define CmpRdRd 119 #define CmpRR 94 #define CompletePrimitive 4 #define ConcreteIPReg 12 #define ConcreteVarBaseReg 10 #define ConstZero 1 #define ConvertRRd 133 #define CS 2 #define Debug DEBUGVM #define DisplacementMask 0x1F #define DisplacementX2N 0 #define DivRdRd 123 #define DPFPReg0 0 #define DPFPReg1 1 #define DPFPReg2 2 #define DPFPReg3 3 #define DPFPReg4 4 #define DPFPReg5 5 #define DPFPReg6 6 #define DPFPReg7 7 #define EncounteredUnknownBytecode -6 #define EQ 0 #define Extra0Reg 7 #define Extra1Reg 8 #define Extra2Reg 9 #define Fill32 4 #define FirstAnnotation 64 #define FirstJump 12 #define FirstSpecialSelector 176 #define FoxCallerSavedIP 4 #define FoxMethod -4 #define FoxMFReceiver -12 #define FoxSavedFP 0 #define FoxThisContext -8 #define FPReg 11 #define FullClosureCompiledBlockIndex 1 #define FullClosureFirstCopiedValueIndex 4 #define FullClosureReceiverIndex 3 #define GCModeBecome 8 #define GCModeFull 1 #define GCModeNewSpace 2 #define GE 10 #define GT 12 #define HasBytecodePC 5 #define HashMultiplyConstant 1664525 #define HashMultiplyMask 0xFFFFFFF #define HeaderIndex 0 #define HI 8 #if !defined(IMMUTABILITY) /* Allow this to be overridden on the compiler command line */ # define IMMUTABILITY 1 #endif #define InFullBlock 2 #define InstanceSpecificationIndex 2 #define InstructionPointerIndex 1 #define InsufficientCodeSpace -2 #define InVanillaBlock 1 #define IsAbsPCReference 3 #define IsAnnotationExtension 1 #define IsDirectedSuperBindingSend 10 #define IsDirectedSuperSend 9 #define IsDisplacementX2N 0 #define IsNSDynamicSuperSend null #define IsNSSelfSend null #define IsNSSendCall null #define IsObjectReference 2 #define IsRelativeCall 4 #define IsSendCall 7 #define IsSuperSend 8 #define Jump 16 #define JumpAbove 31 #define JumpAboveOrEqual 30 #define JumpBelow 29 #define JumpBelowOrEqual 32 #define JumpCarry 23 #define JumpFPEqual 33 #define JumpFPGreater 37 #define JumpFPGreaterOrEqual 38 #define JumpFPLess 35 #define JumpFPLessOrEqual 36 #define JumpFPNotEqual 34 #define JumpFPOrdered 39 #define JumpFPUnordered 40 #define JumpFull 12 #define JumpGreater 27 #define JumpGreaterOrEqual 26 #define JumpLess 25 #define JumpLessOrEqual 28 #define JumpLong 13 #define JumpLongNonZero 15 #define JumpLongZero 14 #define JumpNegative 19 #define JumpNoCarry 24 #define JumpNonNegative 20 #define JumpNonZero 18 #define JumpNoOverflow 22 #define JumpOverflow 21 #define JumpR 10 #define JumpZero 17 #define Label 1 #define LargeContextSlots 62 #define LastJump 40 #define LE 13 #define LinkReg 14 #define Literal 2 #define LiteralStart 1 #define LoadEffectiveAddressMwrR 83 #define LogicalShiftLeftCqR 90 #define LogicalShiftLeftRR 91 #define LogicalShiftRightCqR 88 #define LogicalShiftRightRR 89 #define LowcodeVM 0 #define LR 14 #define LS 9 #define LT 11 #define MapEnd 0 #define MaxCompiledPrimitiveIndex 222 #define MaxCPICCases 6 #define MaxMethodSize 65535 #define MaxNegativeErrorCode -8 #define MaxNumArgs 15 #define MaxStackAllocSize 1572864 #define MaxStackCheckOffset 0xFFF #define MaxX2NDisplacement 992 #define MethodCacheClass 2 #define MethodCacheMask 0xFFC #define MethodCacheMethod 3 #define MethodCacheSelector 1 #define MethodIndex 3 #define MethodTooBig -4 #define MFMethodFlagHasContextFlag 1 #define MFMethodFlagIsBlockFlag 2 #define MI 4 #define MoveAbR 46 #define MoveAwR 42 #define MoveC32R 69 #define MoveCqR 67 #define MoveCwR 68 #define MoveM16rR 55 #define MoveM64rRd 73 #define MoveMbrR 63 #define MoveMwrR 48 #define MoveNotOpcode 15 #define MoveOpcode 13 #define MoveRAb 47 #define MoveRAw 44 #define MoveRdM64r 74 #define MoveRdRd 72 #define MoveRM16r 56 #define MoveRMbr 64 #define MoveRMwr 49 #define MoveRR 41 #define MoveRXbrR 66 #define MoveRXwrR 51 #define MoveXbrRR 65 #define MoveXwrRR 50 #define MSR 146 #define MULTIPLEBYTECODESETS 1 #define MulRdRd 122 #define NE 1 #define NeedsMergeFixupFlag 2 #define NeedsNonMergeFixupFlag 1 #define NegateR 84 #define NewspeakVM 0 #define Nop 5 #define NoReg -1 #define NotFullyInitialized -1 #define NumObjRefsInRuntime 0 #define NumOopsPerNSC 6 #define NumSendTrampolines 4 #define NumSpecialSelectors 32 #define NumStoreTrampolines 5 #define NumTrampolines 74 #define OrCqR 104 #define OrCwR 112 #define OrOpcode 12 #define OrRR 98 #define PC 15 #define PCReg 15 #define PL 5 #define PopLDM 148 #define PopR 78 #define PrefetchAw 82 #define PrimCallCollectsProfileSamples 16 #define PrimCallDoNotJIT 64 #define PrimCallMayCallBack 4 #define PrimCallNeedsNewMethod 1 #define PrimCallNeedsPrimitiveFunction 2 #define PrimCallOnSmalltalkStack 8 #define PrimErrNoMemory 9 #define PrimErrWritePastObject 17 #define PushCq 80 #define PushCw 81 #define PushR 79 #define PushSTM 149 #define R0 0 #define ReceiverIndex 5 #define ReceiverResultReg 5 #define RetN 9 #define RISCTempReg 12 #define RsbOpcode 3 #define SelectorCannotInterpret 34 #define SelectorDoesNotUnderstand 20 #define SenderIndex 0 #define SendNumArgsReg 6 #define ShouldNotJIT -8 #define SignExtend16RR 140 #define SignExtend8RR 139 #define SistaV1BytecodeSet 1 #define SistaVM 0 #define SMULL 145 #define SmallContextSlots 22 #define SP 13 #define SPReg 13 #define SPURVM 1 #define SqrtRd 124 #define SSBaseOffset 1 #define SSConstant 2 #define SSRegister 3 #define SSSpill 4 #define StackPointerIndex 2 #define Stop 11 #define SubCqR 102 #define SubCwR 110 #define SubOpcode 2 #define SubRdRd 121 #define SubRR 96 #define TempReg 0 #define TempVectReadBarrier 0 #define TstCqR 105 #define TstOpcode 8 #define UnfailingPrimitive 3 #define UnimplementedPrimitive -7 #define ValueIndex 1 #define VarBaseReg 10 #define VC 7 #define VS 6 #define XorCqR 106 #define XorCwR 113 #define XorOpcode 1 #define XorRR 99 #define YoungSelectorInPIC -5 typedef struct _AbstractInstruction { unsigned char opcode; unsigned char machineCodeSize; unsigned char maxSize; unsigned char annotation; unsigned char conditionOrNil; usqInt operands [3]; usqInt address; struct _AbstractInstruction *dependent; unsigned int machineCode [5]; } AbstractInstruction; #define CogOutOfLineLiteralsARMCompiler AbstractInstruction #define CogARMCompiler AbstractInstruction #define CogAbstractInstruction AbstractInstruction typedef struct { AbstractInstruction *fakeHeader; AbstractInstruction *fillInstruction; sqInt numArgs; sqInt numCopied; sqInt numInitialNils; sqInt startpc; AbstractInstruction *entryLabel; AbstractInstruction *stackCheckLabel; sqInt span; sqInt hasInstVarRef; } BlockStart; #define CogBlockStart BlockStart typedef struct _BytecodeDescriptor { sqInt (*generator )(void); sqInt NoDbgRegParms (*spanFunction )(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt); sqInt NoDbgRegParms (*needsFrameFunction )(sqInt); signed char stackDelta; unsigned char opcode; unsigned char numBytes; unsigned isBranchTrue : 1; unsigned isBranchFalse : 1; unsigned isReturn : 1; unsigned isBlockCreation : 1; unsigned isMapped : 1; unsigned isMappedInBlock : 1; unsigned isExtension : 1; unsigned isInstVarRef : 1; unsigned is1ByteInstVarStore : 1; unsigned hasUnsafeJump : 1; } BytecodeDescriptor; #define CogBytecodeDescriptor BytecodeDescriptor typedef struct { sqInt (*primitiveGenerator )(void); sqInt primNumArgs; } PrimitiveDescriptor; #define CogPrimitiveDescriptor PrimitiveDescriptor typedef struct { char type; char spilled; signed char liveRegister; signed char registerr; sqInt offset; sqInt constant; sqInt bcptr; } SimStackEntry; #define CogSimStackEntry SimStackEntry typedef struct { AbstractInstruction *targetInstruction; unsigned char simStackPtr; char isTargetOfBackwardBranch; unsigned short instructionIndex; #if LowcodeVM short simNativeStackPtr; unsigned short simNativeStackSize; #endif } BytecodeFixup; #define CogSSBytecodeFixup BytecodeFixup #define CogBytecodeFixup BytecodeFixup typedef struct { sqInt isReceiverResultRegLive; CogSimStackEntry *ssEntry; } CogSSOptStatus; /*** Function Prototypes ***/ #if !PRODUCTION && defined(PlatformNoDbgRegParms) # define NoDbgRegParms PlatformNoDbgRegParms #endif #if !defined(NoDbgRegParms) # define NoDbgRegParms /*empty*/ #endif #if !defined(NeverInline) # define NeverInline /*empty*/ #endif static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction); static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask); static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral); static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp); static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister); static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal); static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal); static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction); static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump); static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress); static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction); static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress); static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta); static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta); static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget); static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms unalignedLongAt(AbstractInstruction * self_in_unalignedLongAt, sqInt byteAddress); static sqInt NoDbgRegParms unalignedLongAtput(AbstractInstruction * self_in_unalignedLongAtput, sqInt byteAddress, sqInt aWord); static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject); static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg); static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr); static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask); static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset); static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset); static sqInt NoDbgRegParms callFullTargetFromReturnAddress(AbstractInstruction * self_in_callFullTargetFromReturnAddress, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize); static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize); static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask); static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask); static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress); static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL); static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction); static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32); static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR); static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush); static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL); static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr); static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft); static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize); static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB); static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB); static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative); static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder); static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer); static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers); static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers); static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest); static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs); static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored); static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers); static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc); static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress); static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr); static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr); static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr); static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr); static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr); static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr); static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr); static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr); static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc); static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode); static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc); static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand); static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc); static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr); static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize); static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize); static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc); static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc); static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue); static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg); static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg); static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize); static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes); static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords); static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8); static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset); static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg); static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue); static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg); static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg); static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags); static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs); static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot); static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr); static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg); static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize); static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg); static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta); static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress); static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress); static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode); static sqInt NoDbgRegParms shiftSetsConditionCodesFor(AbstractInstruction * self_in_shiftSetsConditionCodesFor, sqInt aConditionalJumpOpcode); static sqInt NoDbgRegParms stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes); static AbstractInstruction * NoDbgRegParms stopsFromto(AbstractInstruction * self_in_stopsFromto, sqInt startAddr, sqInt endAddr); static sqInt NoDbgRegParms strbrnplusimm(AbstractInstruction * self_in_strbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms strbrnrm(AbstractInstruction * self_in_strbrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms strhrnplusimm(AbstractInstruction * self_in_strhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue); static sqInt NoDbgRegParms strhrnrm(AbstractInstruction * self_in_strhrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms strrnplusImm(AbstractInstruction * self_in_strrnplusImm, sqInt srcReg, sqInt baseReg, sqInt immediate12bitValue); static sqInt NoDbgRegParms strrnplusimm(AbstractInstruction * self_in_strrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue); static sqInt NoDbgRegParms strrnrm(AbstractInstruction * self_in_strrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg); static sqInt NoDbgRegParms subsrnimmror(AbstractInstruction * self_in_subsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms subrnimmror(AbstractInstruction * self_in_subrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms tstrnimmror(AbstractInstruction * self_in_tstrnimmror, sqInt ignored, sqInt srcReg, sqInt immediate, sqInt rot); static sqInt NoDbgRegParms zoneCallsAreRelative(AbstractInstruction * self_in_zoneCallsAreRelative); static CogMethod * NoDbgRegParms cmHomeMethod(CogBlockMethod * self_in_cmHomeMethod); static sqInt NoDbgRegParms isBranch(BytecodeDescriptor * self_in_isBranch); static AbstractInstruction * NoDbgRegParms gAddCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * NoDbgRegParms gAndCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * NoDbgRegParms gAndCqRR(sqInt quickConstant, sqInt srcReg, sqInt destReg); extern sqInt abortOffset(void); static void addCleanBlockStarts(void); extern void addCogMethodsToHeapMap(void); static sqInt NoDbgRegParms addressIsInCurrentCompilation(sqInt address); static sqInt NoDbgRegParms addressIsInFixups(BytecodeFixup *address); static sqInt NoDbgRegParms addressIsInInstructions(AbstractInstruction *address); static sqInt NoDbgRegParms addressOfEndOfCaseinCPIC(sqInt n, CogMethod *cPIC); static sqInt NoDbgRegParms alignUptoRoutineBoundary(sqInt anAddress); static sqInt allMachineCodeObjectReferencesValid(void); static sqInt allMethodsHaveCorrectHeader(void); static AbstractInstruction * NoDbgRegParms annotateAbsolutePCRef(AbstractInstruction *abstractInstruction); static AbstractInstruction * NoDbgRegParms annotateBytecode(AbstractInstruction *abstractInstruction); static AbstractInstruction * NoDbgRegParms annotateobjRef(AbstractInstruction *abstractInstruction, sqInt anOop); static void NoDbgRegParms assertSaneJumpTarget(AbstractInstruction *jumpTarget); static sqInt NoDbgRegParms blockDispatchTargetsForperformarg(CogMethod *cogMethod, usqInt (*binaryFunction)(sqInt mcpc, sqInt arg), sqInt arg); extern sqInt bytecodePCForstartBcpcin(sqInt mcpc, sqInt startbcpc, CogBlockMethod *cogMethod); static AbstractInstruction * NoDbgRegParms CallFullRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved); static AbstractInstruction * NoDbgRegParms CallRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved); static AbstractInstruction * NoDbgRegParms gCall(sqInt callTarget); static AbstractInstruction * NoDbgRegParms gCmpCqR(sqInt quickConstant, sqInt reg); extern void callCogCodePopReceiver(void); extern void callCogCodePopReceiverAndClassRegs(void); extern sqInt ceCPICMissreceiver(CogMethod *cPIC, sqInt receiver); extern void ceFree(void *pointer); extern void* ceMalloc(size_t size); extern sqInt ceSICMiss(sqInt receiver); extern void checkAssertsEnabledInCogit(void); static sqInt NoDbgRegParms checkIfValidOopRefAndTargetpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod); static sqInt NoDbgRegParms checkIfValidOopRefpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod); extern sqInt checkIntegrityOfObjectReferencesInCode(sqInt gcModes); static sqInt NoDbgRegParms checkMaybeObjRefInClosedPIC(sqInt maybeObject); static sqInt NoDbgRegParms checkValidObjectReferencesInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms NeverInline cleanUpFailingCogCodeConstituents(CogMethod *cogMethodArg); static sqInt NoDbgRegParms closedPICRefersToUnmarkedObject(CogMethod *cPIC); extern char * codeEntryFor(char *address); extern char * codeEntryNameFor(char *address); extern sqInt cogCodeBase(void); extern sqInt cogCodeConstituents(sqInt withDetails); static sqInt NoDbgRegParms cogExtendPICCaseNMethodtagisMNUCase(CogMethod *cPIC, sqInt caseNMethod, sqInt caseNTag, sqInt isMNUCase); extern CogMethod * cogFullBlockMethodnumCopied(sqInt aMethodObj, sqInt numCopied); extern void cogitPostGCAction(sqInt gcMode); extern sqInt cogMethodDoesntLookKosher(CogMethod *cogMethod); extern CogMethod * cogMNUPICSelectorreceivermethodOperandnumArgs(sqInt selector, sqInt rcvr, sqInt methodOperand, sqInt numArgs); static CogMethod * NoDbgRegParms cogOpenPICSelectornumArgs(sqInt selector, sqInt numArgs); static CogMethod * NoDbgRegParms cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase(sqInt selector, sqInt numArgs, CogMethod *case0CogMethod, sqInt case1MethodOrNil, sqInt case1Tag, sqInt isMNUCase); extern CogMethod * cogselector(sqInt aMethodObj, sqInt aSelectorOop); static sqInt NoDbgRegParms collectCogConstituentForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg); static sqInt NoDbgRegParms collectCogMethodConstituent(CogMethod *cogMethod); extern void compactCogCompiledCode(void); static void compactPICsWithFreedTargets(void); static AbstractInstruction * compileAbort(void); static sqInt NoDbgRegParms compileBlockDispatchFromto(sqInt lowBlockStartIndex, sqInt highBlockStartIndex); static void NoDbgRegParms compileBlockEntry(BlockStart *blockStart); static void NoDbgRegParms compileCallFornumArgsargargargargresultRegregsToSave(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt resultRegOrNone, sqInt regMask); static AbstractInstruction * compileCPICEntry(void); static sqInt NoDbgRegParms compileEntireFullBlockMethod(sqInt numCopied); static void compileEntry(void); static sqInt compileFullBlockEntry(void); static sqInt compileMethodBody(void); static sqInt NoDbgRegParms compilePICAbort(sqInt numArgs); static void NoDbgRegParms compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone); static void computeEntryOffsets(void); static void computeFullBlockEntryOffsets(void); static void computeMaximumSizes(void); static sqInt NoDbgRegParms configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(CogMethod *cPIC, CogMethod *case0CogMethod, sqInt case1Method, sqInt case1Tag, sqInt isMNUCase, sqInt numArgs, sqInt addrDelta); static sqInt NoDbgRegParms configureMNUCPICmethodOperandnumArgsdelta(CogMethod *cPIC, sqInt methodOperand, sqInt numArgs, sqInt addrDelta); static sqInt NoDbgRegParms cPICCompactAndIsNowEmpty(CogMethod *cPIC); static sqInt NoDbgRegParms cPICHasForwardedClass(CogMethod *cPIC); static sqInt NoDbgRegParms cPICHasFreedTargets(CogMethod *cPIC); static sqInt cPICPrototypeCaseOffset(void); static sqInt NoDbgRegParms cPICHasTarget(CogMethod *cPIC, CogMethod *targetMethod); static sqInt NoDbgRegParms createCPICData(CogMethod *cPIC); static AbstractInstruction * NoDbgRegParms gDivRRQuoRem(sqInt rDivisor, sqInt rDividend, sqInt rQuotient, sqInt rRemainder); extern sqInt defaultCogCodeSize(void); static sqInt NoDbgRegParms deltaToSkipPrimAndErrorStoreInheader(sqInt aMethodObj, sqInt aMethodHeader); static sqInt NoDbgRegParms endPCOf(sqInt aMethod); extern void enterCogCodePopReceiver(void); static sqInt NoDbgRegParms entryPointTagIsSelector(sqInt entryPoint); static sqInt NoDbgRegParms expectedClosedPICPrototype(CogMethod *cPIC); static sqInt extABytecode(void); static sqInt extBBytecode(void); static sqInt NoDbgRegParms fillInBlockHeadersAt(sqInt startAddress); static CogMethod * NoDbgRegParms fillInMethodHeadersizeselector(CogMethod *method, sqInt size, sqInt selector); static sqInt NoDbgRegParms findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetBcpc); static usqInt NoDbgRegParms findBlockMethodWithEntrystartBcpc(sqInt blockEntryMcpc, sqInt startBcpc); static usqInt NoDbgRegParms findMapLocationForMcpcinMethod(usqInt targetMcpc, CogMethod *cogMethod); extern CogBlockMethod * findMethodForStartBcpcinHomeMethod(sqInt startbcpc, CogMethod *cogMethod); static sqInt NoDbgRegParms findIsBackwardBranchMcpcBcpcMatchingMcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetMcpc); static sqInt NoDbgRegParms firstMappedPCFor(CogMethod *cogMethod); static sqInt firstPrototypeMethodOop(void); static BytecodeFixup * NoDbgRegParms fixupAt(sqInt fixupPC); extern void followForwardedLiteralsIn(CogMethod *cogMethod); extern void followForwardedMethods(void); static sqInt NoDbgRegParms followMaybeObjRefInClosedPICAt(sqInt mcpc); static sqInt NoDbgRegParms followMethodReferencesInClosedPIC(CogMethod *cPIC); extern void freeUnmarkedMachineCode(void); static AbstractInstruction * NoDbgRegParms genCallMustBeBooleanFor(sqInt boolean); static sqInt genCheckForInterruptsTrampoline(void); static AbstractInstruction * NoDbgRegParms genConditionalBranchoperand(sqInt opcode, sqInt operandOne); static void (*genEnilopmartForandandforCallcalled(sqInt regArg1, sqInt regArg2OrNone, sqInt regArg3OrNone, sqInt forCall, char *trampolineName))(void) ; static void NoDbgRegParms genEnilopmartReturn(sqInt forCall); static void NoDbgRegParms generateCaptureCStackPointers(sqInt captureFramePointer); static void generateClosedPICPrototype(void); static CogMethod * generateCogFullBlock(void); static CogMethod * NoDbgRegParms generateCogMethod(sqInt selector); static sqInt NoDbgRegParms generateMapAtstart(usqInt addressOrNull, usqInt startAddress); static void generateOpenPICPrototype(void); static void generateRunTimeTrampolines(void); static void generateStackPointerCapture(void); static void generateTrampolines(void); static BytecodeDescriptor * NoDbgRegParms generatorForPC(sqInt pc); static void genGetLeafCallStackPointer(void); static sqInt NoDbgRegParms genInnerPICAbortTrampoline(char *name); static sqInt genLoadCStackPointersForPrimCall(void); static void NoDbgRegParms genLoadInlineCacheWithSelector(sqInt selectorIndex); static sqInt genNonLocalReturnTrampoline(void); static sqInt NoDbgRegParms genReturnTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0); static sqInt NoDbgRegParms genSmalltalkToCStackSwitch(sqInt pushLinkReg); static sqInt NoDbgRegParms genTrampolineForcalled(void *aRoutine, char *aString); static sqInt NoDbgRegParms genTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0); static sqInt NoDbgRegParms genTrampolineForcalledargargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcalledargargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regMask); static sqInt NoDbgRegParms genTrampolineForcalledargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcalledargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regMask); static sqInt NoDbgRegParms genTrampolineForcalledargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt resultReg); static sqInt NoDbgRegParms genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(void *aRoutine, char *trampolineName, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone, sqInt appendBoolean); static sqInt NoDbgRegParms genTrampolineForcalledregsToSave(void *aRoutine, char *aString, sqInt regMask); static AbstractInstruction * NoDbgRegParms gen(sqInt opcode); static AbstractInstruction * NoDbgRegParms genoperand(sqInt opcode, sqInt operand); static AbstractInstruction * NoDbgRegParms genoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo); static AbstractInstruction * NoDbgRegParms genoperandoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo, sqInt operandThree); static sqInt NoDbgRegParms getLiteral(sqInt litIndex); static sqInt getOpcodeIndex(void); static sqInt NoDbgRegParms incrementUsageOfTargetIfLinkedSendmcpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms indexForSelectorinat(sqInt selector, CogMethod *cogMethod, sqInt mcpc); static sqInt initialClosedPICUsageCount(void); static void initializeBackend(void); extern void initializeCodeZoneFromupTo(sqInt startAddress, sqInt endAddress); static sqInt initialMethodUsageCount(void); static sqInt initialOpenPICUsageCount(void); static sqInt NoDbgRegParms inlineCacheValueForSelectorinat(sqInt selector, CogMethod *aCogMethod, sqInt mcpc); static sqInt NoDbgRegParms inverseBranchFor(sqInt opcode); static sqInt NoDbgRegParms isPCMappedAnnotation(sqInt annotation); extern sqInt isPCWithinMethodZone(void *address); extern sqInt isSendReturnPC(sqInt retpc); static AbstractInstruction * NoDbgRegParms gJumpFPEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPGreaterOrEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPGreater(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gJumpFPNotEqual(void *jumpTarget); static AbstractInstruction * NoDbgRegParms gLogicalShiftLeftCqR(sqInt quickConstant, sqInt reg); static AbstractInstruction * lastOpcode(void); extern void linkSendAtintooffsetreceiver(sqInt callSiteReturnAddress, CogMethod *sendingMethod, CogMethod *targetMethod, sqInt theEntryOffset, sqInt receiver); static BytecodeDescriptor * loadBytesAndGetDescriptor(void); static void NoDbgRegParms loadSubsequentBytesForDescriptorat(BytecodeDescriptor *descriptor, sqInt pc); static AbstractInstruction * NoDbgRegParms gMoveAwR(sqInt address, sqInt reg); static AbstractInstruction * NoDbgRegParms gMoveCwR(sqInt wordConstant, sqInt reg); static usqInt NoDbgRegParms mapEndFor(CogMethod *cogMethod); static sqInt NoDbgRegParms mapForperformUntilarg(CogMethod *cogMethod, sqInt (*functionSymbol)(sqInt annotation, char *mcpc, sqInt arg), sqInt arg); static sqInt NoDbgRegParms mapObjectReferencesInClosedPIC(CogMethod *cPIC); static void mapObjectReferencesInGeneratedRuntime(void); static void mapObjectReferencesInMachineCodeForBecome(void); static void mapObjectReferencesInMachineCodeForFullGC(void); static void mapObjectReferencesInMachineCodeForYoungGC(void); extern void mapObjectReferencesInMachineCode(sqInt gcMode); extern void markAndTraceMachineCodeOfMarkedMethods(void); static void markAndTraceObjectReferencesInGeneratedRuntime(void); static sqInt NoDbgRegParms markAndTraceOrFreeCogMethodfirstVisit(CogMethod *cogMethod, sqInt firstVisit); static sqInt NoDbgRegParms markAndTraceOrFreePICTargetin(sqInt entryPoint, CogMethod *cPIC); static sqInt NoDbgRegParms markLiteralsAndUnlinkIfUnmarkedSendpcmethod(sqInt annotation, char *mcpc, sqInt cogMethod); static sqInt NoDbgRegParms markLiteralspcmethod(sqInt annotation, char *mcpc, sqInt cogMethod); extern void markMethodAndReferents(CogBlockMethod *aCogMethod); extern usqInt maxCogMethodAddress(void); static sqInt maybeAllocAndInitIRCs(void); static sqInt NoDbgRegParms maybeFreeCogMethodDoesntLookKosher(CogMethod *cogMethod); static void NoDbgRegParms maybeMarkCountersIn(CogMethod *cogMethod); static sqInt mclassIsSmallInteger(void); extern usqInt mcPCForBackwardBranchstartBcpcin(sqInt bcpc, sqInt startbcpc, CogBlockMethod *cogMethod); static sqInt NoDbgRegParms methodhasSameCodeAscheckPenultimate(sqInt methodA, sqInt methodB, sqInt comparePenultimateLiteral); extern sqInt minCogMethodAddress(void); extern sqInt mnuOffset(void); static sqInt NoDbgRegParms needsFrameIfImmutability(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameIfInBlock(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameNever(sqInt stackDelta); static sqInt NoDbgRegParms noAssertMethodClassAssociationOf(sqInt methodPointer); static sqInt noCogMethodsMaximallyMarked(void); static sqInt NoDbgRegParms noTargetsFreeInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms outputInstructionsAt(sqInt startAddress); static sqInt NoDbgRegParms outputInstructionsForGeneratedRuntimeAt(sqInt startAddress); static AbstractInstruction * NoDbgRegParms gPushCw(sqInt wordConstant); extern sqInt patchToOpenPICFornumArgsreceiver(sqInt selector, sqInt numArgs, sqInt receiver); static sqInt picAbortDiscriminatorValue(void); static sqInt picInterpretAbortOffset(void); extern void printCogMethodFor(void *address); extern void printTrampolineTable(void); static sqInt processorHasDivQuoRemAndMClassIsSmallInteger(void); static sqInt processorHasMultiplyAndMClassIsSmallInteger(void); static void NoDbgRegParms recordGeneratedRunTimeaddress(char *aString, sqInt address); extern sqInt recordPrimTraceFunc(void); static void recordRunTimeObjectReferences(void); static sqInt NoDbgRegParms registerMaskFor(sqInt reg); static void NoDbgRegParms relocateCallsAndSelfReferencesInMethod(CogMethod *cogMethod); static void NoDbgRegParms relocateCallsInClosedPIC(CogMethod *cPIC); static sqInt NoDbgRegParms relocateIfCallOrMethodReferencemcpcdelta(sqInt annotation, char *mcpc, sqInt refDelta); static sqInt NoDbgRegParms remapIfObjectRefpchasYoung(sqInt annotation, char *mcpc, sqInt hasYoungPtr); static sqInt NoDbgRegParms remapMaybeObjRefInClosedPICAt(sqInt mcpc); static void NoDbgRegParms rewriteCPICCaseAttagobjReftarget(sqInt followingAddress, sqInt newTag, sqInt newObjRef, sqInt newTarget); static AbstractInstruction * NoDbgRegParms gSubCwR(sqInt wordConstant, sqInt reg); static sqInt scanForCleanBlocks(void); extern void setBreakMethod(sqInt anObj); extern void setPostCompileHook(void (*aFunction)(CogMethod *)); extern void setSelectorOfto(CogMethod *cogMethod, sqInt aSelectorOop); static sqInt NoDbgRegParms spanForCleanBlockStartingAt(sqInt startPC); static sqInt subsequentPrototypeMethodOop(void); extern sqInt traceLinkedSendOffset(void); static sqInt NoDbgRegParms trampolineArgConstant(sqInt booleanOrInteger); static char * NoDbgRegParms trampolineNamenumArgs(char *routinePrefix, sqInt numArgs); static char * NoDbgRegParms trampolineNamenumArgslimit(char *routinePrefix, int numArgs, sqInt argsLimit); static char * NoDbgRegParms trampolineNamenumRegArgs(char *routinePrefix, sqInt numArgs); static sqInt unknownBytecode(void); extern void unlinkAllSends(void); static sqInt NoDbgRegParms unlinkIfFreeOrLinkedSendpcof(sqInt annotation, char *mcpc, sqInt theSelector); static sqInt NoDbgRegParms unlinkIfInvalidClassSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendToFreepcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity); static sqInt NoDbgRegParms unlinkIfLinkedSendpcto(sqInt annotation, char *mcpc, sqInt theCogMethod); extern void unlinkSendsLinkedForInvalidClasses(void); extern void unlinkSendsOfisMNUSelector(sqInt selector, sqInt isMNUSelector); extern void unlinkSendsToFree(void); extern void unlinkSendsToandFreeIf(sqInt targetMethodObject, sqInt freeIfTrue); static AbstractInstruction * NoDbgRegParms gXorCwR(sqInt wordConstant, sqInt reg); static void zeroOpcodeIndex(void); static void zeroOpcodeIndexForNewOpcodes(void); static sqInt NoDbgRegParms counters(CogMethod * self_in_counters); extern void addAllToYoungReferrers(void); static void NoDbgRegParms addToOpenPICList(CogMethod *anOpenPIC); static void NoDbgRegParms addToYoungReferrers(CogMethod *cogMethod); static usqInt NoDbgRegParms allocate(sqInt numBytes); static void clearCogCompiledCode(void); static void compactCompiledCode(void); static void NoDbgRegParms ensureInYoungReferrers(CogMethod *cogMethod); static void followForwardedLiteralsInOpenPICList(void); extern void freeMethod(CogMethod *cogMethod); static void freeOlderMethodsForCompaction(void); static sqInt kosherYoungReferrers(void); static void NoDbgRegParms manageFromto(sqInt theStartAddress, sqInt theLimitAddress); extern CogMethod * methodFor(void *address); extern sqInt methodsCompiledToMachineCodeInto(sqInt arrayObj); extern sqInt numMethods(void); extern sqInt numMethodsOfType(sqInt cogMethodType); static sqInt NoDbgRegParms occurrencesInYoungReferrers(CogMethod *cogMethod); static CogMethod * NoDbgRegParms openPICWithSelector(sqInt aSelector); static void planCompaction(void); extern void printCogMethods(void); extern void printCogMethodsOfType(sqInt cmType); extern void printCogMethodsWithMethod(sqInt methodOop); extern void printCogMethodsWithPrimitive(sqInt primIdx); extern void printCogMethodsWithSelector(sqInt selectorOop); extern void printCogYoungReferrers(void); extern sqInt printOpenPICList(void); static sqInt pruneYoungReferrers(void); static sqInt relocateAndPruneYoungReferrers(void); static sqInt relocateMethodsPreCompaction(void); static sqInt NoDbgRegParms removeFromOpenPICList(CogMethod *anOpenPIC); static void voidOpenPICList(void); static void voidYoungReferrersPostTenureAll(void); extern char * whereIsMaybeCodeThing(sqInt anOop); static sqInt NoDbgRegParms checkValidObjectReference(sqInt anOop); static AbstractInstruction * NoDbgRegParms genCmpClassFloatCompactIndexR(sqInt reg); static AbstractInstruction * NoDbgRegParms genCmpClassMethodContextCompactIndexR(sqInt reg); static sqInt NoDbgRegParms genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)); static sqInt NoDbgRegParms genDoubleComparisoninvert(AbstractInstruction * NoDbgRegParms (*jumpOpcodeGenerator)(void *), sqInt invertComparison); static sqInt NoDbgRegParms genGetMethodHeaderOfintoscratch(sqInt methodReg, sqInt headerReg, sqInt scratchReg); static sqInt NoDbgRegParms genLoadSlotsourceRegdestReg(sqInt index, sqInt sourceReg, sqInt destReg); static sqInt genPrimitiveAdd(void); static sqInt genPrimitiveAsFloat(void); static sqInt genPrimitiveBitAnd(void); static sqInt genPrimitiveBitOr(void); static sqInt genPrimitiveBitShift(void); static sqInt genPrimitiveBitXor(void); static sqInt genPrimitiveClass(void); static sqInt genPrimitiveDiv(void); static sqInt genPrimitiveDivide(void); static sqInt genPrimitiveEqual(void); static sqInt genPrimitiveFloatAdd(void); static sqInt genPrimitiveFloatDivide(void); static sqInt genPrimitiveFloatEqual(void); static sqInt genPrimitiveFloatGreaterOrEqual(void); static sqInt genPrimitiveFloatGreaterThan(void); static sqInt genPrimitiveFloatLessOrEqual(void); static sqInt genPrimitiveFloatLessThan(void); static sqInt genPrimitiveFloatMultiply(void); static sqInt genPrimitiveFloatNotEqual(void); static sqInt genPrimitiveFloatSquareRoot(void); static sqInt genPrimitiveFloatSubtract(void); static sqInt genPrimitiveGreaterOrEqual(void); static sqInt genPrimitiveGreaterThan(void); static sqInt genPrimitiveIdentical(void); static sqInt genPrimitiveLessOrEqual(void); static sqInt genPrimitiveLessThan(void); static sqInt genPrimitiveMod(void); static sqInt genPrimitiveMultiply(void); static sqInt genPrimitiveNewMethod(void); static sqInt genPrimitiveNotEqual(void); static sqInt genPrimitiveNotIdentical(void); static sqInt genPrimitiveQuo(void); static sqInt genPrimitiveSubtract(void); static sqInt NoDbgRegParms genSmallIntegerComparison(sqInt jumpOpcode); static sqInt NoDbgRegParms genSmallIntegerComparisonorDoubleComparisoninvert(sqInt jumpOpcode, AbstractInstruction * NoDbgRegParms (*jumpFPOpcodeGenerator)(void *), sqInt invertComparison); static sqInt NoDbgRegParms isUnannotatableConstant(CogSimStackEntry *simStackEntry); static sqInt NoDbgRegParms classForInlineCacheTag(sqInt inlineCacheTag); static sqInt NoDbgRegParms genAddSmallIntegerTagsTo(sqInt aRegister); static sqInt NoDbgRegParms genClearAndSetSmallIntegerTagsIn(sqInt scratchReg); static void NoDbgRegParms genConvertCharacterToSmallIntegerInReg(sqInt reg); static sqInt NoDbgRegParms genConvertIntegerToSmallIntegerInReg(sqInt reg); static void NoDbgRegParms genConvertSmallIntegerToCharacterInReg(sqInt reg); static sqInt NoDbgRegParms genConvertSmallIntegerToIntegerInReg(sqInt reg); static sqInt NoDbgRegParms genGetHashFieldNonImmOfasSmallIntegerInto(sqInt instReg, sqInt destReg); static sqInt NoDbgRegParms genGetHashFieldNonImmOfinto(sqInt instReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genGetInlineCacheClassTagFromintoforEntry(sqInt sourceReg, sqInt destReg, sqInt forEntry); static sqInt NoDbgRegParms genGetNumBytesOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetOverflowSlotsOfinto(sqInt srcReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genJumpIsSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg); static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerInScratchReg(sqInt aRegister); static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg); static AbstractInstruction * NoDbgRegParms genJumpNotSmallInteger(sqInt aRegister); static AbstractInstruction * NoDbgRegParms genJumpSmallInteger(sqInt aRegister); static sqInt genPrimitiveAtPut(void); static sqInt NoDbgRegParms genPrimitiveAtPutSigned(sqInt signedVersion); static sqInt NoDbgRegParms genPrimitiveAtSigned(sqInt signedVersion); static sqInt genPrimitiveIdentityHash(void); static sqInt genPrimitiveImmediateAsInteger(void); static sqInt genPrimitiveNew(void); static sqInt genPrimitiveNewWithArg(void); static sqInt genPrimitiveShallowCopy(void); static sqInt genPrimitiveStringAt(void); static sqInt genPrimitiveStringAtPut(void); static sqInt NoDbgRegParms genRemoveSmallIntegerTagsInScratchReg(sqInt scratchReg); static sqInt NoDbgRegParms genShiftAwaySmallIntegerTagsInScratchReg(sqInt scratchReg); static sqInt NoDbgRegParms getLiteralCountOfplusOneinBytesintoscratch(sqInt methodReg, sqInt plusOne, sqInt inBytes, sqInt litCountReg, sqInt scratchReg); static sqInt NoDbgRegParms inlineCacheTagForInstance(sqInt oop); static AbstractInstruction * NoDbgRegParms jumpNotSmallIntegerUnsignedValueInRegister(sqInt reg); static sqInt NoDbgRegParms markAndTraceCacheTagLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address); static sqInt numSmallIntegerBits(void); static sqInt NoDbgRegParms validInlineCacheTag(usqInt classIndexOrTagPattern); static sqInt NoDbgRegParms cacheTagIsMarked(sqInt cacheTag); static void callStoreCheckTrampoline(void); static sqInt NoDbgRegParms checkValidDerivedObjectReference(sqInt bodyAddress); static sqInt NoDbgRegParms checkValidOopReference(sqInt anOop); static sqInt NoDbgRegParms couldBeDerivedObject(sqInt bodyAddress); static sqInt NoDbgRegParms couldBeObject(sqInt literal); static sqInt NoDbgRegParms genActiveContextTrampolineLargeinBlockcalled(sqInt isLarge, sqInt isInBlock, char *aString); static AbstractInstruction * NoDbgRegParms genAllocFloatValueintoscratchRegscratchReg(sqInt dpreg, sqInt resultReg, sqInt scratch1, sqInt scratch2); static AbstractInstruction * NoDbgRegParms genCheckRememberedBitOfscratch(sqInt objReg, sqInt scratchReg); static sqInt NoDbgRegParms genConvertCharacterToCodeInReg(sqInt reg); static sqInt NoDbgRegParms genConvertIntegerToCharacterInReg(sqInt reg); static sqInt NoDbgRegParms genCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock); static sqInt NoDbgRegParms genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(sqInt compiledBlock, sqInt numArgs, sqInt numCopied, sqInt ignoreContext, sqInt contextNumArgs, sqInt contextIsLarge, sqInt contextIsBlock); static sqInt NoDbgRegParms genEnsureObjInRegNotForwardedscratchReg(sqInt reg, sqInt scratch); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchReg(sqInt reg, sqInt scratch); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(sqInt reg, sqInt scratch, sqInt fwdJumpTarget, sqInt nonFwdJumpTargetOrZero); static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(sqInt reg, sqInt scratch, sqInt index, sqInt objReg); static void generateObjectRepresentationTrampolines(void); static sqInt NoDbgRegParms genGetActiveContextLargeinBlock(sqInt isLarge, sqInt isInBlock); static sqInt NoDbgRegParms genGetActiveContextNumArgslargeinBlock(sqInt numArgs, sqInt isLargeContext, sqInt isInBlock); static sqInt NoDbgRegParms genGetBitsofFormatByteOfinto(sqInt mask, sqInt sourceReg, sqInt destReg); static sqInt NoDbgRegParms genGetClassIndexOfNonImminto(sqInt sourceReg, sqInt destReg); static sqInt NoDbgRegParms genGetClassObjectOfClassIndexintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg); static sqInt NoDbgRegParms genGetClassObjectOfintoscratchReginstRegIsReceiver(sqInt instReg, sqInt destReg, sqInt scratchReg, sqInt instRegIsReceiver); static AbstractInstruction * NoDbgRegParms genGetClassTagOfintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg); static sqInt NoDbgRegParms genGetCompactClassIndexNonImmOfinto(sqInt instReg, sqInt destReg); static sqInt NoDbgRegParms genGetDoubleValueOfinto(sqInt srcReg, sqInt destFPReg); static sqInt NoDbgRegParms genGetFormatOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(sqInt sourceReg, sqInt destReg, sqInt scratchRegOrNone); static sqInt NoDbgRegParms genGetNumSlotsOfinto(sqInt srcReg, sqInt destReg); static sqInt NoDbgRegParms genGetRawSlotSizeOfNonImminto(sqInt sourceReg, sqInt destReg); static AbstractInstruction * NoDbgRegParms genJumpImmediate(sqInt aRegister); #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpImmutablescratchReg(sqInt sourceReg, sqInt scratchReg); #endif /* IMMUTABILITY */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpMutablescratchReg(sqInt sourceReg, sqInt scratchReg); #endif /* IMMUTABILITY */ static AbstractInstruction * NoDbgRegParms genJumpNotCharacterInScratchReg(sqInt reg); static sqInt NoDbgRegParms genNewArrayOfSizeinitialized(sqInt size, sqInt initialized); static sqInt NoDbgRegParms genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock); static sqInt genPrimitiveAsCharacter(void); static sqInt genPrimitiveAt(void); static sqInt NoDbgRegParms genPrimitiveIdenticalOrNotIf(sqInt orNot); static sqInt genPrimitiveIntegerAt(void); static sqInt genPrimitiveIntegerAtPut(void); static sqInt genPrimitiveObjectAt(void); static sqInt genPrimitiveSize(void); static sqInt genPrimitiveStringCompareWith(void); static sqInt genPrimitiveStringReplace(void); static sqInt NoDbgRegParms genSetSmallIntegerTagsIn(sqInt scratchReg); static sqInt genStoreCheckContextReceiverTrampoline(void); static sqInt NoDbgRegParms genStoreCheckReceiverRegvalueRegscratchReginFrame(sqInt destReg, sqInt valueReg, sqInt scratchReg, sqInt inFrame); static sqInt NoDbgRegParms genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt inFrame, sqInt needsStoreCheck); static sqInt NoDbgRegParms genStoreSourceRegslotIndexintoNewObjectInDestReg(sqInt sourceReg, sqInt index, sqInt destReg); #if IMMUTABILITY static sqInt NoDbgRegParms genStoreTrampolineCalledinstVarIndex(char *trampolineName, sqInt instVarIndex); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needsStoreCheck, sqInt needRestoreRcvr); #endif /* IMMUTABILITY */ static sqInt getActiveContextAllocatesInMachineCode(void); static sqInt NoDbgRegParms inlineCacheTagIsYoung(sqInt cacheTag); static AbstractInstruction * NoDbgRegParms jumpNotCharacterUnsignedValueInRegister(sqInt reg); static sqInt NoDbgRegParms markAndTraceLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address); static void NoDbgRegParms markAndTraceLiteralinat(sqInt literal, CogMethod *cogMethod, sqInt *address); static void NoDbgRegParms markAndTraceUpdatedLiteralin(sqInt objOop, CogMethod *cogMethodOrNil); static sqInt NoDbgRegParms maybeCompileRetryOnPrimitiveFail(sqInt primIndex); static sqInt NoDbgRegParms maybeShiftClassTagRegisterForMethodCacheProbe(sqInt classTagReg); static sqInt numCharacterBits(void); extern sqInt numRegArgs(void); static sqInt NoDbgRegParms remapObject(sqInt objOop); static sqInt NoDbgRegParms remapOop(sqInt objOop); static sqInt NoDbgRegParms shouldAnnotateObjectReference(sqInt anOop); static sqInt NoDbgRegParms slotOffsetOfInstVarIndex(sqInt index); static sqInt NoDbgRegParms cmpC32RTempByteSize(AbstractInstruction * self_in_cmpC32RTempByteSize); static AbstractInstruction * NoDbgRegParms concretizeLiteral(AbstractInstruction * self_in_concretizeLiteral); static sqInt NoDbgRegParms inlineCacheTagAt(AbstractInstruction * self_in_inlineCacheTagAt, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms isPCDependent(AbstractInstruction * self_in_isPCDependent); static sqInt NoDbgRegParms literalBeforeFollowingAddress(AbstractInstruction * self_in_literalBeforeFollowingAddress, sqInt followingAddress); static sqInt NoDbgRegParms literalLoadInstructionBytes(AbstractInstruction * self_in_literalLoadInstructionBytes); static sqInt NoDbgRegParms loadLiteralByteSize(AbstractInstruction * self_in_loadLiteralByteSize); static sqInt NoDbgRegParms nsSendCacheAt(AbstractInstruction * self_in_nsSendCacheAt, sqInt callSiteReturnAddress); static sqInt NoDbgRegParms outOfLineLiteralOpcodeLimit(AbstractInstruction * self_in_outOfLineLiteralOpcodeLimit); static sqInt NoDbgRegParms pcRelativeAddressAt(AbstractInstruction * self_in_pcRelativeAddressAt, sqInt instrAddress); static AbstractInstruction * NoDbgRegParms relocateMethodReferenceBeforeAddressby(AbstractInstruction * self_in_relocateMethodReferenceBeforeAddressby, sqInt pc, sqInt delta); static sqInt NoDbgRegParms rewriteFullTransferAttargetexpectedInstruction(AbstractInstruction * self_in_rewriteFullTransferAttargetexpectedInstruction, usqInt callSiteReturnAddress, usqInt callTargetAddress, sqInt expectedInstruction); static sqInt NoDbgRegParms rewriteInlineCacheAttagtarget(AbstractInstruction * self_in_rewriteInlineCacheAttagtarget, usqInt callSiteReturnAddress, sqInt cacheTag, usqInt callTargetAddress); static AbstractInstruction * NoDbgRegParms rewriteInlineCacheTagat(AbstractInstruction * self_in_rewriteInlineCacheTagat, sqInt cacheTag, sqInt callSiteReturnAddress); static usqInt NoDbgRegParms sizePCDependentInstructionAt(AbstractInstruction * self_in_sizePCDependentInstructionAt, sqInt eventualAbsoluteAddress); static AbstractInstruction * NoDbgRegParms storeLiteralbeforeFollowingAddress(AbstractInstruction * self_in_storeLiteralbeforeFollowingAddress, sqInt literal, sqInt followingAddress); static AbstractInstruction * NoDbgRegParms updateLabel(AbstractInstruction * self_in_updateLabel, AbstractInstruction *labelInstruction); static sqInt NoDbgRegParms usesOutOfLineLiteral(AbstractInstruction * self_in_usesOutOfLineLiteral); static SimStackEntry * NoDbgRegParms ensureSpilledAtfrom(SimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister); static sqInt NoDbgRegParms isSameEntryAs(SimStackEntry * self_in_isSameEntryAs, CogSimStackEntry *ssEntry); static SimStackEntry * NoDbgRegParms popToReg(SimStackEntry * self_in_popToReg, sqInt reg); static sqInt NoDbgRegParms registerMask(SimStackEntry * self_in_registerMask); static sqInt NoDbgRegParms registerMaskOrNone(SimStackEntry * self_in_registerMaskOrNone); static sqInt NoDbgRegParms registerOrNone(SimStackEntry * self_in_registerOrNone); static SimStackEntry * NoDbgRegParms storeToReg(SimStackEntry * self_in_storeToReg, sqInt reg); static sqInt NoDbgRegParms isMergeFixup(BytecodeFixup * self_in_isMergeFixup); static AbstractInstruction * NoDbgRegParms allocateLiteral(sqInt aLiteral); static AbstractInstruction * NoDbgRegParms checkLiteralforInstruction(sqInt literal, AbstractInstruction *anInstruction); static AbstractInstruction * NoDbgRegParms checkQuickConstantforInstruction(sqInt literal, AbstractInstruction *anInstruction); static sqInt NoDbgRegParms dumpLiterals(sqInt generateBranchAround); static sqInt endSizeOffset(void); static sqInt NoDbgRegParms literalInstructionInRange(AbstractInstruction *litInst); static AbstractInstruction * NoDbgRegParms locateLiteral(sqInt aLiteral); static sqInt NoDbgRegParms mustDumpLiterals(sqInt currentOpcodeIndex); static sqInt compileBlockDispatch(void); static void compileGetErrorCode(void); static sqInt compileInterpreterPrimitive(void); static sqInt NoDbgRegParms compileInterpreterPrimitiveflags(void (*primitiveRoutine)(void), sqInt flags); static sqInt NoDbgRegParms compileMachineCodeInterpreterPrimitive(void (*primitiveRoutine)(void)); static AbstractInstruction * NoDbgRegParms compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selector, sqInt shift, sqInt baseRegOrNone); static void NoDbgRegParms compileOpenPICnumArgs(sqInt selector, sqInt numArgs); static AbstractInstruction * NoDbgRegParms compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selectorReg, sqInt shift, sqInt baseRegOrNone); static sqInt compilePrimitive(void); static sqInt extendedPushBytecode(void); static sqInt extendedStoreAndPopBytecode(void); static sqInt extendedStoreBytecode(void); static sqInt NoDbgRegParms frameOffsetOfTemporary(sqInt index); static sqInt genCallMappedInlinedPrimitive(void); static AbstractInstruction * NoDbgRegParms genDoubleFailIfZeroArgRcvrarg(int rcvrReg, int argReg); static sqInt genExtendedSendBytecode(void); static sqInt genExtendedSuperBytecode(void); static sqInt genExtJumpIfFalse(void); static sqInt genExtJumpIfTrue(void); static sqInt genExtNopBytecode(void); static sqInt genExtPushCharacterBytecode(void); static sqInt genExtPushIntegerBytecode(void); static sqInt genExtPushLiteralBytecode(void); static sqInt genExtPushLiteralVariableBytecode(void); static sqInt genExtPushPseudoVariable(void); static sqInt genExtPushReceiverVariableBytecode(void); static sqInt genExtSendBytecode(void); static sqInt genExtSendSuperBytecode(void); static sqInt genExtStoreAndPopLiteralVariableBytecode(void); static sqInt genExtStoreAndPopReceiverVariableBytecode(void); static sqInt genExtStoreLiteralVariableBytecode(void); static sqInt genExtStoreReceiverVariableBytecode(void); static sqInt genExtUnconditionalJump(void); static sqInt genFastPrimFail(void); static void NoDbgRegParms genFastPrimTraceUsingand(sqInt r1, sqInt r2); static sqInt genLongJumpIfFalse(void); static sqInt genLongJumpIfTrue(void); static sqInt genLongPushTemporaryVariableBytecode(void); static sqInt genLongStoreAndPopTemporaryVariableBytecode(void); static sqInt genLongStoreTemporaryVariableBytecode(void); static sqInt genLongUnconditionalBackwardJump(void); static sqInt genLongUnconditionalForwardJump(void); static sqInt NoDbgRegParms genLookupForPerformNumArgs(sqInt numArgs); static AbstractInstruction * NoDbgRegParms genMoveConstantR(sqInt constant, sqInt reg); static sqInt NoDbgRegParms genMustBeBooleanTrampolineForcalled(sqInt boolean, char *trampolineName); static sqInt genPrimitiveHashMultiply(void); static void NoDbgRegParms genPrimReturnEnterCogCodeEnilopmart(sqInt profiling); static sqInt genPushClosureTempsBytecode(void); static sqInt genPushConstantFalseBytecode(void); static sqInt genPushConstantNilBytecode(void); static sqInt genPushConstantOneBytecode(void); static sqInt genPushConstantTrueBytecode(void); static sqInt genPushConstantZeroBytecode(void); static sqInt genPushLiteralConstantBytecode(void); static sqInt genPushLiteralVariable16CasesBytecode(void); static sqInt genPushLiteralVariableBytecode(void); static sqInt genPushQuickIntegerConstantBytecode(void); static sqInt genPushReceiverVariableBytecode(void); static sqInt genPushTemporaryVariableBytecode(void); extern sqInt genQuickReturnConst(void); extern sqInt genQuickReturnInstVar(void); extern sqInt genQuickReturnSelf(void); static sqInt genReturnFalse(void); static sqInt genReturnNil(void); static sqInt genReturnNilFromBlock(void); static sqInt genReturnTrue(void); static sqInt genSecondExtendedSendBytecode(void); static sqInt genSendLiteralSelector0ArgsBytecode(void); static sqInt genSendLiteralSelector1ArgBytecode(void); static sqInt genSendLiteralSelector2ArgsBytecode(void); static sqInt genShortJumpIfFalse(void); static sqInt genShortJumpIfTrue(void); static sqInt genShortUnconditionalJump(void); static sqInt genSpecialSelectorEqualsEquals(void); static sqInt genSpecialSelectorNotEqualsEquals(void); static sqInt genSpecialSelectorSend(void); static sqInt genStoreAndPopReceiverVariableBytecode(void); static sqInt genStoreAndPopRemoteTempLongBytecode(void); static sqInt genStoreAndPopTemporaryVariableBytecode(void); static sqInt genStoreRemoteTempLongBytecode(void); static sqInt genUnconditionalTrapBytecode(void); extern sqInt mapPCDataForinto(CogMethod *cogMethod, sqInt arrayObj); static void maybeCompileAllocFillerCheck(void); static sqInt numSpecialSelectors(void); static usqInt NoDbgRegParms pcDataForBlockEntryMethod(sqInt blockEntryMcpc, sqInt cogMethod); static sqInt NoDbgRegParms pcDataForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg); static PrimitiveDescriptor * primitiveGeneratorOrNil(void); extern void recordCallOffsetIn(CogMethod *cogMethod); extern void rewritePrimInvocationInto(CogMethod *cogMethod, void (*primFunctionPointer)(void)); static sqInt NoDbgRegParms seemsToBeInstantiating(sqInt format); static sqInt NoDbgRegParms v3BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v3ShortForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static sqInt NoDbgRegParms v4LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); extern void voidCogCompiledCode(void); static BlockStart * NoDbgRegParms addBlockStartAtnumArgsnumCopiedspan(sqInt bytecodepc, sqInt numArgs, sqInt numCopied, sqInt span); static void NoDbgRegParms adjustArgumentsForPerform(sqInt numArgs); static sqInt NoDbgRegParms allocateRegForStackEntryAtnotConflictingWith(sqInt index, sqInt regMask); static sqInt NoDbgRegParms allocateRegNotConflictingWith(sqInt regMask); static sqInt NoDbgRegParms anyReferencesToRegisterinTopNItems(sqInt reg, sqInt n); extern void callCogCodePopReceiverArg0Regs(void); extern void callCogCodePopReceiverArg1Arg0Regs(void); static sqInt NoDbgRegParms compileAbstractInstructionsFromthrough(sqInt start, sqInt end); static sqInt compileBlockBodies(void); static void NoDbgRegParms compileBlockFrameBuild(BlockStart *blockStart); static void NoDbgRegParms compileBlockFramelessEntry(BlockStart *blockStart); static CogMethod * NoDbgRegParms compileCogFullBlockMethod(sqInt numCopied); static CogMethod * NoDbgRegParms compileCogMethod(sqInt selector); static sqInt compileEntireMethod(void); static void compileFrameBuild(void); static void NoDbgRegParms compileFullBlockFramelessEntry(sqInt numCopied); static void NoDbgRegParms compileFullBlockMethodFrameBuild(sqInt numCopied); #if IMMUTABILITY static void compileTwoPathFrameBuild(void); #endif /* IMMUTABILITY */ static void compileTwoPathFramelessInit(void); static sqInt NoDbgRegParms cPICMissTrampolineFor(sqInt numArgs); static sqInt doubleExtendedDoAnythingBytecode(void); static sqInt duplicateTopBytecode(void); static BytecodeFixup * NoDbgRegParms ensureFixupAt(sqInt targetPC); static BytecodeFixup * NoDbgRegParms ensureNonMergeFixupAt(sqInt targetPC); static void ensureReceiverResultRegContainsSelf(void); static void NoDbgRegParms evaluateat(BytecodeDescriptor *descriptor, sqInt pc); static sqInt NoDbgRegParms eventualTargetOf(sqInt targetBytecodePC); static sqInt NoDbgRegParms freeAnyRegNotConflictingWith(sqInt regMask); static sqInt genBlockReturn(void); static void (*genCallPICEnilopmartNumArgs(sqInt numArgs))(void) ; static sqInt genCallPrimitiveBytecode(void); static sqInt genExternalizePointersForPrimitiveCall(void); static sqInt genExtPushClosureBytecode(void); static sqInt genExtPushFullClosureBytecode(void); static void generateEnilopmarts(void); static sqInt NoDbgRegParms generateInstructionsAt(sqInt eventualAbsoluteAddress); static void generateMissAbortTrampolines(void); static void generateSendTrampolines(void); static void generateTracingTrampolines(void); static sqInt NoDbgRegParms genForwardersInlinedIdenticalOrNotIf(sqInt orNot); static sqInt NoDbgRegParms genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(sqInt argIsConstant, sqInt rcvrIsConstant, sqInt argReg, sqInt rcvrRegOrNone, sqInt orNot); static sqInt NoDbgRegParms genInlinedIdenticalOrNotIf(sqInt orNot); static sqInt NoDbgRegParms genJumpBackTo(sqInt targetBytecodePC); static sqInt NoDbgRegParms genJumpIfto(sqInt boolean, sqInt targetBytecodePC); static sqInt NoDbgRegParms genJumpTo(sqInt targetBytecodePC); static sqInt NoDbgRegParms genMarshalledSendnumArgssendTable(sqInt selectorIndex, sqInt numArgs, sqInt *sendTable); static sqInt NoDbgRegParms genMethodAbortTrampolineFor(sqInt numArgs); static sqInt NoDbgRegParms genPICAbortTrampolineFor(sqInt numArgs); static sqInt NoDbgRegParms genPICMissTrampolineFor(sqInt numArgs); static sqInt genPopStackBytecode(void); static sqInt genPrimitiveClosureValue(void); static sqInt genPrimitiveFullClosureValue(void); static sqInt genPrimitivePerform(void); static sqInt genPushActiveContextBytecode(void); static sqInt genPushClosureCopyCopiedValuesBytecode(void); static sqInt NoDbgRegParms genPushLiteralIndex(sqInt literalIndex); static sqInt NoDbgRegParms genPushLiteralVariable(sqInt literalIndex); static sqInt NoDbgRegParms genPushLiteral(sqInt literal); static sqInt NoDbgRegParms genPushMaybeContextReceiverVariable(sqInt slotIndex); static sqInt genPushNewArrayBytecode(void); static sqInt genPushReceiverBytecode(void); static sqInt NoDbgRegParms genPushReceiverVariable(sqInt index); static void genPushRegisterArgs(void); static sqInt genPushRemoteTempLongBytecode(void); static sqInt NoDbgRegParms genPushTemporaryVariable(sqInt index); static sqInt genReturnReceiver(void); static sqInt genReturnTopFromBlock(void); static sqInt genReturnTopFromMethod(void); static sqInt NoDbgRegParms genSendDirectedSupernumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt NoDbgRegParms genSendSupernumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt NoDbgRegParms genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3); static sqInt NoDbgRegParms genSendnumArgs(sqInt selectorIndex, sqInt numArgs); static sqInt genSpecialSelectorArithmetic(void); static sqInt genSpecialSelectorClass(void); static sqInt genSpecialSelectorComparison(void); static sqInt genStaticallyResolvedSpecialSelectorComparison(void); static sqInt NoDbgRegParms genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt litVarIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck); static sqInt NoDbgRegParms genStorePopRemoteTempAtneedsStoreCheck(sqInt popBoolean, sqInt slotIndex, sqInt remoteTempIndex, sqInt needsStoreCheck); static sqInt NoDbgRegParms genStorePopTemporaryVariable(sqInt popBoolean, sqInt tempIndex); static sqInt genUpArrowReturn(void); static void NoDbgRegParms initSimStackForFramefulMethod(sqInt startpc); static void NoDbgRegParms initSimStackForFramelessBlock(sqInt startpc); static void NoDbgRegParms initSimStackForFramelessMethod(sqInt startpc); static sqInt liveRegisters(void); static sqInt NoDbgRegParms mapDeadDescriptorIfNeeded(BytecodeDescriptor *descriptor); static void NoDbgRegParms marshallSendArguments(sqInt numArgs); static sqInt maybeCompilingFirstPassOfBlockWithInitialPushNil(void); static sqInt NoDbgRegParms mergeWithFixupIfRequired(BytecodeFixup *fixup); static sqInt NoDbgRegParms methodAbortTrampolineFor(sqInt numArgs); static sqInt methodFoundInvalidPostScan(void); static sqInt NoDbgRegParms needsFrameIfMod16GENumArgs(sqInt stackDelta); static sqInt NoDbgRegParms needsFrameIfStackGreaterThanOne(sqInt stackDelta); static sqInt NoDbgRegParms numberOfSpillsInTopNItems(sqInt n); static sqInt NoDbgRegParms picAbortTrampolineFor(sqInt numArgs); static sqInt prevInstIsPCAnnotated(void); static sqInt receiverIsInReceiverResultReg(void); static void NoDbgRegParms reinitializeFixupsFromthrough(sqInt start, sqInt end); static sqInt NoDbgRegParms scanBlock(BlockStart *blockStart); static sqInt scanMethod(void); static sqInt NoDbgRegParms squeakV3orSistaV1PushNilSizenumInitialNils(sqInt aMethodObj, sqInt numInitialNils); static sqInt NoDbgRegParms squeakV3orSistaV1NumPushNils(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj); static void NoDbgRegParms ssAllocateRequiredRegMaskupThroughupThroughNative(sqInt requiredRegsMask, sqInt stackPtr, sqInt nativeStackPtr); static void NoDbgRegParms ssFlushUpThroughReceiverVariable(sqInt slotIndex); static void NoDbgRegParms ssFlushUpThroughTemporaryVariable(sqInt tempIndex); static void NoDbgRegParms ssPop(sqInt n); static sqInt NoDbgRegParms ssPushAnnotatedConstant(sqInt literal); static sqInt NoDbgRegParms ssPushBaseoffset(sqInt reg, sqInt offset); static sqInt NoDbgRegParms ssPushConstant(sqInt literal); static sqInt NoDbgRegParms ssPushDesc(SimStackEntry simStackEntry); static sqInt NoDbgRegParms ssPushRegister(sqInt reg); static void NoDbgRegParms ssPush(sqInt n); static SimStackEntry ssSelfDescriptor(void); static void NoDbgRegParms ssStoreAndReplacePoptoReg(sqInt popBoolean, sqInt reg); static sqInt NoDbgRegParms ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg); static void NoDbgRegParms ssStorePoptoReg(sqInt popBoolean, sqInt reg); static CogSimStackEntry * ssTop(void); static CogSimStackEntry * NoDbgRegParms ssValue(sqInt n); static sqInt NoDbgRegParms stackEntryIsBoolean(CogSimStackEntry *simStackEntry); static sqInt tempsValidAndVolatileEntriesSpilled(void); static sqInt NoDbgRegParms tryCollapseTempVectorInitializationOfSize(sqInt slots); static sqInt violatesEnsureSpilledSpillAssert(void); static void voidReceiverResultRegContainsSelf(void); /*** Variables ***/ static AbstractInstruction * abstractOpcodes; static AbstractInstruction aMethodLabel; static AbstractInstruction * const backEnd = &aMethodLabel; static usqInt baseAddress; static sqInt blockCount; static AbstractInstruction * blockEntryLabel; static AbstractInstruction * blockEntryNoContextSwitch; sqInt blockNoContextSwitchOffset; static BlockStart * blockStarts; static sqInt breakBlock; static sqInt breakMethod; sqInt breakPC; static sqInt byte0; static sqInt byte1; static sqInt byte2; static sqInt byte3; static sqInt bytecodePC; static sqInt bytecodeSetOffset; void * CFramePointer; void * CStackPointer; sqInt cbEntryOffset; sqInt cbNoSwitchEntryOffset; sqInt ceBaseFrameReturnTrampoline; static sqInt ceByteSizeOfTrampoline; void (*ceCall0ArgsPIC)(void); void (*ceCall1ArgsPIC)(void); void (*ceCall2ArgsPIC)(void); void (*ceCallCogCodePopReceiverAndClassRegs)(void); void (*ceCallCogCodePopReceiverArg0Regs)(void); void (*ceCallCogCodePopReceiverArg1Arg0Regs)(void); void (*ceCallCogCodePopReceiverReg)(void); sqInt ceCannotResumeTrampoline; void (*ceCaptureCStackPointers)(void); static usqIntptr_t (*ceCheckFeaturesFunction)(void); sqInt ceCheckForInterruptTrampoline; static sqInt ceCPICMissTrampoline; void (*ceEnterCogCodePopReceiverReg)(void); static sqInt ceFetchContextInstVarTrampoline; static sqInt ceFFICalloutTrampoline; static sqInt ceFloatObjectOfTrampoline; static sqInt ceFloatValueOfTrampoline; static void (*ceFlushICache)(usqIntptr_t from, usqIntptr_t to); static sqInt ceFreeTrampoline; usqIntptr_t (*ceGetFP)(void); usqIntptr_t (*ceGetSP)(void); static sqInt ceInlineNewHashTrampoline; static sqInt ceInstantiateClassIndexableSizeTrampoline; static sqInt ceInstantiateClassTrampoline; static sqInt ceLargeActiveContextInBlockTrampoline; static sqInt ceLargeActiveContextInFullBlockTrampoline; static sqInt ceLargeActiveContextInMethodTrampoline; static sqInt ceMallocTrampoline; static sqInt ceMethodAbortTrampoline; static sqInt ceNewHashTrampoline; static sqInt ceNonLocalReturnTrampoline; static sqInt cePICAbortTrampoline; static sqInt cePositive32BitIntegerTrampoline; static sqInt cePositive32BitValueOfTrampoline; static sqInt cePositive64BitIntegerTrampoline; static sqInt cePositive64BitValueOfTrampoline; static sqInt cePrimReturnEnterCogCode; static sqInt cePrimReturnEnterCogCodeProfiling; static sqInt ceReapAndResetErrorCodeTrampoline; sqInt ceReturnToInterpreterTrampoline; static sqInt ceScheduleScavengeTrampoline; static sqInt ceSendMustBeBooleanAddFalseTrampoline; static sqInt ceSendMustBeBooleanAddTrueTrampoline; static sqInt ceSigned32BitIntegerTrampoline; static sqInt ceSigned32BitValueOfTrampoline; static sqInt ceSigned64BitIntegerTrampoline; static sqInt ceSigned64BitValueOfTrampoline; static sqInt ceSmallActiveContextInBlockTrampoline; static sqInt ceSmallActiveContextInFullBlockTrampoline; static sqInt ceSmallActiveContextInMethodTrampoline; static sqInt ceStoreCheckContextReceiverTrampoline; static sqInt ceStoreCheckTrampoline; static sqInt ceStoreContextInstVarTrampoline; #if IMMUTABILITY sqInt ceStoreTrampolines[5]; #endif static sqInt ceTraceBlockActivationTrampoline; static sqInt ceTraceLinkedSendTrampoline; static sqInt ceTraceStoreTrampoline; usqIntptr_t (*ceTryLockVMOwner)(void); void (*ceUnlockVMOwner)(void); sqInt cFramePointerInUse; static sqInt checkedEntryAlignment; static sqInt closedPICSize; sqInt cmEntryOffset; sqInt cmNoCheckEntryOffset; static sqInt codeBase; static sqInt codeModified; static sqInt cogConstituentIndex; static sqInt compactionInProgress; static sqInt compilationPass; static sqInt compilationTrace; static sqInt cPICCaseSize; static sqInt cPICEndOfCodeOffset; static sqInt cPICEndSize; static sqInt cPICPrototype; static sqInt currentCallCleanUpSize; static sqInt deadCode; static sqInt debugBytecodePointers; static sqInt debugFixupBreaks; static sqInt debugOpcodeIndices; usqIntptr_t debugPrimCallStackOffset; static sqInt debugStackPointers; static sqInt directedSendUsesBinding; static sqInt directedSuperBindingSendTrampolines[NumSendTrampolines]; static sqInt directedSuperSendTrampolines[NumSendTrampolines]; static sqInt disassemblingMethod; static AbstractInstruction * endCPICCase0; static sqInt endPC; static AbstractInstruction * entry; static sqInt entryPointMask; static CogMethod * enumeratingCogMethod; static sqInt expectedFPAlignment; static sqInt expectedSPAlignment; static sqInt extA; static sqInt extB; static sqInt externalPrimCallOffsets[MaxNumArgs + 1]; static sqInt externalPrimJumpOffsets[MaxNumArgs + 1]; static sqInt externalSetPrimOffsets[MaxNumArgs + 1]; static sqInt firstCPICCaseOffset; static sqInt firstOpcodeIndex; static sqInt firstSend; static BytecodeFixup * fixups; static AbstractInstruction * fullBlockEntry; static AbstractInstruction * fullBlockNoContextSwitchEntry; static BytecodeDescriptor generatorTable[512] = { { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushReceiverBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantTrueBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantFalseBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantNilBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushQuickIntegerConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genReturnReceiver, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTrue, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnFalse, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNil, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromMethod, 0, needsFrameIfInBlock, -1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extendedPushBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { extendedStoreBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { extendedStoreAndPopBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtendedSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { doubleExtendedDoAnythingBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtendedSuperBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, { genSecondExtendedSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genPopStackBytecode, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { duplicateTopBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushActiveContextBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushNewArrayBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genCallPrimitiveBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushClosureCopyCopiedValuesBytecode, v3BlockCodeSize, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalBackwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongUnconditionalForwardJump, v3LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfTrue, v3LongForwardBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genLongJumpIfFalse, v3LongForwardBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AddRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, SubRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLess, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreater, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLessOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreaterOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpNonZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AndRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, OrRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorClass, 0, needsFrameIfStackGreaterThanOne, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorNotEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushReceiverVariableBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralVariable16CasesBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushLiteralConstantBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushTemporaryVariableBytecode, 0, needsFrameIfMod16GENumArgs, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushReceiverBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantTrueBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantFalseBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantNilBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantZeroBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPushConstantOneBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushPseudoVariable, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { duplicateTopBytecode, 0, needsFrameNever, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genReturnReceiver, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTrue, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnFalse, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNil, 0, needsFrameIfInBlock, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnTopFromMethod, 0, needsFrameIfInBlock, -1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, { genReturnNilFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { genReturnTopFromBlock, 0, needsFrameNever, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { genExtNopBytecode, 0, needsFrameNever, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AddRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, SubRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLess, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreater, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpLessOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpGreaterOrEqual, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorComparison, 0, 0, 0, JumpNonZero, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, AndRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorArithmetic, 0, 0, 0, OrRR, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorClass, 0, needsFrameIfStackGreaterThanOne, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorNotEqualsEquals, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSpecialSelectorSend, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector0ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector1ArgBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genSendLiteralSelector2ArgsBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortUnconditionalJump, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfTrue, v3ShortForwardBranchDistance, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genShortJumpIfFalse, v3ShortForwardBranchDistance, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopReceiverVariableBytecode, 0, needsFrameIfImmutability, -1, 0, 1, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 1, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genPopStackBytecode, 0, needsFrameNever, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genUnconditionalTrapBytecode, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extABytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { extBBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genExtPushReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, { genExtPushLiteralVariableBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushLiteralBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genLongPushTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genPushNewArrayBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushIntegerBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushCharacterBytecode, 0, needsFrameNever, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtSendBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtSendSuperBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genCallMappedInlinedPrimitive, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }, { genExtUnconditionalJump, v4LongBranchDistance, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtJumpIfTrue, v4LongBranchDistance, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtJumpIfFalse, v4LongBranchDistance, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, { genExtStoreAndPopReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtStoreAndPopLiteralVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 0, 0, 0 }, { genLongStoreAndPopTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtStoreReceiverVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 1, 0, 0 }, { genExtStoreLiteralVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, IMMUTABILITY, 0, 0, 0, 0, 0 }, { genLongStoreTemporaryVariableBytecode, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { genCallPrimitiveBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, { genExtPushFullClosureBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genExtPushClosureBytecode, v4BlockCodeSize, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { genPushRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { genStoreAndPopRemoteTempLongBytecode, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { unknownBytecode, 0, 0, 0, Nop, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 } }; static sqInt guardPageSize; static sqInt hasNativeFrame; static sqInt hasYoungReferent; static sqInt inBlock; static sqInt initialPC; static sqInt introspectionData; static sqInt introspectionDataIndex; static int labelCounter; static sqInt lastDumpedLiteralIndex; static sqInt lastSend; static usqInt limitAddress; static AbstractInstruction * literals; static sqInt literalsSize; static sqInt maxLitIndex; static sqInt methodAbortTrampolines[4]; static sqInt methodBytesFreedSinceLastCompaction; static sqInt methodCount; static sqInt methodHeader; static AbstractInstruction * const methodLabel = &aMethodLabel; static sqInt methodObj; static sqInt methodOrBlockNumArgs; static sqInt methodOrBlockNumTemps; static sqInt methodZoneBase; static usqIntptr_t minValidCallAddress; sqInt missOffset; static usqInt mzFreeStart; static sqInt needsFrame; static sqInt nextLiteralIndex; static AbstractInstruction * noCheckEntry; static sqInt numAbstractOpcodes; static sqInt numExtB; static usqInt objectReferencesInRuntime[NumObjRefsInRuntime+1]; static sqInt opcodeIndex; static CogMethod *openPICList = 0; static sqInt openPICSize; static sqInt ordinarySendTrampolines[NumSendTrampolines]; static sqInt picAbortTrampolines[4]; static AbstractInstruction * picInterpretAbort; static sqInt picMissTrampolines[4]; static AbstractInstruction * picMNUAbort; static void (*postCompileHook)(CogMethod *); static BytecodeDescriptor * prevBCDescriptor; static AbstractInstruction * primInvokeInstruction; static sqInt primitiveIndex; static AbstractInstruction * primSetFunctionLabel; void (*realCECallCogCodePopReceiverAndClassRegs)(void); void (*realCECallCogCodePopReceiverArg0Regs)(void); void (*realCECallCogCodePopReceiverArg1Arg0Regs)(void); void (*realCECallCogCodePopReceiverReg)(void); void (*realCEEnterCogCodePopReceiverReg)(void); static sqInt receiverTags; static sqInt regArgsHaveBeenPushed; static sqInt runtimeObjectRefIndex; static AbstractInstruction * sendMiss; static sqInt simNativeSpillBase; static sqInt simNativeStack; static sqInt simNativeStackPtr; static sqInt simNativeStackSize; static sqInt simSpillBase; static SimStackEntry simStack[70]; static sqInt simStackPtr; static AbstractInstruction * stackCheckLabel; static AbstractInstruction * stackOverflowCall; static sqInt superSendTrampolines[NumSendTrampolines]; static sqInt tempOop; int traceFlags = 8 /* prim trace log on by default */; sqInt traceStores; static char *trampolineAddresses[NumTrampolines*2]; static sqInt trampolineTableIndex; static sqInt uncheckedEntryAlignment; static usqInt unpairedMethodList; static sqInt useTwoPaths; static usqInt youngReferrers; /*** Macros ***/ #define flushICacheFromto(me,startAddress,endAddress) __clear_cache((char*) startAddress, (char*) (endAddress )) #define cPICNumCases stackCheckOffset #define cPICNumCasesHack hack hack hack i.e. the getter macro does all the work #define abstractInstructionAt(index) (&abstractOpcodes[index]) #define allocateBlockStarts(numBlocks) do { \ blockStarts = (numBlocks) ? alloca(sizeof(BlockStart) * (numBlocks)) : 0; \ } while (0) #define backEnd() backEnd #define blockAlignment(self) 8 #define blockStartAt(index) (&blockStarts[index]) #define breakOnImplicitReceiver() (traceFlags & 64) #define ceBaseFrameReturnPC() ceBaseFrameReturnTrampoline #define ceCannotResumePC() ((usqInt)ceCannotResumeTrampoline) #define ceCheckFeatures() ceCheckFeaturesFunction() #define ceReturnToInterpreterPC() ((usqInt)ceReturnToInterpreterTrampoline) #define cFramePointerAddress() ((usqIntptr_t)&CFramePointer) #define compileSendTrace() ((traceFlags & 258) == 258) #define cr() putchar('\n') #define cStackPointerAddress() ((usqIntptr_t)&CStackPointer) #define entryOffset() cmEntryOffset #define generatorAt(index) (&generatorTable[index]) #define getCFramePointer() CFramePointer #define getCStackPointer() CStackPointer #define getIsObjectReference() 2 #define halt() warning("halt") #define haltmsg(msg) warning("halt: " msg) #define interpretOffset() missOffset #define maxCogCodeSize() (16*1024*1024) #define maybeBreakGeneratingAt(address) 0 #define maybeHaltIfDebugPC() 0 #define methodLabel() methodLabel #define methodZoneBase() methodZoneBase #define minCallAddress() minValidCallAddress #define noCheckEntryOffset() cmNoCheckEntryOffset #define noContextSwitchBlockEntryOffset() blockNoContextSwitchOffset #define notYetImplemented() warning("not yet implemented") #define printNum(n) printf("%" PRIdSQINT, (sqInt) (n)) #define printOnTrace() (traceFlags & 1) #define print(aString) printf("%s", aString) #define recordBlockTrace() (traceFlags & 4) #define recordEventTrace() (traceFlags & 16) #define recordOverflowTrace() (traceFlags & 32) #define recordPrimTrace() (traceFlags & 8) #define recordSendTrace() (traceFlags & 2) #define reportError(n) warning("compilation error") #define setCFramePointer(theFP) (CFramePointer = (void *)(theFP)) #define setCStackPointer(theSP) (CStackPointer = (void *)(theSP)) #define tryLockVMOwner() (ceTryLockVMOwner() != 0) #define unlockVMOwner() ceUnlockVMOwner() #define nextOpenPIC methodObject #define nextOpenPICHack hack hack hack i.e. the getter macro does all the work #define freeStart() mzFreeStart #define limitZony() ((CogMethod *)mzFreeStart) #define methodBytesFreedSinceLastCompaction() methodBytesFreedSinceLastCompaction #define roundUpLength(numBytes) ((numBytes) + 7 & -8) #define youngReferrers() youngReferrers #define maybeConstant(sse) ((sse)->constant) #define literalInstructionAt(index) (&literals[index]) #define fullBlockEntryOffset() cbEntryOffset #define fullBlockNoContextSwitchEntryOffset() cbNoSwitchEntryOffset #define fixupAtIndex(index) (&fixups[index]) #define simNativeStackAt(index) (simNativeStack + (index)) #define simSelf() simStack #define simStackAt(index) (simStack + (index)) #define traceDescriptor(ign) 0 #define traceFixupmerge(igu,ana) 0 #define traceMerge(ign) 0 #define traceSimStack() 0 #define traceSpill(ign) 0 #define allocatype(numElements, elementType) alloca((numElements)*sizeof(elementType)) #define numElementsIn(anArray) (sizeof(anArray)/sizeof(anArray[0])) #define oopisGreaterThanOrEqualTo(anOop,otherOop) ((usqInt)(anOop) >= (usqInt)(otherOop)) #define oopisGreaterThanOrEqualToandLessThanOrEqualTo(anOop,baseOop,limitOop) ((usqInt)(anOop) >= (usqInt)(baseOop) && (usqInt)(anOop) <= (usqInt)(limitOop)) #define oopisGreaterThanOrEqualToandLessThan(anOop,baseOop,limitOop) ((usqInt)(anOop) >= (usqInt)(baseOop) && (usqInt)(anOop) < (usqInt)(limitOop)) #define oopisGreaterThan(anOop,otherOop) ((usqInt)(anOop) > (usqInt)(otherOop)) #define oopisGreaterThanandLessThan(anOop,baseOop,limitOop) ((usqInt)(anOop) > (usqInt)(baseOop) && (usqInt)(anOop) < (usqInt)(limitOop)) #define oopisLessThanOrEqualTo(anOop,otherOop) ((usqInt)(anOop) <= (usqInt)(otherOop)) #define oopisLessThan(anOop,otherOop) ((usqInt)(anOop) < (usqInt)(otherOop)) /* CogAbstractInstruction>>#addDependent: */ static AbstractInstruction * NoDbgRegParms addDependent(AbstractInstruction * self_in_addDependent, AbstractInstruction *anInstruction) { if (!(((self_in_addDependent->dependent)) == null)) { (anInstruction->dependent = (self_in_addDependent->dependent)); } return ((self_in_addDependent->dependent) = anInstruction); } /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. */ /* CogAbstractInstruction>>#availableFloatRegisterOrNoneFor: */ static sqInt NoDbgRegParms availableFloatRegisterOrNoneFor(AbstractInstruction * self_in_availableFloatRegisterOrNoneFor, sqInt liveRegsMask) { if (!(liveRegsMask & (1U << DPFPReg0))) { return DPFPReg0; } if (!(liveRegsMask & (1U << DPFPReg1))) { return DPFPReg1; } if (!(liveRegsMask & (1U << DPFPReg2))) { return DPFPReg2; } if (!(liveRegsMask & (1U << DPFPReg3))) { return DPFPReg3; } if (!(liveRegsMask & (1U << DPFPReg4))) { return DPFPReg4; } if (!(liveRegsMask & (1U << DPFPReg5))) { return DPFPReg5; } if (!(liveRegsMask & (1U << DPFPReg6))) { return DPFPReg6; } if (!(liveRegsMask & (1U << DPFPReg7))) { return DPFPReg7; } return NoReg; } /* For out-of-line literal support, clone a literal from a literal. */ /* CogAbstractInstruction>>#cloneLiteralFrom: */ static AbstractInstruction * NoDbgRegParms cloneLiteralFrom(AbstractInstruction * self_in_cloneLiteralFrom, AbstractInstruction *existingLiteral) { assert((((existingLiteral->opcode)) == Literal) && ((((self_in_cloneLiteralFrom->dependent)) == null) && (((self_in_cloneLiteralFrom->address)) == null))); (self_in_cloneLiteralFrom->opcode) = Literal; (self_in_cloneLiteralFrom->annotation) = (existingLiteral->annotation); ((self_in_cloneLiteralFrom->operands))[0] = (((existingLiteral->operands))[0]); ((self_in_cloneLiteralFrom->operands))[1] = (((existingLiteral->operands))[1]); ((self_in_cloneLiteralFrom->operands))[2] = (((existingLiteral->operands))[2]); return self_in_cloneLiteralFrom; } /* Generic register swap code. Subclasses for processors that have a true exchange operation will override to use it. */ /* CogAbstractInstruction>>#genSwapR:R:Scratch: */ static AbstractInstruction * NoDbgRegParms genSwapRRScratch(AbstractInstruction * self_in_genSwapRRScratch, sqInt regA, sqInt regB, sqInt regTmp) { AbstractInstruction *first; first = genoperandoperand(MoveRR, regA, regTmp); genoperandoperand(MoveRR, regB, regA); genoperandoperand(MoveRR, TempReg, regB); return first; } /* CogAbstractInstruction>>#genWriteCResultIntoReg: */ static AbstractInstruction * NoDbgRegParms genWriteCResultIntoReg(AbstractInstruction * self_in_genWriteCResultIntoReg, sqInt abstractRegister) { sqInt cResultReg; cResultReg = R0; if (abstractRegister != cResultReg) { genoperandoperand(MoveRR, cResultReg, abstractRegister); } return self_in_genWriteCResultIntoReg; } /* For out-of-line literal support, initialize a sharable literal. */ /* CogAbstractInstruction>>#initializeSharableLiteral: */ static AbstractInstruction * NoDbgRegParms initializeSharableLiteral(AbstractInstruction * self_in_initializeSharableLiteral, sqInt literal) { (self_in_initializeSharableLiteral->opcode) = Literal; /* separate := nil for Slang */ (self_in_initializeSharableLiteral->annotation) = null; (self_in_initializeSharableLiteral->address) = null; (self_in_initializeSharableLiteral->dependent) = null; ((self_in_initializeSharableLiteral->operands))[0] = literal; ((self_in_initializeSharableLiteral->operands))[1] = 1; ((self_in_initializeSharableLiteral->operands))[2] = -1; return self_in_initializeSharableLiteral; } /* For out-of-line literal support, initialize an unsharable literal. */ /* CogAbstractInstruction>>#initializeUniqueLiteral: */ static AbstractInstruction * NoDbgRegParms initializeUniqueLiteral(AbstractInstruction * self_in_initializeUniqueLiteral, sqInt literal) { (self_in_initializeUniqueLiteral->opcode) = Literal; /* separate := nil for Slang */ (self_in_initializeUniqueLiteral->annotation) = null; (self_in_initializeUniqueLiteral->address) = null; (self_in_initializeUniqueLiteral->dependent) = null; ((self_in_initializeUniqueLiteral->operands))[0] = literal; ((self_in_initializeUniqueLiteral->operands))[1] = 0; ((self_in_initializeUniqueLiteral->operands))[2] = -1; return self_in_initializeUniqueLiteral; } /* CogAbstractInstruction>>#isAnInstruction: */ static sqInt NoDbgRegParms isAnInstruction(AbstractInstruction * self_in_isAnInstruction, AbstractInstruction *addressOrInstruction) { return (addressIsInInstructions(addressOrInstruction)) || (addressOrInstruction == (methodLabel())); } /* CogAbstractInstruction>>#isJump */ static sqInt NoDbgRegParms isJump(AbstractInstruction * self_in_isJump) { return ((((self_in_isJump->opcode)) >= FirstJump) && (((self_in_isJump->opcode)) <= LastJump)); } /* Answer if an address can be accessed using the offset in a MoveMw:r:R: or similar instruction. We assume this is true for 32-bit processors and expect 64-bit processors to answer false for values in the interpreter or the object memory. */ /* CogAbstractInstruction>>#isWithinMwOffsetRange: */ static sqInt NoDbgRegParms isWithinMwOffsetRange(AbstractInstruction * self_in_isWithinMwOffsetRange, sqInt anAddress) { return 1; } /* Set the target of a jump instruction. These all have the target in the first operand. */ /* CogAbstractInstruction>>#jmpTarget: */ static AbstractInstruction * NoDbgRegParms jmpTarget(AbstractInstruction * self_in_jmpTarget, AbstractInstruction *anAbstractInstruction) { ((self_in_jmpTarget->operands))[0] = (((usqInt)anAbstractInstruction)); return anAbstractInstruction; } /* Answer the constant loaded by the instruction sequence just before this address: */ /* CogAbstractInstruction>>#literal32BeforeFollowingAddress: */ static sqInt NoDbgRegParms literal32BeforeFollowingAddress(AbstractInstruction * self_in_literal32BeforeFollowingAddress, sqInt followingAddress) { return literalBeforeFollowingAddress(self_in_literal32BeforeFollowingAddress, followingAddress); } /* We assume here that calls and jumps look the same as regards their displacement. This works on at least x86, ARM and x86_64. Processors on which that isn't the case can override as necessary. */ /* CogAbstractInstruction>>#relocateJumpLongBeforeFollowingAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateJumpLongBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongBeforeFollowingAddressby, sqInt pc, sqInt delta) { relocateCallBeforeReturnPCby(self_in_relocateJumpLongBeforeFollowingAddressby, pc, delta); return self_in_relocateJumpLongBeforeFollowingAddressby; } /* Relocate a long conditional jump before pc. Default to relocating a non-conditional jump. Processors that have different formats for conditional and unconditional jumps override. */ /* CogAbstractInstruction>>#relocateJumpLongConditionalBeforeFollowingAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateJumpLongConditionalBeforeFollowingAddressby(AbstractInstruction * self_in_relocateJumpLongConditionalBeforeFollowingAddressby, sqInt pc, sqInt delta) { relocateJumpLongBeforeFollowingAddressby(self_in_relocateJumpLongConditionalBeforeFollowingAddressby, pc, delta); return self_in_relocateJumpLongConditionalBeforeFollowingAddressby; } /* CogAbstractInstruction>>#resolveJumpTarget */ static AbstractInstruction * NoDbgRegParms resolveJumpTarget(AbstractInstruction * self_in_resolveJumpTarget) { BytecodeFixup *fixup; assert(isJump(self_in_resolveJumpTarget)); fixup = ((BytecodeFixup *) (((self_in_resolveJumpTarget->operands))[0])); if (addressIsInFixups(fixup)) { assert(addressIsInInstructions((fixup->targetInstruction))); jmpTarget(self_in_resolveJumpTarget, (fixup->targetInstruction)); } return self_in_resolveJumpTarget; } /* Rewrite a conditional jump long to jump to target. This version defaults to using rewriteJumpLongAt:, which works for many ISAs. Subclasses override if necessary. */ /* CogAbstractInstruction>>#rewriteConditionalJumpLongAt:target: */ static sqInt NoDbgRegParms rewriteConditionalJumpLongAttarget(AbstractInstruction * self_in_rewriteConditionalJumpLongAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteJumpLongAttarget(self_in_rewriteConditionalJumpLongAttarget, callSiteReturnAddress, callTargetAddress); } /* CogAbstractInstruction>>#unalignedLongAt: */ static sqInt NoDbgRegParms unalignedLongAt(AbstractInstruction * self_in_unalignedLongAt, sqInt byteAddress) { return error("subclassResponsibility"); } /* CogAbstractInstruction>>#unalignedLongAt:put: */ static sqInt NoDbgRegParms unalignedLongAtput(AbstractInstruction * self_in_unalignedLongAtput, sqInt byteAddress, sqInt aWord) { return error("subclassResponsibility"); } /* A hack hook to allow ARM to override the simulated address for the short-cut trampolines, and to allow x64 to address CStackPointer and CFramePointer relative to VarBaseReg. */ /* CogAbstractInstruction>>#wantsNearAddressFor: */ static sqInt NoDbgRegParms wantsNearAddressFor(AbstractInstruction * self_in_wantsNearAddressFor, sqInt anObject) { return 0; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc ADDS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-23 */ /* CogARMCompiler>>#adds:rn:imm:ror: */ static sqInt NoDbgRegParms addsrnimmror(AbstractInstruction * self_in_addsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. ADD destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-23 */ /* CogARMCompiler>>#add:rn:imm:ror: */ static sqInt NoDbgRegParms addrnimmror(AbstractInstruction * self_in_addrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* return an ADD destReg, srcReg, addReg instruction ADD destReg, srcReg, addReg - ARM_ARM v7 DDI10406 p. A8-24 */ /* CogARMCompiler>>#add:rn:rm: */ static sqInt NoDbgRegParms addrnrm(AbstractInstruction * self_in_addrnrm, sqInt destReg, sqInt srcReg, sqInt addReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (addReg & 0xFFF); } /* Answer the address of the __aeabi_idivmod() call provided by the ARM low level libs to do an integer divide that returns the quo in R0 and rem in R1. A word on the somewhat strange usage of idivmod herein; we need a declaration for the _aeabi_idivmod helper function, despite the fact that in a simple C program test, you don't. To get that declaration we need a variable to hang it off; thus the non-existent var idivmod, and in simulation we need to simulate it, which is what aeabiDiv:Mod: does. */ /* CogARMCompiler>>#aeabiDivModFunctionAddr */ static usqInt NoDbgRegParms aeabiDivModFunctionAddr(AbstractInstruction * self_in_aeabiDivModFunctionAddr) { extern void __aeabi_idivmod(int dividend, int divisor); return (usqInt)__aeabi_idivmod; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc ANDS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-34 */ /* CogARMCompiler>>#ands:rn:imm:ror: */ static sqInt NoDbgRegParms andsrnimmror(AbstractInstruction * self_in_andsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc AND destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 p. A8-34 */ /* CogARMCompiler>>#and:rn:imm:ror: */ static sqInt NoDbgRegParms andrnimmror(AbstractInstruction * self_in_andrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. N.B. Do /not/ allocate TempReg. */ /* Answer an unused abstract register in the liveRegMask. Subclasses with more registers can override to answer them. N.B. Do /not/ allocate TempReg. */ /* CogARMCompiler>>#availableRegisterOrNoneFor: */ static sqInt NoDbgRegParms availableRegisterOrNoneFor(AbstractInstruction * self_in_availableRegisterOrNoneFor, sqInt liveRegsMask) { if (!(liveRegsMask & (1U << Extra0Reg))) { return Extra0Reg; } if (!(liveRegsMask & (1U << Extra1Reg))) { return Extra1Reg; } if (!(liveRegsMask & (1U << Extra2Reg))) { return Extra2Reg; } if (!(liveRegsMask & (1U << Arg1Reg))) { return Arg1Reg; } if (!(liveRegsMask & (1U << Arg0Reg))) { return Arg0Reg; } if (!(liveRegsMask & (1U << SendNumArgsReg))) { return SendNumArgsReg; } if (!(liveRegsMask & (1U << ClassReg))) { return ClassReg; } if (!(liveRegsMask & (1U << ReceiverResultReg))) { return ReceiverResultReg; } return NoReg; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc BICS destReg, srcReg, #immediate ROR #rot - ARM_ARM v7 DDI10406 pp. A8-50-1 */ /* CogARMCompiler>>#bics:rn:imm:ror: */ static sqInt NoDbgRegParms bicsrnimmror(AbstractInstruction * self_in_bicsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(BicOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* return a BL offset instruction; offset is signed 24bits of WORD offset, so +_32Mbyte range. Return address is in LR BL offset - ARM_ARM v7 DDI10406 pp. A8-58-9 */ /* CogARMCompiler>>#bl: */ static sqInt NoDbgRegParms bl(AbstractInstruction * self_in_bl, sqInt offset) { return (((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (1 & 1))) << 24))) | ((((usqInt) offset) >> 2) & 0xFFFFFF)); } /* return a B offset instruction; offset is signed 24bits of WORD offset, so +_32Mbyte range B offset - ARM_ARM v7 DDI10406 pp. A8-44-5 */ /* CogARMCompiler>>#b: */ static sqInt NoDbgRegParms b(AbstractInstruction * self_in_b, sqInt offset) { return (((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset) >> 2) & 0xFFFFFF)); } /* Answer the address that the call immediately preceding callSiteReturnAddress will jump to. */ /* this is also used by #jumpLongTargetBeforeFollowingAddress: and so we check for both call and jump related instructions; later on we can use simpler tests once it feels safe to assume we get here always with a call/jump in the proper place */ /* CogARMCompiler>>#callFullTargetFromReturnAddress: */ static sqInt NoDbgRegParms callFullTargetFromReturnAddress(AbstractInstruction * self_in_callFullTargetFromReturnAddress, sqInt callSiteReturnAddress) { return error("subclassResponsibility"); } /* ARM calls and jumps span +/- 32 mb, more than enough for intra-zone calls and jumps. */ /* CogARMCompiler>>#callInstructionByteSize */ static sqInt NoDbgRegParms callInstructionByteSize(AbstractInstruction * self_in_callInstructionByteSize) { return 4; } /* Answer the address that the call immediately preceding callSiteReturnAddress will jump to. */ /* this is also used by #jumpLongTargetBeforeFollowingAddress:. */ /* CogARMCompiler>>#callTargetFromReturnAddress: */ static sqInt NoDbgRegParms callTargetFromReturnAddress(AbstractInstruction * self_in_callTargetFromReturnAddress, sqInt callSiteReturnAddress) { sqInt call; sqInt callDistance; sqInt relativeJump; call = longAt(callSiteReturnAddress - 4); assert((instructionIsB(self_in_callTargetFromReturnAddress, call)) || (instructionIsBL(self_in_callTargetFromReturnAddress, call))); /* begin extractOffsetFromBL: */ relativeJump = call & 0xFFFFFF; relativeJump = (relativeJump & (1U << 23) ? ((int) (((sqInt)((usqInt)((relativeJump | 0x3F000000)) << 2)))) : ((sqInt)((usqInt)(relativeJump) << 2))); callDistance = relativeJump; return (callSiteReturnAddress + 4) + (((int) callDistance)); } /* Because we don't use Thumb, each ARM instruction has 4 bytes. Many abstract opcodes need more than one instruction. Instructions that refer to constants and/or literals depend on literals being stored in-line or out-of-line. N.B. The ^N forms are to get around the bytecode compiler's long branch limits which are exceeded when each case jumps around the otherwise. */ /* CogARMCompiler>>#computeMaximumSize */ static sqInt NoDbgRegParms computeMaximumSize(AbstractInstruction * self_in_computeMaximumSize) { sqInt constant; sqInt constant1; sqInt constant2; sqInt constant4; sqInt constant5; sqInt i1; sqInt i2; sqInt i3; sqInt value; unsigned int value1; switch ((self_in_computeMaximumSize->opcode)) { case Label: return 0; case Literal: case Fill32: case Nop: case Call: case JumpR: case Jump: case JumpLong: case JumpZero: case JumpNonZero: case JumpNegative: case JumpNonNegative: case JumpOverflow: case JumpNoOverflow: case JumpCarry: case JumpNoCarry: case JumpLess: case JumpGreaterOrEqual: case JumpGreater: case JumpLessOrEqual: case JumpBelow: case JumpAboveOrEqual: case JumpAbove: case JumpBelowOrEqual: case JumpLongZero: case JumpLongNonZero: case Stop: case AddRR: case AndRR: case CmpRR: case OrRR: case XorRR: case SubRR: case NegateR: case LogicalShiftLeftCqR: case LogicalShiftRightCqR: case ArithmeticShiftRightCqR: case LogicalShiftLeftRR: case LogicalShiftRightRR: case ArithmeticShiftRightRR: case AddRdRd: case CmpRdRd: case SubRdRd: case MulRdRd: case DivRdRd: case SqrtRd: case SMULL: case MSR: case CMPSMULL: case PopLDM: case PushSTM: case MoveRR: case MoveRdRd: case MoveXbrRR: case MoveRXbrR: case MoveXwrRR: case MoveRXwrR: case PopR: case PushR: return 4; case AlignmentNops: return (((self_in_computeMaximumSize->operands))[0]) - 4; case CallFull: case JumpFull: case AddCwR: case AndCwR: case CmpCwR: case OrCwR: case SubCwR: case XorCwR: case MoveRdM64r: case MoveM64rRd: return 4 /* literalLoadInstructionBytes */ + 4; case JumpFPEqual: case JumpFPNotEqual: case JumpFPLess: case JumpFPGreaterOrEqual: case JumpFPGreater: case JumpFPLessOrEqual: case JumpFPOrdered: case JumpFPUnordered: case ConvertRRd: return 8; case RetN: return ((((self_in_computeMaximumSize->operands))[0]) == 0 ? 4 : 8); case AddCqR: case CmpCqR: case SubCqR: /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ constant = ((self_in_computeMaximumSize->operands))[0]; value = constant; while (1) { if ((value & 0xFF) == value) { return 4; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value) { return 4; } } if (!((value == constant) && (constant != 0))) break; value = -constant; } return 4 /* literalLoadInstructionBytes */ + 4; case AndCqR: case AndCqRR: case XorCqR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant1 = ((self_in_computeMaximumSize->operands))[0]; value1 = constant1; while (1) { if ((value1 & 0xFF) == value1) { return 4; } for (i2 = 2; i2 <= 30; i2 += 2) { if ((value1 & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == value1) { return 4; } } if (!(value1 == constant1)) break; value1 = (constant1 < 0 ? -1 - constant1 : (unsigned int)~constant1); } return 8; case OrCqR: case TstCqR: case LoadEffectiveAddressMwrR: case MoveM16rR: /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ constant2 = ((self_in_computeMaximumSize->operands))[0]; if ((constant2 & 0xFF) == constant2) { return 4; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant2 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant2) { return 4; } } return 4 /* literalLoadInstructionBytes */ + 4; case MoveCqR: return 4 /* literalLoadInstructionBytes */; case MoveCwR: return 4 /* literalLoadInstructionBytes */; case MoveAwR: case MoveAbR: case PrefetchAw: return (((((self_in_computeMaximumSize->operands))[0]) != null) && (((((self_in_computeMaximumSize->operands))[0]) >= (varBaseAddress())) && (((((self_in_computeMaximumSize->operands))[0]) - (varBaseAddress())) < (1U << 12))) ? 4 : 4 /* literalLoadInstructionBytes */ + 4); case MoveRAw: case MoveRAb: return (((((self_in_computeMaximumSize->operands))[1]) != null) && (((((self_in_computeMaximumSize->operands))[1]) >= (varBaseAddress())) && (((((self_in_computeMaximumSize->operands))[1]) - (varBaseAddress())) < (1U << 12))) ? 4 : 4 /* literalLoadInstructionBytes */ + 4); case MoveRMwr: case MoveRMbr: case MoveRM16r: /* begin is12BitValue:ifTrue:ifFalse: */ constant4 = ((self_in_computeMaximumSize->operands))[1]; if ((SQABS(constant4)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant4 >= 0) { return 4; } else { return 4; } } else { return 4 /* literalLoadInstructionBytes */ + 4; } case MoveMbrR: case MoveMwrR: /* begin is12BitValue:ifTrue:ifFalse: */ constant5 = ((self_in_computeMaximumSize->operands))[0]; if ((SQABS(constant5)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant5 >= 0) { return 4; } else { return 4; } } else { return 4 /* literalLoadInstructionBytes */ + 4; } case PushCw: return 4 /* literalLoadInstructionBytes */ + 4; case PushCq: return 4 /* literalLoadInstructionBytes */ + 4; default: error("Case not found and no otherwise clause"); } return 0; } /* According to IHI0042E ARM Architecture Procedure Calling Standard, in section 5.1.1: A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate r9 as v6). SP = r13, so... */ /* CogARMCompiler>>#concreteCalleeSavedRegisterMask */ static sqInt NoDbgRegParms concreteCalleeSavedRegisterMask(AbstractInstruction * self_in_concreteCalleeSavedRegisterMask) { return 3568; } /* According to IHI0042E ARM Architecture Procedure Calling Standard, in section 5.1.1: A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate r9 as v6). SP = r13, so the callee-saved regs are r4-r8 & r10-r12. The caller-saved registers are those that are not callee-saved and not reserved for hardware/abi uses, i..e r0-r3, r9 & r12. */ /* CogARMCompiler>>#concreteCallerSavedRegisterMask */ static sqInt NoDbgRegParms concreteCallerSavedRegisterMask(AbstractInstruction * self_in_concreteCallerSavedRegisterMask) { return 4623; } /* Generate concrete machine code for the instruction at actualAddress, setting machineCodeSize, and answer the following address. */ /* Generate concrete machine code for the instruction at actualAddress, setting machineCodeSize, and answer the following address. */ /* CogARMCompiler>>#concretizeAt: */ static sqInt NoDbgRegParms concretizeAt(AbstractInstruction * self_in_concretizeAt, sqInt actualAddress) { assert((actualAddress % 4) == 0); (self_in_concretizeAt->address) = actualAddress; dispatchConcretize(self_in_concretizeAt); assert((((self_in_concretizeAt->maxSize)) == null) || (((self_in_concretizeAt->maxSize)) >= ((self_in_concretizeAt->machineCodeSize)))); return actualAddress + ((self_in_concretizeAt->machineCodeSize)); } /* Generate a CMP a, b, ASR #31 instruction, specifically for comparing the resutls of SMULLs in genMulR:R: */ /* CogARMCompiler>>#concretizeCMPSMULL */ static usqInt NoDbgRegParms concretizeCMPSMULL(AbstractInstruction * self_in_concretizeCMPSMULL) { sqInt aWord; usqInt hiReg; usqInt loReg; hiReg = ((self_in_concretizeCMPSMULL->operands))[0]; loReg = ((self_in_concretizeCMPSMULL->operands))[1]; /* begin machineCodeAt:put: */ aWord = (((((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((hiReg << 16) | (0U << 12))) + (0x1FU << 7)) + (2U << 5)) + loReg; ((self_in_concretizeCMPSMULL->machineCode))[0 / 4] = aWord; return ((self_in_concretizeCMPSMULL->machineCodeSize) = 4); } /* Concretize the current instruction, but with a condition. */ /* CogARMCompiler>>#concretizeConditionalInstruction */ static void NoDbgRegParms concretizeConditionalInstruction(AbstractInstruction * self_in_concretizeConditionalInstruction) { sqInt aWord; sqInt i; usqInt instr; unsigned char savedCond; assert(((self_in_concretizeConditionalInstruction->conditionOrNil)) != null); savedCond = (self_in_concretizeConditionalInstruction->conditionOrNil); (self_in_concretizeConditionalInstruction->conditionOrNil) = null; dispatchConcretize(self_in_concretizeConditionalInstruction); (self_in_concretizeConditionalInstruction->conditionOrNil) = savedCond; for (i = 0; i < ((self_in_concretizeConditionalInstruction->machineCodeSize)); i += 4) { instr = (((((self_in_concretizeConditionalInstruction->machineCode))[i / 4]) | (15U << 28)) - (15U << 28)); /* begin machineCodeAt:put: */ aWord = instr | (((int)((usqInt)((((self_in_concretizeConditionalInstruction->conditionOrNil)) & 15)) << 28))); ((self_in_concretizeConditionalInstruction->machineCode))[i / 4] = aWord; } return; } /* fill with operand 0 according to the processor's endianness */ /* CogARMCompiler>>#concretizeFill32 */ static usqInt NoDbgRegParms concretizeFill32(AbstractInstruction * self_in_concretizeFill32) { sqInt aWord; /* begin machineCodeAt:put: */ aWord = ((self_in_concretizeFill32->operands))[0]; ((self_in_concretizeFill32->machineCode))[0 / 4] = aWord; return ((self_in_concretizeFill32->machineCodeSize) = 4); } /* Generate an MSR CPSR_f, #flags instruction. Note that we only have business with the NZCV flags so we use N -> 8 Z -> 4 C -> 2 V -> 1. You don't want to mess with this too much. */ /* CogARMCompiler>>#concretizeMSR */ static usqInt NoDbgRegParms concretizeMSR(AbstractInstruction * self_in_concretizeMSR) { sqInt aWord; usqInt flags; flags = ((self_in_concretizeMSR->operands))[0]; /* begin machineCodeAt:put: */ aWord = msr(self_in_concretizeMSR, flags); ((self_in_concretizeMSR->machineCode))[0 / 4] = aWord; return ((self_in_concretizeMSR->machineCodeSize) = 4); } /* CogARMCompiler>>#concretizePushOrPopMultipleRegisters: */ static usqInt NoDbgRegParms concretizePushOrPopMultipleRegisters(AbstractInstruction * self_in_concretizePushOrPopMultipleRegisters, sqInt doPush) { assert((((self_in_concretizePushOrPopMultipleRegisters->operands))[0]) != 0); ((self_in_concretizePushOrPopMultipleRegisters->machineCode))[0] = ((((((int)((usqInt)(AL) << 28))) + ((doPush ? 146U << 20 : 139U << 20))) + (((int)((usqInt)(SP) << 16)))) + (((self_in_concretizePushOrPopMultipleRegisters->operands))[0])); return ((self_in_concretizePushOrPopMultipleRegisters->machineCodeSize) = 4); } /* Generate an SMULL loResultReg, hiResultReg, srcA, srcB instruction */ /* CogARMCompiler>>#concretizeSMULL */ static usqInt NoDbgRegParms concretizeSMULL(AbstractInstruction * self_in_concretizeSMULL) { sqInt aWord; sqInt hiResultReg; usqInt loResultReg; usqInt srcA; usqInt srcB; /* NOTE: srcB contains the other mutiplicand at this point. It is OK to use it as the destination for the low part of the result and in fact this saves us moving it later */ srcA = ((self_in_concretizeSMULL->operands))[0]; loResultReg = (srcB = ((self_in_concretizeSMULL->operands))[1]); hiResultReg = RISCTempReg; /* begin machineCodeAt:put: */ aWord = (((((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((6U << 21) | (0U << 20)))) | ((((sqInt)((usqInt)(hiResultReg) << 16))) | (loResultReg << 12))) + (srcA << 8)) + (9U << 4)) + srcB; ((self_in_concretizeSMULL->machineCode))[0 / 4] = aWord; return ((self_in_concretizeSMULL->machineCodeSize) = 4); } /* test for the NV condition code; this isn't allowed as an actual condition and is used to encdoe many of the newer instructions */ /* CogARMCompiler>>#conditionIsNotNever: */ static sqInt NoDbgRegParms conditionIsNotNever(AbstractInstruction * self_in_conditionIsNotNever, sqInt instr) { return (((usqInt) instr) >> 28) < 15; } /* return an {opcode} destReg, srcReg, addReg lsl #shft */ /* important detail - a 0 shft requires setting the shift-type code to 0 to avoid potential instruction confusion */ /* CogARMCompiler>>#dataOpType:rd:rn:rm:lsr: */ static sqInt NoDbgRegParms dataOpTyperdrnrmlsr(AbstractInstruction * self_in_dataOpTyperdrnrmlsr, sqInt armOpcode, sqInt destReg, sqInt srcReg, sqInt addReg, sqInt shft) { if (shft == 0) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(armOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (addReg & 0xFFF); } else { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(armOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | ((((((sqInt)((usqInt)(shft) << 7))) | 32) | addReg) & 0xFFF); } } /* Attempt to generate concrete machine code for the instruction at address. This is the inner dispatch of concretizeAt: actualAddress which exists only to get around the branch size limits in the SqueakV3 (blue book derived) bytecode set. */ /* CogARMCompiler>>#dispatchConcretize */ static void NoDbgRegParms dispatchConcretize(AbstractInstruction * self_in_dispatchConcretize) { usqInt addressOperand; sqInt aWord; sqInt aWord1; sqInt aWord10; sqInt aWord11; sqInt aWord110; sqInt aWord111; sqInt aWord1110; sqInt aWord1111; sqInt aWord1112; sqInt aWord1113; sqInt aWord112; sqInt aWord113; sqInt aWord114; sqInt aWord115; sqInt aWord116; sqInt aWord117; sqInt aWord118; sqInt aWord119; sqInt aWord12; sqInt aWord120; sqInt aWord121; sqInt aWord1210; sqInt aWord1211; sqInt aWord122; sqInt aWord123; sqInt aWord124; sqInt aWord125; sqInt aWord126; sqInt aWord127; sqInt aWord128; sqInt aWord129; sqInt aWord13; sqInt aWord130; sqInt aWord131; sqInt aWord132; sqInt aWord133; sqInt aWord134; sqInt aWord14; sqInt aWord15; sqInt aWord16; sqInt aWord17; sqInt aWord18; sqInt aWord19; sqInt aWord2; sqInt aWord20; sqInt aWord21; sqInt aWord210; sqInt aWord211; sqInt aWord2110; sqInt aWord2111; sqInt aWord212; sqInt aWord213; sqInt aWord214; sqInt aWord215; sqInt aWord216; sqInt aWord217; sqInt aWord218; sqInt aWord219; sqInt aWord22; sqInt aWord220; sqInt aWord221; sqInt aWord222; sqInt aWord223; sqInt aWord224; sqInt aWord225; sqInt aWord226; sqInt aWord23; sqInt aWord24; sqInt aWord25; sqInt aWord26; sqInt aWord27; sqInt aWord28; sqInt aWord29; sqInt aWord3; sqInt aWord30; sqInt aWord31; sqInt aWord310; sqInt aWord311; sqInt aWord312; sqInt aWord313; sqInt aWord314; sqInt aWord315; sqInt aWord316; sqInt aWord32; sqInt aWord33; sqInt aWord34; sqInt aWord35; sqInt aWord36; sqInt aWord37; sqInt aWord38; sqInt aWord39; sqInt aWord4; sqInt aWord40; sqInt aWord41; sqInt aWord410; sqInt aWord411; sqInt aWord42; sqInt aWord43; sqInt aWord44; sqInt aWord45; sqInt aWord46; sqInt aWord47; sqInt aWord48; sqInt aWord49; sqInt aWord5; sqInt aWord50; sqInt aWord51; sqInt aWord52; sqInt aWord53; sqInt aWord54; sqInt aWord55; sqInt aWord56; sqInt aWord57; sqInt aWord58; sqInt aWord59; sqInt aWord6; sqInt aWord60; sqInt aWord61; sqInt aWord62; sqInt aWord63; sqInt aWord64; sqInt aWord65; sqInt aWord66; sqInt aWord67; sqInt aWord68; sqInt aWord7; sqInt aWord8; sqInt aWord9; usqInt base; usqInt base1; usqInt base2; usqInt base3; usqInt baseReg; usqInt baseReg1; usqInt baseReg2; usqInt constant; usqInt constant1; usqInt constant10; sqInt constant11; usqInt constant12; usqInt constant13; usqInt constant14; usqInt constant2; usqInt constant3; usqInt constant4; usqInt constant5; usqInt constant6; usqInt constant7; usqInt constant8; usqInt constant9; AbstractInstruction *dependentChain; usqInt dest; usqInt dest1; usqInt destAddr; usqInt destAddr1; usqInt destReg; usqInt destReg1; usqInt destReg10; usqInt destReg11; usqInt destReg12; usqInt destReg2; usqInt destReg3; usqInt destReg4; usqInt destReg5; usqInt destReg6; usqInt destReg7; usqInt destReg8; usqInt destReg9; sqInt distance; sqInt distance1; sqInt distance2; usqInt distReg; usqInt distReg1; usqInt distReg2; usqInt dstReg; usqInt dstReg1; sqInt flagsOrOpcode; sqInt flagsOrOpcode1; sqInt flagsOrOpcode11; sqInt flagsOrOpcode12; sqInt flagsOrOpcode2; sqInt flagsOrOpcode3; sqInt flagsOrOpcode4; sqInt flagsOrOpcode5; usqInt fpReg; sqInt hb; sqInt hb1; sqInt hb11; sqInt hb12; sqInt hb2; sqInt hb3; sqInt hb4; sqInt hb5; sqInt i; sqInt i1; sqInt i10; sqInt i11; sqInt i12; sqInt i13; sqInt i14; sqInt i15; sqInt i2; sqInt i3; sqInt i4; sqInt i5; sqInt i6; sqInt i7; sqInt i8; sqInt i9; sqInt immediate; sqInt immediate1; sqInt immediate10; sqInt immediate11; sqInt immediate12; sqInt immediate13; sqInt immediate14; sqInt immediate15; sqInt immediate16; sqInt immediate17; sqInt immediate18; sqInt immediate19; sqInt immediate2; sqInt immediate20; sqInt immediate3; sqInt immediate4; sqInt immediate5; sqInt immediate6; sqInt immediate7; sqInt immediate8; sqInt immediate9; usqInt index; usqInt index1; usqInt index2; usqInt index3; usqInt instrOffset; usqInt instrOffset1; usqInt instrOffset10; usqInt instrOffset11; usqInt instrOffset12; usqInt instrOffset13; usqInt instrOffset14; usqInt instrOffset15; usqInt instrOffset16; sqInt instrOffset17; sqInt instrOffset18; sqInt instrOffset19; usqInt instrOffset2; usqInt instrOffset20; usqInt instrOffset21; usqInt instrOffset22; sqInt instrOffset23; usqInt instrOffset24; usqInt instrOffset25; usqInt instrOffset26; usqInt instrOffset27; usqInt instrOffset28; usqInt instrOffset29; usqInt instrOffset3; usqInt instrOffset4; usqInt instrOffset5; usqInt instrOffset6; usqInt instrOffset7; usqInt instrOffset8; usqInt instrOffset9; sqInt invert; sqInt invert1; sqInt invert2; sqInt invert3; sqInt invert4; unsigned int invVal; AbstractInstruction *jumpTarget; AbstractInstruction *jumpTarget1; AbstractInstruction *jumpTarget10; AbstractInstruction *jumpTarget11; AbstractInstruction *jumpTarget110; AbstractInstruction *jumpTarget111; AbstractInstruction *jumpTarget112; AbstractInstruction *jumpTarget113; AbstractInstruction *jumpTarget114; AbstractInstruction *jumpTarget115; AbstractInstruction *jumpTarget116; AbstractInstruction *jumpTarget117; AbstractInstruction *jumpTarget118; AbstractInstruction *jumpTarget119; AbstractInstruction *jumpTarget12; AbstractInstruction *jumpTarget120; AbstractInstruction *jumpTarget121; AbstractInstruction *jumpTarget122; AbstractInstruction *jumpTarget123; AbstractInstruction *jumpTarget124; AbstractInstruction *jumpTarget13; AbstractInstruction *jumpTarget14; AbstractInstruction *jumpTarget15; AbstractInstruction *jumpTarget16; AbstractInstruction *jumpTarget17; AbstractInstruction *jumpTarget18; AbstractInstruction *jumpTarget19; AbstractInstruction *jumpTarget2; AbstractInstruction *jumpTarget20; AbstractInstruction *jumpTarget21; AbstractInstruction *jumpTarget22; AbstractInstruction *jumpTarget23; AbstractInstruction *jumpTarget24; AbstractInstruction *jumpTarget25; AbstractInstruction *jumpTarget26; AbstractInstruction *jumpTarget27; AbstractInstruction *jumpTarget28; AbstractInstruction *jumpTarget29; AbstractInstruction *jumpTarget3; AbstractInstruction *jumpTarget30; AbstractInstruction *jumpTarget31; AbstractInstruction *jumpTarget32; AbstractInstruction *jumpTarget33; AbstractInstruction *jumpTarget34; AbstractInstruction *jumpTarget4; AbstractInstruction *jumpTarget5; AbstractInstruction *jumpTarget6; AbstractInstruction *jumpTarget7; AbstractInstruction *jumpTarget8; AbstractInstruction *jumpTarget9; sqInt negate; sqInt negate1; sqInt offset; sqInt offset1; sqInt offset10; sqInt offset11; sqInt offset12; sqInt offset13; sqInt offset14; sqInt offset15; sqInt offset16; sqInt offset17; sqInt offset18; sqInt offset19; sqInt offset2; sqInt offset20; sqInt offset21; sqInt offset22; sqInt offset23; sqInt offset24; sqInt offset25; sqInt offset26; usqInt offset27; sqInt offset28; sqInt offset29; sqInt offset3; sqInt offset30; sqInt offset31; sqInt offset32; sqInt offset33; sqInt offset4; sqInt offset5; sqInt offset6; sqInt offset7; sqInt offset8; sqInt offset9; sqInt p; int rd; int rd1; int rd10; int rd11; int rd110; int rd111; int rd12; int rd13; int rd14; int rd15; int rd16; int rd17; int rd18; int rd19; int rd2; int rd20; int rd21; int rd22; int rd3; int rd4; int rd5; int rd6; int rd7; int rd8; int rd9; usqInt reg; usqInt reg1; usqInt reg2; usqInt reg3; usqInt reg4; usqInt reg5; usqInt reg6; usqInt reg7; usqInt regA; usqInt regB; usqInt regLHS; usqInt regLHS1; usqInt regLHS2; usqInt regLHS3; usqInt regLHS4; usqInt regRHS; usqInt regRHS1; usqInt regRHS2; usqInt regRHS3; usqInt rn; usqInt rn1; usqInt rn10; usqInt rn11; usqInt rn110; usqInt rn111; usqInt rn12; usqInt rn13; usqInt rn14; usqInt rn15; usqInt rn16; usqInt rn17; usqInt rn18; usqInt rn19; usqInt rn2; usqInt rn20; usqInt rn21; usqInt rn22; usqInt rn23; usqInt rn24; usqInt rn3; usqInt rn4; usqInt rn5; usqInt rn6; usqInt rn7; usqInt rn8; usqInt rn9; sqInt rot; sqInt rot1; sqInt rot10; sqInt rot11; sqInt rot12; sqInt rot13; sqInt rot2; sqInt rot3; sqInt rot4; sqInt rot5; sqInt rot6; sqInt rot7; sqInt rot8; sqInt rot9; usqInt src; usqInt src1; usqInt srcAddr; usqInt srcAddr1; usqInt srcReg; usqInt srcReg1; usqInt srcReg10; usqInt srcReg11; usqInt srcReg12; usqInt srcReg13; usqInt srcReg14; usqInt srcReg15; usqInt srcReg16; usqInt srcReg17; usqInt srcReg18; usqInt srcReg19; usqInt srcReg2; usqInt srcReg3; usqInt srcReg4; usqInt srcReg5; usqInt srcReg6; usqInt srcReg7; usqInt srcReg8; usqInt srcReg9; int u; int u1; sqInt val; sqInt val1; sqInt val11; sqInt val12; sqInt val2; usqInt val3; sqInt val4; sqInt val5; sqInt value; sqInt value1; unsigned int value2; unsigned int value3; unsigned int value4; unsigned int value5; unsigned int value6; sqInt word; sqInt word1; usqInt word2; usqInt word3; if (!(((self_in_dispatchConcretize->conditionOrNil)) == null)) { concretizeConditionalInstruction(self_in_dispatchConcretize); return; } switch ((self_in_dispatchConcretize->opcode)) { case Label: /* begin concretizeLabel */ dependentChain = (self_in_dispatchConcretize->dependent); while (!(dependentChain == null)) { /* begin updateLabel: */ if (((dependentChain->opcode)) != Literal) { assert((((dependentChain->opcode)) == MoveCwR) || (((dependentChain->opcode)) == PushCw)); ((dependentChain->operands))[0] = (((self_in_dispatchConcretize->address)) + (((self_in_dispatchConcretize->operands))[1])); } dependentChain = (dependentChain->dependent); } (self_in_dispatchConcretize->machineCodeSize) = 0; return; case Literal: concretizeLiteral(self_in_dispatchConcretize); return; case AlignmentNops: /* begin concretizeAlignmentNops */ assert((((self_in_dispatchConcretize->machineCodeSize)) % 4) == 0); for (p = 0; p < ((self_in_dispatchConcretize->machineCodeSize)); p += 4) { /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[p / 4] = 3785359360U; } return; case Fill32: concretizeFill32(self_in_dispatchConcretize); return; case Nop: /* begin concretizeNop */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 3785359360U; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case Call: /* begin concretizeCall */ assert((((self_in_dispatchConcretize->operands))[0]) != 0); assert(((((self_in_dispatchConcretize->operands))[0]) % 4) == 0); /* normal pc offset */ offset2 = (((int) (((self_in_dispatchConcretize->operands))[0]))) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset2)); /* begin machineCodeAt:put: */ aWord = bl(self_in_dispatchConcretize, offset2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CallFull: /* begin concretizeCallFull */ jumpTarget1 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); if ((addressIsInInstructions(jumpTarget1)) || (jumpTarget1 == (methodLabel()))) { jumpTarget1 = ((AbstractInstruction *) ((jumpTarget1->address))); } assert(jumpTarget1 != 0); jumpTarget = jumpTarget1; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord1 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1; instrOffset = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[instrOffset / 4] = ((((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((1 & 1)) << 5)))) | ConcreteIPReg)); assert(instrOffset == (literalLoadInstructionBytes(self_in_dispatchConcretize))); (self_in_dispatchConcretize->machineCodeSize) = instrOffset + 4; return; case JumpR: /* begin concretizeJumpR */ /* bx reg */ reg = ((self_in_dispatchConcretize->operands))[0]; aWord2 = (((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((0 & 1)) << 5)))) | reg); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord2; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpFull: /* begin concretizeJumpFull */ jumpTarget11 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); if ((addressIsInInstructions(jumpTarget11)) || (jumpTarget11 == (methodLabel()))) { jumpTarget11 = ((AbstractInstruction *) ((jumpTarget11->address))); } assert(jumpTarget11 != 0); jumpTarget2 = jumpTarget11; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord3 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord3; instrOffset1 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[instrOffset1 / 4] = ((((int)((usqInt)(AL) << 28))) | ((19922704 | (((int)((usqInt)((0 & 1)) << 5)))) | ConcreteIPReg)); (self_in_dispatchConcretize->machineCodeSize) = instrOffset1 + 4; return; case JumpLong: case Jump: /* begin concretizeConditionalJump: */ jumpTarget12 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget12); if ((addressIsInInstructions(jumpTarget12)) || (jumpTarget12 == (methodLabel()))) { jumpTarget12 = ((AbstractInstruction *) ((jumpTarget12->address))); } assert(jumpTarget12 != 0); jumpTarget3 = jumpTarget12; offset3 = (((int) jumpTarget3)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset3)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(AL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset3) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLongZero: case JumpZero: /* begin concretizeConditionalJump: */ jumpTarget13 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget13); if ((addressIsInInstructions(jumpTarget13)) || (jumpTarget13 == (methodLabel()))) { jumpTarget13 = ((AbstractInstruction *) ((jumpTarget13->address))); } assert(jumpTarget13 != 0); jumpTarget4 = jumpTarget13; offset4 = (((int) jumpTarget4)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset4)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(EQ) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset4) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLongNonZero: case JumpNonZero: /* begin concretizeConditionalJump: */ jumpTarget14 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget14); if ((addressIsInInstructions(jumpTarget14)) || (jumpTarget14 == (methodLabel()))) { jumpTarget14 = ((AbstractInstruction *) ((jumpTarget14->address))); } assert(jumpTarget14 != 0); jumpTarget5 = jumpTarget14; offset5 = (((int) jumpTarget5)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset5)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(NE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset5) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNegative: /* begin concretizeConditionalJump: */ jumpTarget15 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget15); if ((addressIsInInstructions(jumpTarget15)) || (jumpTarget15 == (methodLabel()))) { jumpTarget15 = ((AbstractInstruction *) ((jumpTarget15->address))); } assert(jumpTarget15 != 0); jumpTarget6 = jumpTarget15; offset6 = (((int) jumpTarget6)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset6)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(MI) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset6) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNonNegative: /* begin concretizeConditionalJump: */ jumpTarget16 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget16); if ((addressIsInInstructions(jumpTarget16)) || (jumpTarget16 == (methodLabel()))) { jumpTarget16 = ((AbstractInstruction *) ((jumpTarget16->address))); } assert(jumpTarget16 != 0); jumpTarget7 = jumpTarget16; offset7 = (((int) jumpTarget7)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset7)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(PL) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset7) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpOverflow: /* begin concretizeConditionalJump: */ jumpTarget17 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget17); if ((addressIsInInstructions(jumpTarget17)) || (jumpTarget17 == (methodLabel()))) { jumpTarget17 = ((AbstractInstruction *) ((jumpTarget17->address))); } assert(jumpTarget17 != 0); jumpTarget8 = jumpTarget17; offset8 = (((int) jumpTarget8)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset8)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(VS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset8) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNoOverflow: /* begin concretizeConditionalJump: */ jumpTarget18 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget18); if ((addressIsInInstructions(jumpTarget18)) || (jumpTarget18 == (methodLabel()))) { jumpTarget18 = ((AbstractInstruction *) ((jumpTarget18->address))); } assert(jumpTarget18 != 0); jumpTarget9 = jumpTarget18; offset9 = (((int) jumpTarget9)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset9)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(VC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset9) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpCarry: case JumpAboveOrEqual: /* begin concretizeConditionalJump: */ jumpTarget19 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget19); if ((addressIsInInstructions(jumpTarget19)) || (jumpTarget19 == (methodLabel()))) { jumpTarget19 = ((AbstractInstruction *) ((jumpTarget19->address))); } assert(jumpTarget19 != 0); jumpTarget10 = jumpTarget19; offset10 = (((int) jumpTarget10)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset10)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(CS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset10) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpNoCarry: case JumpBelow: /* begin concretizeConditionalJump: */ jumpTarget110 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget110); if ((addressIsInInstructions(jumpTarget110)) || (jumpTarget110 == (methodLabel()))) { jumpTarget110 = ((AbstractInstruction *) ((jumpTarget110->address))); } assert(jumpTarget110 != 0); jumpTarget20 = jumpTarget110; offset11 = (((int) jumpTarget20)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset11)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(CC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset11) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLess: /* begin concretizeConditionalJump: */ jumpTarget111 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget111); if ((addressIsInInstructions(jumpTarget111)) || (jumpTarget111 == (methodLabel()))) { jumpTarget111 = ((AbstractInstruction *) ((jumpTarget111->address))); } assert(jumpTarget111 != 0); jumpTarget21 = jumpTarget111; offset12 = (((int) jumpTarget21)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset12)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset12) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpGreaterOrEqual: /* begin concretizeConditionalJump: */ jumpTarget112 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget112); if ((addressIsInInstructions(jumpTarget112)) || (jumpTarget112 == (methodLabel()))) { jumpTarget112 = ((AbstractInstruction *) ((jumpTarget112->address))); } assert(jumpTarget112 != 0); jumpTarget22 = jumpTarget112; offset13 = (((int) jumpTarget22)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset13)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(GE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset13) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpGreater: /* begin concretizeConditionalJump: */ jumpTarget113 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget113); if ((addressIsInInstructions(jumpTarget113)) || (jumpTarget113 == (methodLabel()))) { jumpTarget113 = ((AbstractInstruction *) ((jumpTarget113->address))); } assert(jumpTarget113 != 0); jumpTarget23 = jumpTarget113; offset14 = (((int) jumpTarget23)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset14)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(GT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset14) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpLessOrEqual: /* begin concretizeConditionalJump: */ jumpTarget114 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget114); if ((addressIsInInstructions(jumpTarget114)) || (jumpTarget114 == (methodLabel()))) { jumpTarget114 = ((AbstractInstruction *) ((jumpTarget114->address))); } assert(jumpTarget114 != 0); jumpTarget24 = jumpTarget114; offset15 = (((int) jumpTarget24)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset15)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset15) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpAbove: /* begin concretizeConditionalJump: */ jumpTarget115 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget115); if ((addressIsInInstructions(jumpTarget115)) || (jumpTarget115 == (methodLabel()))) { jumpTarget115 = ((AbstractInstruction *) ((jumpTarget115->address))); } assert(jumpTarget115 != 0); jumpTarget25 = jumpTarget115; offset16 = (((int) jumpTarget25)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset16)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(HI) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset16) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpBelowOrEqual: /* begin concretizeConditionalJump: */ jumpTarget116 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget116); if ((addressIsInInstructions(jumpTarget116)) || (jumpTarget116 == (methodLabel()))) { jumpTarget116 = ((AbstractInstruction *) ((jumpTarget116->address))); } assert(jumpTarget116 != 0); jumpTarget26 = jumpTarget116; offset17 = (((int) jumpTarget26)) - (((int) (((self_in_dispatchConcretize->address)) + 8))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset17)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(LS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset17) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case JumpFPEqual: /* begin concretizeFPConditionalJump: */ jumpTarget117 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget117); if ((addressIsInInstructions(jumpTarget117)) || (jumpTarget117 == (methodLabel()))) { jumpTarget117 = ((AbstractInstruction *) ((jumpTarget117->address))); } assert(jumpTarget117 != 0); jumpTarget27 = jumpTarget117; offset18 = (((int) jumpTarget27)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset18)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(EQ) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset18) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPNotEqual: /* begin concretizeFPConditionalJump: */ jumpTarget118 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget118); if ((addressIsInInstructions(jumpTarget118)) || (jumpTarget118 == (methodLabel()))) { jumpTarget118 = ((AbstractInstruction *) ((jumpTarget118->address))); } assert(jumpTarget118 != 0); jumpTarget28 = jumpTarget118; offset19 = (((int) jumpTarget28)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset19)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(NE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset19) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPLess: /* begin concretizeFPConditionalJump: */ jumpTarget119 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget119); if ((addressIsInInstructions(jumpTarget119)) || (jumpTarget119 == (methodLabel()))) { jumpTarget119 = ((AbstractInstruction *) ((jumpTarget119->address))); } assert(jumpTarget119 != 0); jumpTarget29 = jumpTarget119; offset20 = (((int) jumpTarget29)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset20)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(LT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset20) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPGreaterOrEqual: /* begin concretizeFPConditionalJump: */ jumpTarget120 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget120); if ((addressIsInInstructions(jumpTarget120)) || (jumpTarget120 == (methodLabel()))) { jumpTarget120 = ((AbstractInstruction *) ((jumpTarget120->address))); } assert(jumpTarget120 != 0); jumpTarget30 = jumpTarget120; offset21 = (((int) jumpTarget30)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset21)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(GE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset21) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPGreater: /* begin concretizeFPConditionalJump: */ jumpTarget121 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget121); if ((addressIsInInstructions(jumpTarget121)) || (jumpTarget121 == (methodLabel()))) { jumpTarget121 = ((AbstractInstruction *) ((jumpTarget121->address))); } assert(jumpTarget121 != 0); jumpTarget31 = jumpTarget121; offset22 = (((int) jumpTarget31)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset22)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(GT) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset22) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPLessOrEqual: /* begin concretizeFPConditionalJump: */ jumpTarget122 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget122); if ((addressIsInInstructions(jumpTarget122)) || (jumpTarget122 == (methodLabel()))) { jumpTarget122 = ((AbstractInstruction *) ((jumpTarget122->address))); } assert(jumpTarget122 != 0); jumpTarget32 = jumpTarget122; offset23 = (((int) jumpTarget32)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset23)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(LE) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset23) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPOrdered: /* begin concretizeFPConditionalJump: */ jumpTarget123 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget123); if ((addressIsInInstructions(jumpTarget123)) || (jumpTarget123 == (methodLabel()))) { jumpTarget123 = ((AbstractInstruction *) ((jumpTarget123->address))); } assert(jumpTarget123 != 0); jumpTarget33 = jumpTarget123; offset24 = (((int) jumpTarget33)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset24)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(VC) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset24) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case JumpFPUnordered: /* begin concretizeFPConditionalJump: */ jumpTarget124 = ((AbstractInstruction *) (((self_in_dispatchConcretize->operands))[0])); assertSaneJumpTarget(jumpTarget124); if ((addressIsInInstructions(jumpTarget124)) || (jumpTarget124 == (methodLabel()))) { jumpTarget124 = ((AbstractInstruction *) ((jumpTarget124->address))); } assert(jumpTarget124 != 0); jumpTarget34 = jumpTarget124; offset25 = (((int) jumpTarget34)) - (((int) (((self_in_dispatchConcretize->address)) + (8 + 4)))); assert(isInImmediateJumpRange(self_in_dispatchConcretize, offset25)); /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = 4008835600U /* fmstat */; /* begin machineCodeAt:put: */ ((self_in_dispatchConcretize->machineCode))[4 / 4] = ((((int)((usqInt)(VS) << 28))) | ((((int)((usqInt)((10 | (0 & 1))) << 24))) | ((((usqInt) offset25) >> 2) & 0xFFFFFF))); (self_in_dispatchConcretize->machineCodeSize) = 8; return; case RetN: /* begin concretizeRetN */ offset26 = ((self_in_dispatchConcretize->operands))[0]; if (offset26 == 0) { /* begin machineCodeAt:put: */ aWord4 = movrn(self_in_dispatchConcretize, PC, LR); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord4; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l133; } assert(offset26 < 0xFF); /* begin machineCodeAt:put: */ aWord11 = addrnimmror(self_in_dispatchConcretize, SP, SP, offset26, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord11; /* begin machineCodeAt:put: */ aWord21 = movrn(self_in_dispatchConcretize, PC, LR); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord21; (self_in_dispatchConcretize->machineCodeSize) = 8; l133: /* end concretizeRetN */; return; case Stop: /* begin concretizeStop */ ((self_in_dispatchConcretize->machineCode))[0 / 4] = ((((int)((usqInt)(AL) << 28))) | ((66U << 20) | (7U << 4))); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AddCqR: /* begin concretizeNegateableDataOperationCqR: */ val = ((self_in_dispatchConcretize->operands))[0]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen. */ rn = ((self_in_dispatchConcretize->operands))[1]; rd = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value = val; while (1) { if ((value & 0xFF) == value) { negate = val != value; /* begin machineCodeAt:put: */ flagsOrOpcode = (negate ? inverseOpcodeFor(self_in_dispatchConcretize, AddOpcode) : AddOpcode); aWord5 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode) << 21))) | (1U << 20)))) | ((rn << 16) | (((int)((usqInt)(rd) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord5; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l143; goto l136; } for (i = 2; i <= 30; i += 2) { if ((value & (((0xFFU << i) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i)))) == value) { rot = 32 - i; immediate = (((usqInt) value) >> i) | ((((sqInt)((usqInt)(value) << (32 - i)))) & 0xFFFFFFFFU); negate = val != value; /* begin machineCodeAt:put: */ flagsOrOpcode1 = (negate ? inverseOpcodeFor(self_in_dispatchConcretize, AddOpcode) : AddOpcode); aWord5 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode1) << 21))) | (1U << 20)))) | ((rn << 16) | (((int)((usqInt)(rd) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord5; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l143; goto l136; } } if (!((value == val) && (val != 0))) break; value = -val; } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val > 0) { hb = highBit(val); if ((1U << hb) == (val + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord12 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord12; /* begin machineCodeAt:put: */ aWord22 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AddOpcode, rd, rn, ConcreteIPReg, 32 - hb); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord22; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l143; } } /* begin concretizeDataOperationCwR: */ constant = ((self_in_dispatchConcretize->operands))[0]; rn1 = ((self_in_dispatchConcretize->operands))[1]; rd1 = rn1; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord31 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord31; instrOffset2 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord111 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn1 << 16) | (((int)((usqInt)(rd1) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset2 / 4] = aWord111; (self_in_dispatchConcretize->machineCodeSize) = instrOffset2 + 4; goto l143; l136: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; l143: /* end concretizeNegateableDataOperationCqR: */; return; case AndCqR: /* begin concretizeInvertibleDataOperationCqR: */ val2 = ((self_in_dispatchConcretize->operands))[0]; rn18 = ((self_in_dispatchConcretize->operands))[1]; assert(!((((self_in_dispatchConcretize->opcode)) == CmpOpcode))); /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value4 = val2; while (1) { if ((value4 & 0xFF) == value4) { invert2 = val2 != value4; /* begin machineCodeAt:put: */ flagsOrOpcode2 = (invert2 ? inverseOpcodeFor(self_in_dispatchConcretize, AndOpcode) : AndOpcode); aWord65 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode2) << 21))) | (1U << 20)))) | ((rn18 << 16) | (rn18 << 12))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value4) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord65; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l319; } for (i8 = 2; i8 <= 30; i8 += 2) { if ((value4 & (((0xFFU << i8) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i8)))) == value4) { rot8 = 32 - i8; immediate15 = (((usqInt) value4) >> i8) | ((value4 << (32 - i8)) & 0xFFFFFFFFU); invert2 = val2 != value4; /* begin machineCodeAt:put: */ flagsOrOpcode11 = (invert2 ? inverseOpcodeFor(self_in_dispatchConcretize, AndOpcode) : AndOpcode); aWord65 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode11) << 21))) | (1U << 20)))) | ((rn18 << 16) | (rn18 << 12))) | (((((sqInt)((usqInt)((((usqInt) rot8) >> 1)) << 8))) | immediate15) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord65; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l319; } } if (!(value4 == val2)) break; value4 = (val2 < 0 ? -1 - val2 : (unsigned int)~val2); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val2 > 0) { hb2 = highBit(val2); if ((1U << hb2) == (val2 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord131 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord131; /* begin machineCodeAt:put: */ aWord223 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, rn18, rn18, ConcreteIPReg, 32 - hb2); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord223; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l331; } } /* begin concretizeDataOperationCqR: */ val11 = ((self_in_dispatchConcretize->operands))[0]; rn21 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd18 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn21); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val11 & 0xFF) == val11) { /* begin machineCodeAt:put: */ aWord410 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn21 << 16) | (((int)((usqInt)(rd18) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val11) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord410; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l365; } for (i13 = 2; i13 <= 30; i13 += 2) { if ((val11 & (((0xFFU << i13) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i13)))) == val11) { rot11 = 32 - i13; immediate14 = (((usqInt) val11) >> i13) | ((((sqInt)((usqInt)(val11) << (32 - i13)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord410 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn21 << 16) | (((int)((usqInt)(rd18) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot11) >> 1)) << 8))) | immediate14) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord410; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l331; goto l365; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val11 > 0) { hb11 = highBit(val11); if ((1U << hb11) == (val11 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord1210 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1210; /* begin machineCodeAt:put: */ aWord2110 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, rd18, rn21, ConcreteIPReg, 32 - hb11); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord2110; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l331; } } /* begin concretizeDataOperationCwR: */ constant10 = ((self_in_dispatchConcretize->operands))[0]; rn19 = ((self_in_dispatchConcretize->operands))[1]; rd19 = rn19; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord313 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord313; instrOffset26 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1110 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn19 << 16) | (((int)((usqInt)(rd19) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset26 / 4] = aWord1110; (self_in_dispatchConcretize->machineCodeSize) = instrOffset26 + 4; goto l331; l365: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; goto l331; l319: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l331: /* end concretizeInvertibleDataOperationCqR: */; return; case AndCqRR: /* begin concretizeAndCqRR */ val3 = ((self_in_dispatchConcretize->operands))[0]; srcReg19 = ((self_in_dispatchConcretize->operands))[1]; dstReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value5 = val3; while (1) { if ((value5 & 0xFF) == value5) { invert3 = val3 != value5; /* begin machineCodeAt:put: */ aWord66 = (invert3 ? bicsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, value5, 0) : andsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, value5, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord66; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l339; goto l337; } for (i9 = 2; i9 <= 30; i9 += 2) { if ((value5 & (((0xFFU << i9) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i9)))) == value5) { rot9 = 32 - i9; immediate16 = (((usqInt) value5) >> i9) | ((value5 << (32 - i9)) & 0xFFFFFFFFU); invert3 = val3 != value5; /* begin machineCodeAt:put: */ aWord66 = (invert3 ? bicsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, immediate16, rot9) : andsrnimmror(self_in_dispatchConcretize, dstReg1, srcReg19, immediate16, rot9)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord66; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l339; goto l337; } } if (!(value5 == val3)) break; value5 = (val3 < 0 ? -1 - val3 : (unsigned int)~val3); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ hb3 = highBit(((self_in_dispatchConcretize->operands))[0]); if ((1U << hb3) == (val3 + 1)) { /* MVN temp reg, 0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord132 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord132; /* begin machineCodeAt:put: */ aWord224 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, AndOpcode, dstReg1, srcReg19, ConcreteIPReg, 32 - hb3); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord224; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l339; } else { /* begin concretizeDataOperationCwR: */ constant12 = ((self_in_dispatchConcretize->operands))[0]; rn20 = ((self_in_dispatchConcretize->operands))[1]; rd20 = rn20; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord314 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord314; instrOffset27 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1111 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn20 << 16) | (((int)((usqInt)(rd20) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset27 / 4] = aWord1111; (self_in_dispatchConcretize->machineCodeSize) = instrOffset27 + 4; goto l339; } l337: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l339: /* end concretizeAndCqRR */; return; case CmpCqR: /* begin concretizeNegateableDataOperationCqR: */ val1 = ((self_in_dispatchConcretize->operands))[0]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen. */ rn2 = ((self_in_dispatchConcretize->operands))[1]; rd2 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn2); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value1 = val1; while (1) { if ((value1 & 0xFF) == value1) { negate1 = val1 != value1; /* begin machineCodeAt:put: */ flagsOrOpcode3 = (negate1 ? inverseOpcodeFor(self_in_dispatchConcretize, CmpOpcode) : CmpOpcode); aWord6 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode3) << 21))) | (1U << 20)))) | ((rn2 << 16) | (((int)((usqInt)(rd2) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value1) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord6; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l151; goto l144; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value1 & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value1) { rot1 = 32 - i1; immediate1 = (((usqInt) value1) >> i1) | ((((sqInt)((usqInt)(value1) << (32 - i1)))) & 0xFFFFFFFFU); negate1 = val1 != value1; /* begin machineCodeAt:put: */ flagsOrOpcode4 = (negate1 ? inverseOpcodeFor(self_in_dispatchConcretize, CmpOpcode) : CmpOpcode); aWord6 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode4) << 21))) | (1U << 20)))) | ((rn2 << 16) | (((int)((usqInt)(rd2) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot1) >> 1)) << 8))) | immediate1) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord6; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l151; goto l144; } } if (!((value1 == val1) && (val1 != 0))) break; value1 = -val1; } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val1 > 0) { hb1 = highBit(val1); if ((1U << hb1) == (val1 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord13 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord13; /* begin machineCodeAt:put: */ aWord23 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, CmpOpcode, rd2, rn2, ConcreteIPReg, 32 - hb1); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord23; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l151; } } /* begin concretizeDataOperationCwR: */ constant1 = ((self_in_dispatchConcretize->operands))[0]; rn11 = ((self_in_dispatchConcretize->operands))[1]; rd11 = 0; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord32 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord32; instrOffset3 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord112 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn11 << 16) | (((int)((usqInt)(rd11) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset3 / 4] = aWord112; (self_in_dispatchConcretize->machineCodeSize) = instrOffset3 + 4; goto l151; l144: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; l151: /* end concretizeNegateableDataOperationCqR: */; return; case OrCqR: /* begin concretizeDataOperationCqR: */ val4 = ((self_in_dispatchConcretize->operands))[0]; rn22 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd21 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn22); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val4 & 0xFF) == val4) { /* begin machineCodeAt:put: */ aWord67 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn22 << 16) | (((int)((usqInt)(rd21) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val4) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord67; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l349; goto l347; } for (i10 = 2; i10 <= 30; i10 += 2) { if ((val4 & (((0xFFU << i10) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i10)))) == val4) { rot10 = 32 - i10; immediate17 = (((usqInt) val4) >> i10) | ((((sqInt)((usqInt)(val4) << (32 - i10)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord67 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn22 << 16) | (((int)((usqInt)(rd21) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot10) >> 1)) << 8))) | immediate17) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord67; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l349; goto l347; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val4 > 0) { hb4 = highBit(val4); if ((1U << hb4) == (val4 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord133 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord133; /* begin machineCodeAt:put: */ aWord225 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, OrOpcode, rd21, rn22, ConcreteIPReg, 32 - hb4); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord225; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l349; } } /* begin concretizeDataOperationCwR: */ constant13 = ((self_in_dispatchConcretize->operands))[0]; rn110 = ((self_in_dispatchConcretize->operands))[1]; rd110 = rn110; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord315 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord315; instrOffset28 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1112 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn110 << 16) | (((int)((usqInt)(rd110) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset28 / 4] = aWord1112; (self_in_dispatchConcretize->machineCodeSize) = instrOffset28 + 4; goto l349; l347: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l349: /* end concretizeDataOperationCqR: */; return; case SubCqR: /* begin concretizeSubCqR */ word = ((self_in_dispatchConcretize->operands))[0]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((word & 0xFF) == word) { reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord7 = subsrnimmror(self_in_dispatchConcretize, reg1, reg1, word, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord7; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l152; } for (i11 = 2; i11 <= 30; i11 += 2) { if ((word & (((0xFFU << i11) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i11)))) == word) { rot2 = 32 - i11; immediate2 = (((usqInt) word) >> i11) | ((((sqInt)((usqInt)(word) << (32 - i11)))) & 0xFFFFFFFFU); reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord7 = subsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, rot2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord7; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l152; } } /* before building a full load of a big constant, see if we can do an add of the constant negated */ /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if (((-word) & 0xFF) == (-word)) { immediate2 = -word; reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord14 = addsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord14; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l366; } for (i2 = 2; i2 <= 30; i2 += 2) { if (((-word) & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == (-word)) { rot2 = 32 - i2; immediate2 = (((usqInt) (-word)) >> i2) | ((((sqInt)((usqInt)((-word)) << (32 - i2)))) & 0xFFFFFFFFU); reg1 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord14 = addsrnimmror(self_in_dispatchConcretize, reg1, reg1, immediate2, rot2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord14; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l159; goto l366; } } /* begin concretizeDataOperationCwR: */ constant2 = ((self_in_dispatchConcretize->operands))[0]; rn3 = ((self_in_dispatchConcretize->operands))[1]; rd3 = rn3; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord24 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord24; instrOffset4 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord113 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn3 << 16) | (((int)((usqInt)(rd3) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset4 / 4] = aWord113; (self_in_dispatchConcretize->machineCodeSize) = instrOffset4 + 4; goto l159; l366: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l152: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l159: /* end concretizeSubCqR */; return; case TstCqR: /* begin concretizeTstCqR */ constant11 = ((self_in_dispatchConcretize->operands))[0]; if ((constant11 & 0xFF) == constant11) { reg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord8 = tstrnimmror(self_in_dispatchConcretize, reg2, reg2, constant11, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord8; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l165; goto l160; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant11 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant11) { rot3 = 32 - i3; immediate3 = (((usqInt) constant11) >> i3) | ((((sqInt)((usqInt)(constant11) << (32 - i3)))) & 0xFFFFFFFFU); reg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord8 = tstrnimmror(self_in_dispatchConcretize, reg2, reg2, immediate3, rot3); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord8; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l165; goto l160; } } /* begin concretizeDataOperationCwR: */ constant3 = ((self_in_dispatchConcretize->operands))[0]; rn4 = ((self_in_dispatchConcretize->operands))[1]; rd4 = rn4; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord25 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord25; instrOffset5 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord15 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(TstOpcode) << 21))) | (1U << 20)))) | ((rn4 << 16) | (((int)((usqInt)(rd4) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset5 / 4] = aWord15; (self_in_dispatchConcretize->machineCodeSize) = instrOffset5 + 4; goto l165; l160: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l165: /* end concretizeTstCqR */; return; case XorCqR: /* begin concretizeInvertibleDataOperationCqR: */ val5 = ((self_in_dispatchConcretize->operands))[0]; rn23 = ((self_in_dispatchConcretize->operands))[1]; assert(!((((self_in_dispatchConcretize->opcode)) == CmpOpcode))); /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value6 = val5; while (1) { if ((value6 & 0xFF) == value6) { invert4 = val5 != value6; /* begin machineCodeAt:put: */ flagsOrOpcode5 = (invert4 ? inverseOpcodeFor(self_in_dispatchConcretize, XorOpcode) : XorOpcode); aWord68 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode5) << 21))) | (1U << 20)))) | ((rn23 << 16) | (rn23 << 12))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | value6) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord68; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l351; } for (i15 = 2; i15 <= 30; i15 += 2) { if ((value6 & (((0xFFU << i15) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i15)))) == value6) { rot12 = 32 - i15; immediate19 = (((usqInt) value6) >> i15) | ((value6 << (32 - i15)) & 0xFFFFFFFFU); invert4 = val5 != value6; /* begin machineCodeAt:put: */ flagsOrOpcode12 = (invert4 ? inverseOpcodeFor(self_in_dispatchConcretize, XorOpcode) : XorOpcode); aWord68 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((sqInt)((usqInt)(flagsOrOpcode12) << 21))) | (1U << 20)))) | ((rn23 << 16) | (rn23 << 12))) | (((((sqInt)((usqInt)((((usqInt) rot12) >> 1)) << 8))) | immediate19) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord68; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l351; } } if (!(value6 == val5)) break; value6 = (val5 < 0 ? -1 - val5 : (unsigned int)~val5); } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val5 > 0) { hb5 = highBit(val5); if ((1U << hb5) == (val5 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord134 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord134; /* begin machineCodeAt:put: */ aWord226 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, XorOpcode, rn23, rn23, ConcreteIPReg, 32 - hb5); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord226; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l363; } } /* begin concretizeDataOperationCqR: */ val12 = ((self_in_dispatchConcretize->operands))[0]; rn24 = ((self_in_dispatchConcretize->operands))[1]; /* Extra note - if ever a version of this code wants to NOT set the Set flag - Cmp must always have it set or it will pretend to be a SMALALBT and Very Bad Things might happen */ rd22 = (((self_in_dispatchConcretize->opcode)) == CmpOpcode ? 0 : rn24); /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((val12 & 0xFF) == val12) { /* begin machineCodeAt:put: */ aWord411 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn24 << 16) | (((int)((usqInt)(rd22) << 12))))) | (((((int)((usqInt)((((usqInt) 0) >> 1)) << 8))) | val12) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord411; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l367; } for (i14 = 2; i14 <= 30; i14 += 2) { if ((val12 & (((0xFFU << i14) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i14)))) == val12) { rot13 = 32 - i14; immediate18 = (((usqInt) val12) >> i14) | ((((sqInt)((usqInt)(val12) << (32 - i14)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord411 = (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn24 << 16) | (((int)((usqInt)(rd22) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot13) >> 1)) << 8))) | immediate18) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord411; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l363; goto l367; } } /* let's try to see if the constant can be made from a simple shift of 0xFFFFFFFF */ if (val12 > 0) { hb12 = highBit(val12); if ((1U << hb12) == (val12 + 1)) { /* MVN temp, #0, making 0xffffffff */ /* begin machineCodeAt:put: */ aWord1211 = mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, 0, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord1211; /* begin machineCodeAt:put: */ aWord2111 = dataOpTyperdrnrmlsr(self_in_dispatchConcretize, XorOpcode, rd22, rn24, ConcreteIPReg, 32 - hb12); ((self_in_dispatchConcretize->machineCode))[4 / 4] = aWord2111; (self_in_dispatchConcretize->machineCodeSize) = 8; goto l363; } } /* begin concretizeDataOperationCwR: */ constant14 = ((self_in_dispatchConcretize->operands))[0]; rn111 = ((self_in_dispatchConcretize->operands))[1]; rd111 = rn111; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord316 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord316; instrOffset29 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord1113 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn111 << 16) | (((int)((usqInt)(rd111) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset29 / 4] = aWord1113; (self_in_dispatchConcretize->machineCodeSize) = instrOffset29 + 4; goto l363; l367: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; goto l363; l351: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; l363: /* end concretizeInvertibleDataOperationCqR: */; return; case AddCwR: /* begin concretizeDataOperationCwR: */ constant4 = ((self_in_dispatchConcretize->operands))[0]; rn5 = ((self_in_dispatchConcretize->operands))[1]; rd5 = rn5; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord9 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord9; instrOffset6 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord16 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn5 << 16) | (((int)((usqInt)(rd5) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset6 / 4] = aWord16; (self_in_dispatchConcretize->machineCodeSize) = instrOffset6 + 4; return; case AndCwR: /* begin concretizeDataOperationCwR: */ constant5 = ((self_in_dispatchConcretize->operands))[0]; rn6 = ((self_in_dispatchConcretize->operands))[1]; rd6 = rn6; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord10 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord10; instrOffset7 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord17 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn6 << 16) | (((int)((usqInt)(rd6) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset7 / 4] = aWord17; (self_in_dispatchConcretize->machineCodeSize) = instrOffset7 + 4; return; case CmpCwR: /* begin concretizeDataOperationCwR: */ constant6 = ((self_in_dispatchConcretize->operands))[0]; rn7 = ((self_in_dispatchConcretize->operands))[1]; rd7 = 0; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord18 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord18; instrOffset8 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord19 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn7 << 16) | (((int)((usqInt)(rd7) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset8 / 4] = aWord19; (self_in_dispatchConcretize->machineCodeSize) = instrOffset8 + 4; return; case OrCwR: /* begin concretizeDataOperationCwR: */ constant7 = ((self_in_dispatchConcretize->operands))[0]; rn8 = ((self_in_dispatchConcretize->operands))[1]; rd8 = rn8; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord20 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord20; instrOffset9 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord110 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn8 << 16) | (((int)((usqInt)(rd8) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset9 / 4] = aWord110; (self_in_dispatchConcretize->machineCodeSize) = instrOffset9 + 4; return; case SubCwR: /* begin concretizeDataOperationCwR: */ constant8 = ((self_in_dispatchConcretize->operands))[0]; rn9 = ((self_in_dispatchConcretize->operands))[1]; rd9 = rn9; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord26 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord26; instrOffset10 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord114 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn9 << 16) | (((int)((usqInt)(rd9) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset10 / 4] = aWord114; (self_in_dispatchConcretize->machineCodeSize) = instrOffset10 + 4; return; case XorCwR: /* begin concretizeDataOperationCwR: */ constant9 = ((self_in_dispatchConcretize->operands))[0]; rn10 = ((self_in_dispatchConcretize->operands))[1]; rd10 = rn10; /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord27 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord27; instrOffset11 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord115 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn10 << 16) | (((int)((usqInt)(rd10) << 12))))) | (ConcreteIPReg & 0xFFF); ((self_in_dispatchConcretize->machineCode))[instrOffset11 / 4] = aWord115; (self_in_dispatchConcretize->machineCodeSize) = instrOffset11 + 4; return; case AddRR: /* begin concretizeDataOperationRR: */ srcReg1 = ((self_in_dispatchConcretize->operands))[0]; rn12 = ((self_in_dispatchConcretize->operands))[1]; rd12 = rn12; /* begin machineCodeAt:put: */ aWord28 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AddOpcode) << 21))) | (1U << 20)))) | ((rn12 << 16) | (((int)((usqInt)(rd12) << 12))))) | (srcReg1 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord28; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AndRR: /* begin concretizeDataOperationRR: */ srcReg2 = ((self_in_dispatchConcretize->operands))[0]; rn13 = ((self_in_dispatchConcretize->operands))[1]; rd13 = rn13; /* begin machineCodeAt:put: */ aWord29 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(AndOpcode) << 21))) | (1U << 20)))) | ((rn13 << 16) | (((int)((usqInt)(rd13) << 12))))) | (srcReg2 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord29; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CmpRR: /* begin concretizeDataOperationRR: */ srcReg3 = ((self_in_dispatchConcretize->operands))[0]; rn14 = ((self_in_dispatchConcretize->operands))[1]; rd14 = 0; /* begin machineCodeAt:put: */ aWord30 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(CmpOpcode) << 21))) | (1U << 20)))) | ((rn14 << 16) | (((int)((usqInt)(rd14) << 12))))) | (srcReg3 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord30; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case OrRR: /* begin concretizeDataOperationRR: */ srcReg4 = ((self_in_dispatchConcretize->operands))[0]; rn15 = ((self_in_dispatchConcretize->operands))[1]; rd15 = rn15; /* begin machineCodeAt:put: */ aWord33 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (1U << 20)))) | ((rn15 << 16) | (((int)((usqInt)(rd15) << 12))))) | (srcReg4 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord33; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SubRR: /* begin concretizeDataOperationRR: */ srcReg5 = ((self_in_dispatchConcretize->operands))[0]; rn16 = ((self_in_dispatchConcretize->operands))[1]; rd16 = rn16; /* begin machineCodeAt:put: */ aWord34 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((rn16 << 16) | (((int)((usqInt)(rd16) << 12))))) | (srcReg5 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord34; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case XorRR: /* begin concretizeDataOperationRR: */ srcReg6 = ((self_in_dispatchConcretize->operands))[0]; rn17 = ((self_in_dispatchConcretize->operands))[1]; rd17 = rn17; /* begin machineCodeAt:put: */ aWord35 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(XorOpcode) << 21))) | (1U << 20)))) | ((rn17 << 16) | (((int)((usqInt)(rd17) << 12))))) | (srcReg6 & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord35; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case AddRdRd: /* begin concretizeAddRdRd */ regRHS = ((self_in_dispatchConcretize->operands))[0]; regLHS = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3996125952U | (regLHS << 16)) | (regLHS << 12)) | regRHS); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case CmpRdRd: /* begin concretizeCmpRdRd */ regA = ((self_in_dispatchConcretize->operands))[0]; regB = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = ((4004776768U | (regB << 12)) | regA); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case DivRdRd: /* begin concretizeDivRdRd */ regRHS1 = ((self_in_dispatchConcretize->operands))[0]; regLHS1 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((4001368832U | (regLHS1 << 16)) | (regLHS1 << 12)) | regRHS1); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MulRdRd: /* begin concretizeMulRdRd */ regRHS2 = ((self_in_dispatchConcretize->operands))[0]; regLHS2 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3995077376U | (regLHS2 << 16)) | (regLHS2 << 12)) | regRHS2); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SubRdRd: /* begin concretizeSubRdRd */ regRHS3 = ((self_in_dispatchConcretize->operands))[0]; regLHS3 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (((3996126016U | (regLHS3 << 16)) | (regLHS3 << 12)) | regRHS3); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SqrtRd: /* begin concretizeSqrtRd */ regLHS4 = ((self_in_dispatchConcretize->operands))[0]; ((self_in_dispatchConcretize->machineCode))[0] = ((4004580288U | (regLHS4 << 12)) | regLHS4); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case NegateR: /* begin concretizeNegateR */ /* RSB destReg, srcReg, #0 */ reg3 = ((self_in_dispatchConcretize->operands))[0]; aWord36 = ((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(RsbOpcode) << 21))) | (0U << 20)))) | ((reg3 << 16) | (reg3 << 12)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord36; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LoadEffectiveAddressMwrR: /* begin concretizeLoadEffectiveAddressMwrR */ offset27 = ((self_in_dispatchConcretize->operands))[0]; srcReg7 = ((self_in_dispatchConcretize->operands))[1]; destReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((offset27 & 0xFF) == offset27) { /* begin machineCodeAt:put: */ aWord37 = addrnimmror(self_in_dispatchConcretize, destReg1, srcReg7, offset27, 0U << 1); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord37; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l204; } for (i4 = 2; i4 <= 30; i4 += 2) { if ((offset27 & (((0xFFU << i4) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i4)))) == offset27) { rot4 = 32 - i4; immediate4 = (((usqInt) offset27) >> i4) | ((offset27 << (32 - i4)) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord37 = addrnimmror(self_in_dispatchConcretize, destReg1, srcReg7, immediate4, ((sqInt)((usqInt)(rot4) << 1))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord37; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l204; } } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord116 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord116; instrOffset12 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord210 = addrnrm(self_in_dispatchConcretize, destReg1, srcReg7, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[16 / 4] = aWord210; (self_in_dispatchConcretize->machineCodeSize) = instrOffset12 + 4; l204: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; (self_in_dispatchConcretize->machineCodeSize); return; case ArithmeticShiftRightCqR: /* begin concretizeArithmeticShiftRightCqR */ distance = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dist -100 srcR */ reg4 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord38 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg4 << 12))) | (((((sqInt)((usqInt)(distance) << 7))) | (64 | reg4)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord38; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftRightCqR: /* begin concretizeLogicalShiftRightCqR */ distance1 = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dist -010 srcR */ reg5 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord39 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg5 << 12))) | (((((sqInt)((usqInt)(distance1) << 7))) | (32 | reg5)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord39; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftLeftCqR: /* begin concretizeLogicalShiftLeftCqR */ distance2 = (((((self_in_dispatchConcretize->operands))[0]) < 0x1F) ? (((self_in_dispatchConcretize->operands))[0]) : 0x1F); /* cond 000 1101 0 0000 dest dista 000 srcR */ reg6 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord40 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (reg6 << 12))) | (((((sqInt)((usqInt)(distance2) << 7))) | reg6) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord40; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case ArithmeticShiftRightRR: /* begin concretizeArithmeticShiftRightRR */ distReg = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 destR distR 0101 srcR */ destReg2 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord41 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg2 << 12))) | (((distReg << 8) | (80 | destReg2)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord41; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftLeftRR: /* begin concretizeLogicalShiftLeftRR */ distReg1 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest dist 0001 srcR */ destReg3 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord42 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg3 << 12))) | (((distReg1 << 8) | (16 | destReg3)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord42; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case LogicalShiftRightRR: /* begin concretizeLogicalShiftRightRR */ distReg2 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest dist 0011 srcR */ destReg4 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord43 = (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (destReg4 << 12))) | (((distReg2 << 8) | (48 | destReg4)) & 0xFFF); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord43; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case SMULL: concretizeSMULL(self_in_dispatchConcretize); return; case CMPSMULL: concretizeCMPSMULL(self_in_dispatchConcretize); return; case MSR: concretizeMSR(self_in_dispatchConcretize); return; case PopLDM: concretizePushOrPopMultipleRegisters(self_in_dispatchConcretize, 0); return; case PushSTM: concretizePushOrPopMultipleRegisters(self_in_dispatchConcretize, 1); return; case MoveCqR: /* begin concretizeMoveCqR */ word1 = ((self_in_dispatchConcretize->operands))[0]; reg7 = ((self_in_dispatchConcretize->operands))[1]; /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((word1 & 0xFF) == word1) { /* begin machineCodeAt:put: */ aWord44 = movimmror(self_in_dispatchConcretize, reg7, word1, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord44; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l224; } for (i12 = 2; i12 <= 30; i12 += 2) { if ((word1 & (((0xFFU << i12) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i12)))) == word1) { rot5 = 32 - i12; immediate5 = (((usqInt) word1) >> i12) | ((((sqInt)((usqInt)(word1) << (32 - i12)))) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord44 = movimmror(self_in_dispatchConcretize, reg7, immediate5, rot5); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord44; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l224; } } if (word1 < 0) { invVal = -1 - word1; } else { invVal = (unsigned int)~word1; } /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ if ((invVal & 0xFF) == invVal) { /* begin machineCodeAt:put: */ aWord117 = mvnimmror(self_in_dispatchConcretize, reg7, invVal, 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord117; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l368; } for (i5 = 2; i5 <= 30; i5 += 2) { if ((invVal & (((0xFFU << i5) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i5)))) == invVal) { rot5 = 32 - i5; immediate5 = (((usqInt) invVal) >> i5) | ((invVal << (32 - i5)) & 0xFFFFFFFFU); /* begin machineCodeAt:put: */ aWord117 = mvnimmror(self_in_dispatchConcretize, reg7, immediate5, rot5); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord117; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l226; goto l368; } } (self_in_dispatchConcretize->machineCodeSize) = loadCwInto(self_in_dispatchConcretize, ((self_in_dispatchConcretize->operands))[1]); goto l226; l368: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l224: /* end rotateable8bitImmediate:ifTrue:ifFalse: */; l226: /* end concretizeMoveCqR */; return; case MoveCwR: /* begin concretizeMoveCwR */ (self_in_dispatchConcretize->machineCodeSize) = loadCwInto(self_in_dispatchConcretize, ((self_in_dispatchConcretize->operands))[1]); return; case MoveRR: /* begin concretizeMoveRR */ srcReg8 = ((self_in_dispatchConcretize->operands))[0]; /* cond 000 1101 0 0000 dest 0000 0000 srcR */ destReg5 = ((self_in_dispatchConcretize->operands))[1]; /* begin machineCodeAt:put: */ aWord45 = movrn(self_in_dispatchConcretize, destReg5, srcReg8); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord45; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveAwR: /* begin concretizeMoveAwR */ srcAddr = ((self_in_dispatchConcretize->operands))[0]; destReg6 = ((self_in_dispatchConcretize->operands))[1]; if ((srcAddr != null) && ((srcAddr >= (varBaseAddress())) && ((srcAddr - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord46 = ldrrnplusImm(self_in_dispatchConcretize, destReg6, ConcreteVarBaseReg, srcAddr - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord46; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l233; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord118 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord118; instrOffset13 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord211 = ldrrnplusImm(self_in_dispatchConcretize, destReg6, ConcreteIPReg, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset13 / 4] = aWord211; (self_in_dispatchConcretize->machineCodeSize) = instrOffset13 + 4; l233: /* end concretizeMoveAwR */; return; case MoveRAw: /* begin concretizeMoveRAw */ srcReg9 = ((self_in_dispatchConcretize->operands))[0]; destAddr = ((self_in_dispatchConcretize->operands))[1]; if ((destAddr != null) && ((destAddr >= (varBaseAddress())) && ((destAddr - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord47 = strrnplusImm(self_in_dispatchConcretize, srcReg9, ConcreteVarBaseReg, destAddr - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord47; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l238; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord119 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord119; instrOffset14 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord212 = strrnplusImm(self_in_dispatchConcretize, srcReg9, ConcreteIPReg, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset14 / 4] = aWord212; (self_in_dispatchConcretize->machineCodeSize) = instrOffset14 + 4; l238: /* end concretizeMoveRAw */; return; case MoveAbR: /* begin concretizeMoveAbR */ srcAddr1 = ((self_in_dispatchConcretize->operands))[0]; destReg7 = ((self_in_dispatchConcretize->operands))[1]; if ((srcAddr1 != null) && ((srcAddr1 >= (varBaseAddress())) && ((srcAddr1 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord48 = ldrbrnplusimm(self_in_dispatchConcretize, destReg7, ConcreteVarBaseReg, 1, srcAddr1 - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord48; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l243; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord120 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord120; instrOffset15 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord213 = ldrbrnplusimm(self_in_dispatchConcretize, destReg7, ConcreteIPReg, 1, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset15 / 4] = aWord213; (self_in_dispatchConcretize->machineCodeSize) = instrOffset15 + 4; l243: /* end concretizeMoveAbR */; return; case MoveRAb: /* begin concretizeMoveRAb */ srcReg10 = ((self_in_dispatchConcretize->operands))[0]; destAddr1 = ((self_in_dispatchConcretize->operands))[1]; if ((destAddr1 != null) && ((destAddr1 >= (varBaseAddress())) && ((destAddr1 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord49 = strbrnplusimm(self_in_dispatchConcretize, srcReg10, ConcreteVarBaseReg, 1, destAddr1 - (varBaseAddress())); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord49; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l248; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord121 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord121; instrOffset16 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord214 = strbrnplusimm(self_in_dispatchConcretize, srcReg10, ConcreteIPReg, 1, 0); ((self_in_dispatchConcretize->machineCode))[instrOffset16 / 4] = aWord214; (self_in_dispatchConcretize->machineCodeSize) = instrOffset16 + 4; l248: /* end concretizeMoveRAb */; return; case MoveMbrR: /* begin concretizeMoveMbrR */ offset28 = ((self_in_dispatchConcretize->operands))[0]; srcReg11 = ((self_in_dispatchConcretize->operands))[1]; destReg8 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset28)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset28 >= 0) { /* begin machineCodeAt:put: */ aWord50 = ldrbrnplusimm(self_in_dispatchConcretize, destReg8, srcReg11, 1, offset28); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord50; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l255; goto l252; } else { immediate6 = SQABS(offset28); /* begin machineCodeAt:put: */ aWord50 = ldrbrnplusimm(self_in_dispatchConcretize, destReg8, srcReg11, 0, immediate6); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord50; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l255; goto l252; } } else { if ((offset28 != null) && ((offset28 >= (varBaseAddress())) && ((offset28 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord122 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset28 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord122; instrOffset17 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord215 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord215; instrOffset17 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord310 = ldrbrnrm(self_in_dispatchConcretize, destReg8, srcReg11, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset17 / 4] = aWord310; (self_in_dispatchConcretize->machineCodeSize) = instrOffset17 + 4; goto l255; goto l252; } l252: /* end is12BitValue:ifTrue:ifFalse: */; l255: /* end concretizeMoveMbrR */; return; case MoveRMbr: /* begin concretizeMoveRMbr */ srcReg12 = ((self_in_dispatchConcretize->operands))[0]; offset29 = ((self_in_dispatchConcretize->operands))[1]; baseReg = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset29)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset29 >= 0) { /* begin machineCodeAt:put: */ aWord51 = strbrnplusimm(self_in_dispatchConcretize, srcReg12, baseReg, 1, offset29); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord51; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l262; goto l259; } else { immediate7 = SQABS(offset29); /* begin machineCodeAt:put: */ aWord51 = strbrnplusimm(self_in_dispatchConcretize, srcReg12, baseReg, 0, immediate7); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord51; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l262; goto l259; } } else { if ((offset29 != null) && ((offset29 >= (varBaseAddress())) && ((offset29 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord123 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset29 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord123; instrOffset18 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord216 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord216; instrOffset18 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord311 = strbrnrm(self_in_dispatchConcretize, srcReg12, baseReg, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset18 / 4] = aWord311; (self_in_dispatchConcretize->machineCodeSize) = instrOffset18 + 4; goto l262; goto l259; } l259: /* end is12BitValue:ifTrue:ifFalse: */; l262: /* end concretizeMoveRMbr */; return; case MoveRM16r: /* begin concretizeMoveRM16r */ srcReg13 = ((self_in_dispatchConcretize->operands))[0]; offset30 = ((self_in_dispatchConcretize->operands))[1]; baseReg1 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset30)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset30 >= 0) { /* begin machineCodeAt:put: */ aWord52 = strhrnplusimm(self_in_dispatchConcretize, srcReg13, baseReg1, 1, offset30); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord52; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l269; goto l266; } else { immediate8 = SQABS(offset30); /* begin machineCodeAt:put: */ aWord52 = strhrnplusimm(self_in_dispatchConcretize, srcReg13, baseReg1, 0, immediate8); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord52; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l269; goto l266; } } else { if ((offset30 != null) && ((offset30 >= (varBaseAddress())) && ((offset30 - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ aWord124 = addsrnimmror(self_in_dispatchConcretize, ConcreteIPReg, ConcreteVarBaseReg, offset30 - (varBaseAddress()), 0); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord124; instrOffset19 = 4; } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord217 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord217; instrOffset19 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); } /* begin machineCodeAt:put: */ aWord312 = strhrnrm(self_in_dispatchConcretize, srcReg13, baseReg1, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset19 / 4] = aWord312; (self_in_dispatchConcretize->machineCodeSize) = instrOffset19 + 4; goto l269; goto l266; } l266: /* end is12BitValue:ifTrue:ifFalse: */; l269: /* end concretizeMoveRM16r */; return; case MoveM16rR: /* begin concretizeMoveM16rR */ offset31 = ((self_in_dispatchConcretize->operands))[0]; srcReg14 = ((self_in_dispatchConcretize->operands))[1]; destReg9 = ((self_in_dispatchConcretize->operands))[2]; /* begin is8BitValue:ifTrue:ifFalse: */ if ((SQABS(offset31)) <= 0xFF) { /* (2 raisedTo: 8)-1 */ if (offset31 >= 0) { /* begin machineCodeAt:put: */ aWord53 = ldrhrnplusimm(self_in_dispatchConcretize, destReg9, srcReg14, 1, offset31); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord53; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l275; } else { immediate9 = SQABS(offset31); /* begin machineCodeAt:put: */ aWord53 = ldrhrnplusimm(self_in_dispatchConcretize, destReg9, srcReg14, 0, immediate9); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord53; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l275; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord125 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord125; instrOffset20 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord218 = ldrhrnrm(self_in_dispatchConcretize, destReg9, srcReg14, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset20 / 4] = aWord218; (self_in_dispatchConcretize->machineCodeSize) = instrOffset20 + 4; goto l275; } l275: /* end concretizeMoveM16rR */; return; case MoveM64rRd: /* begin concretizeMoveM64rRd */ offset = ((self_in_dispatchConcretize->operands))[0]; u = (offset > 0 ? 1 : 0); srcReg = ((self_in_dispatchConcretize->operands))[1]; destReg = ((self_in_dispatchConcretize->operands))[2]; ((self_in_dispatchConcretize->machineCode))[0] = ((((3977251584U | (srcReg << 16)) | (destReg << 12)) | (((int)((usqInt)(u) << 23)))) | (((usqInt) offset) >> 2)); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveMwrR: /* begin concretizeMoveMwrR */ offset32 = ((self_in_dispatchConcretize->operands))[0]; srcReg15 = ((self_in_dispatchConcretize->operands))[1]; destReg10 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset32)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset32 >= 0) { /* begin machineCodeAt:put: */ aWord54 = ldrrnplusimm(self_in_dispatchConcretize, destReg10, srcReg15, 1, offset32); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord54; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l281; goto l276; } else { immediate10 = SQABS(offset32); /* begin machineCodeAt:put: */ aWord54 = ldrrnplusimm(self_in_dispatchConcretize, destReg10, srcReg15, 0, immediate10); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord54; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l281; goto l276; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord126 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord126; instrOffset21 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord219 = ldrrnrm(self_in_dispatchConcretize, destReg10, srcReg15, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset21 / 4] = aWord219; (self_in_dispatchConcretize->machineCodeSize) = instrOffset21 + 4; goto l281; goto l276; } l276: /* end is12BitValue:ifTrue:ifFalse: */; l281: /* end concretizeMoveMwrR */; return; case MoveXbrRR: /* begin concretizeMoveXbrRR */ /* index is number of *bytes* */ index = ((self_in_dispatchConcretize->operands))[0]; base = ((self_in_dispatchConcretize->operands))[1]; /* LDRB dest, [base, +index, LSL #0] */ /* cond 011 1100 1 base dest 00000 00 0 inde */ dest = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord55 = ldrbrnrm(self_in_dispatchConcretize, dest, base, index); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord55; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRXbrR: /* begin concretizeMoveRXbrR */ src = ((self_in_dispatchConcretize->operands))[0]; index1 = ((self_in_dispatchConcretize->operands))[1]; /* str b src, [base, +index, LSL #0] */ /* cond 011 1100 0 base srcR 00000 00 0 index */ base1 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord56 = strbrnrm(self_in_dispatchConcretize, src, base1, index1); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord56; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveXwrRR: /* begin concretizeMoveXwrRR */ index2 = ((self_in_dispatchConcretize->operands))[0]; base2 = ((self_in_dispatchConcretize->operands))[1]; /* LDR dest, [base, +index, LSL #2] */ /* cond 011 1100 1 base dest 00010 00 0 inde bulit by lowest level generator so we can do the lsl #2 on the index register */ dest1 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord57 = memMxrregbasepubwlrmLsl2(self_in_dispatchConcretize, AL, dest1, base2, 1, 1, 0, 0, 1, index2); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord57; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRXwrR: /* begin concretizeMoveRXwrR */ src1 = ((self_in_dispatchConcretize->operands))[0]; /* index is number of *words* = 4* bytes */ index3 = ((self_in_dispatchConcretize->operands))[1]; /* str src, [base, +index, LSL #2] */ /* cond 011 1100 0 base srcR 00010 00 0 inde */ base3 = ((self_in_dispatchConcretize->operands))[2]; /* begin machineCodeAt:put: */ aWord58 = memMxrregbasepubwlrmLsl2(self_in_dispatchConcretize, AL, src1, base3, 1, 1, 0, 0, 0, index3); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord58; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case MoveRMwr: /* begin concretizeMoveRMwr */ srcReg16 = ((self_in_dispatchConcretize->operands))[0]; offset33 = ((self_in_dispatchConcretize->operands))[1]; baseReg2 = ((self_in_dispatchConcretize->operands))[2]; /* begin is12BitValue:ifTrue:ifFalse: */ if ((SQABS(offset33)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (offset33 >= 0) { /* begin machineCodeAt:put: */ aWord59 = strrnplusimm(self_in_dispatchConcretize, srcReg16, baseReg2, 1, offset33); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord59; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l295; goto l290; } else { immediate11 = SQABS(offset33); /* begin machineCodeAt:put: */ aWord59 = strrnplusimm(self_in_dispatchConcretize, srcReg16, baseReg2, 0, immediate11); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord59; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l295; goto l290; } } else { /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord127 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord127; instrOffset22 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord220 = strrnrm(self_in_dispatchConcretize, srcReg16, baseReg2, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset22 / 4] = aWord220; (self_in_dispatchConcretize->machineCodeSize) = instrOffset22 + 4; goto l295; goto l290; } l290: /* end is12BitValue:ifTrue:ifFalse: */; l295: /* end concretizeMoveRMwr */; return; case MoveRdM64r: /* begin concretizeMoveRdM64r */ offset1 = ((self_in_dispatchConcretize->operands))[1]; u1 = (offset1 > 0 ? 1 : 0); dstReg = ((self_in_dispatchConcretize->operands))[2]; fpReg = ((self_in_dispatchConcretize->operands))[0]; ((self_in_dispatchConcretize->machineCode))[0] = ((((3976203008U | (dstReg << 16)) | (fpReg << 12)) | (((int)((usqInt)(u1) << 23)))) | (((usqInt) offset1) >> 2)); (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PopR: /* begin concretizePopR */ /* LDR destReg, [SP], #4 */ destReg11 = ((self_in_dispatchConcretize->operands))[0]; aWord60 = popR(self_in_dispatchConcretize, destReg11); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord60; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PushR: /* begin concretizePushR */ /* cond | 010 | 1001 | 0 | -Rn- | -Rd- | 0000 0000 0100 */ /* STR srcReg, [sp, #-4] */ srcReg17 = ((self_in_dispatchConcretize->operands))[0]; aWord61 = pushR(self_in_dispatchConcretize, srcReg17); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord61; (self_in_dispatchConcretize->machineCodeSize) = 4; return; case PushCq: /* begin concretizePushCq */ word2 = ((self_in_dispatchConcretize->operands))[0]; /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value2 = word2; while (1) { if ((value2 & 0xFF) == value2) { invert = word2 != value2; /* begin machineCodeAt:put: */ aWord62 = (invert ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, value2, 0) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, value2, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord62; instrOffset23 = 4; goto l303; } for (i6 = 2; i6 <= 30; i6 += 2) { if ((value2 & (((0xFFU << i6) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i6)))) == value2) { rot6 = 32 - i6; immediate12 = (((usqInt) value2) >> i6) | ((value2 << (32 - i6)) & 0xFFFFFFFFU); invert = word2 != value2; /* begin machineCodeAt:put: */ aWord62 = (invert ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate12, rot6) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate12, rot6)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord62; instrOffset23 = 4; goto l303; } } if (!(value2 == word2)) break; value2 = (word2 < 0 ? -1 - word2 : (unsigned int)~word2); } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord128 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord128; instrOffset23 = ((usqInt) (((self_in_dispatchConcretize->machineCodeSize) = 4))); l303: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; /* begin machineCodeAt:put: */ aWord221 = pushR(self_in_dispatchConcretize, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset23 / 4] = aWord221; (self_in_dispatchConcretize->machineCodeSize) = instrOffset23 + 4; return; case PushCw: /* begin concretizePushCw */ word3 = ((self_in_dispatchConcretize->operands))[0]; if (((addressIsInInstructions(((AbstractInstruction *) word3))) || ((((AbstractInstruction *) word3)) == (methodLabel()))) || (((((usqInt)word3)) >= ((methodLabel->address))) && ((((usqInt)word3)) < (youngReferrers())))) { instrOffset24 = loadCwInto(self_in_dispatchConcretize, ConcreteIPReg); } else { /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ value3 = word3; while (1) { if ((value3 & 0xFF) == value3) { invert1 = word3 != value3; /* begin machineCodeAt:put: */ aWord63 = (invert1 ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, value3, 0) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, value3, 0)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord63; instrOffset24 = 4; goto l308; } for (i7 = 2; i7 <= 30; i7 += 2) { if ((value3 & (((0xFFU << i7) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i7)))) == value3) { rot7 = 32 - i7; immediate13 = (((usqInt) value3) >> i7) | ((value3 << (32 - i7)) & 0xFFFFFFFFU); invert1 = word3 != value3; /* begin machineCodeAt:put: */ aWord63 = (invert1 ? mvnimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate13, rot7) : movimmror(self_in_dispatchConcretize, ConcreteIPReg, immediate13, rot7)); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord63; instrOffset24 = 4; goto l308; } } if (!(value3 == word3)) break; value3 = (word3 < 0 ? -1 - word3 : (unsigned int)~word3); } instrOffset24 = loadCwInto(self_in_dispatchConcretize, ConcreteIPReg); l308: /* end rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */; } /* begin machineCodeAt:put: */ aWord129 = pushR(self_in_dispatchConcretize, ConcreteIPReg); ((self_in_dispatchConcretize->machineCode))[instrOffset24 / 4] = aWord129; (self_in_dispatchConcretize->machineCodeSize) = instrOffset24 + 4; return; case PrefetchAw: /* begin concretizePrefetchAw */ addressOperand = ((self_in_dispatchConcretize->operands))[0]; if ((addressOperand != null) && ((addressOperand >= (varBaseAddress())) && ((addressOperand - (varBaseAddress())) < (1U << 12)))) { /* begin machineCodeAt:put: */ immediate20 = addressOperand - (varBaseAddress()); aWord64 = ((usqInt) (4115722240U | ((((int)((usqInt)(ConcreteVarBaseReg) << 16))) | ((1U << 23) | immediate20)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord64; (self_in_dispatchConcretize->machineCodeSize) = 4; goto l314; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_dispatchConcretize->dependent))->address))); assert((SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord130 = ldrrnplusimm(self_in_dispatchConcretize, ConcreteIPReg, PC, (((((self_in_dispatchConcretize->dependent))->address)) >= (((self_in_dispatchConcretize->address)) + 8) ? 1 : 0), SQABS((((((self_in_dispatchConcretize->dependent))->address)) - (((self_in_dispatchConcretize->address)) + 8)))); ((self_in_dispatchConcretize->machineCode))[0 / 4] = aWord130; instrOffset25 = ((self_in_dispatchConcretize->machineCodeSize) = 4); /* begin machineCodeAt:put: */ aWord222 = 4115722240U | ((((int)((usqInt)(ConcreteIPReg) << 16))) | ((1U << 23) | 0)); ((self_in_dispatchConcretize->machineCode))[instrOffset25 / 4] = aWord222; (self_in_dispatchConcretize->machineCodeSize) = instrOffset25 + 4; l314: /* end concretizePrefetchAw */; return; case ConvertRRd: /* begin concretizeConvertRRd */ srcReg18 = ((self_in_dispatchConcretize->operands))[0]; destReg12 = ((self_in_dispatchConcretize->operands))[1]; ((self_in_dispatchConcretize->machineCode))[0] = (fmsrFromto(self_in_dispatchConcretize, srcReg18, 9)); ((self_in_dispatchConcretize->machineCode))[1] = (fsitodFromto(self_in_dispatchConcretize, 9, destReg12)); (self_in_dispatchConcretize->machineCodeSize) = 8; return; default: error("Case not found and no otherwise clause"); } return; } /* FMSR or VMOV instruction to move a value from an ARM reg to an fpu double register ready for conversion FMSR regB, regA - ARM_ARM v5 DDI 01001.pdf pp. C4-68 VMOV regB, regA - ARM_ARM v7 DDi10406 pp. A8-462-3 */ /* the dest reg bits are spread out a little */ /* CogARMCompiler>>#fmsrFrom:to: */ static usqInt NoDbgRegParms fmsrFromto(AbstractInstruction * self_in_fmsrFromto, sqInt regA, sqInt regB) { sqInt destReg; destReg = (((sqInt)((usqInt)((((usqInt) regB) >> 1)) << 16))) | (((sqInt)((usqInt)((regB & 1)) << 7))); return (3992979984U | (((sqInt)((usqInt)(regA) << 12)))) | destReg; } /* FSITOD or VCVT instruction to move convert an integer value to an fpu double FSITOD regB, regA - ARM_ARM v5 DDI 01001.pdf pp. C4-95 VCVTW. regB, regA - ARM_ARM v7 DDI10406.pdf pp. A8-576-8 */ /* the src reg bits are spread out a little */ /* CogARMCompiler>>#fsitodFrom:to: */ static usqInt NoDbgRegParms fsitodFromto(AbstractInstruction * self_in_fsitodFromto, sqInt regA, sqInt regB) { sqInt srcReg; srcReg = (((usqInt) regA) >> 1) | (((sqInt)((usqInt)((regA & 1)) << 5))); return (4005039040U | srcReg) | (((sqInt)((usqInt)(regB) << 12))); } /* Answer if CallFull and/or JumpFull are relative and hence need relocating on method compation. If so, they are annotated with IsRelativeCall in methods and relocated in relocateIfCallOrMethodReference:mcpc:delta: */ /* CogARMCompiler>>#fullCallsAreRelative */ static sqInt NoDbgRegParms fullCallsAreRelative(AbstractInstruction * self_in_fullCallsAreRelative) { return 0; } /* Currently no instruction level support for divide on ARM. See also #canDivQuoRem */ /* CogARMCompiler>>#genDivR:R:Quo:Rem: */ static AbstractInstruction * NoDbgRegParms genDivRRQuoRem(AbstractInstruction * self_in_genDivRRQuoRem, sqInt abstractRegDivisor, sqInt abstractRegDividend, sqInt abstractRegQuotient, sqInt abstractRegRemainder) { usqInt divRemFunctionAddr; AbstractInstruction * inst; sqInt rDividend; sqInt rDivisor; sqInt rQuotient; sqInt rRemainder; assert(abstractRegDividend != abstractRegDivisor); assert(abstractRegQuotient != abstractRegRemainder); rDividend = abstractRegDividend; rDivisor = abstractRegDivisor; if (!(rDividend == CArg0Reg)) { /* we need to move the value in rDividend to CArg0Reg. Best to double check if rDivisor is already using it first */ if (rDivisor == CArg0Reg) { /* oh dear; we also need to move rDivisor's value out of the way first.. I'll move it to CArg1Reg and if some nitwit has managed to put rDividend there they deserve the crash */ if (rDividend == CArg1Reg) { error("register choices in genDivR:R:Quo:Rem: made life impossible"); } genoperandoperand(MoveRR, rDivisor, CArg1Reg); rDivisor = CArg1Reg; } genoperandoperand(MoveRR, rDividend, CArg0Reg); } if (!(rDivisor == CArg1Reg)) { genoperandoperand(MoveRR, rDivisor, CArg1Reg); } divRemFunctionAddr = aeabiDivModFunctionAddr(self_in_genDivRRQuoRem); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); CallFullRTregistersToBeSavedMask(((usqInt)divRemFunctionAddr), (1U << CArg2Reg) | (1U << CArg3Reg)); genoperand(PopR, LinkReg); rQuotient = abstractRegQuotient; rRemainder = abstractRegRemainder; if (!(rQuotient == CArg0Reg)) { /* oh good grief, not again */ genoperandoperand(MoveRR, CArg0Reg, rQuotient); if (rQuotient == CArg1Reg) { error("register choices in genDivR:R:Quo:Rem: made life impossible"); } } if (!(rRemainder == CArg1Reg)) { genoperandoperand(MoveRR, CArg1Reg, rRemainder); } return self_in_genDivRRQuoRem; } /* Load the stack pointer register with that of the C stack, effecting a switch to the C stack. Used when machine code calls into the CoInterpreter run-time (e.g. to invoke interpreter primitives). */ /* CogARMCompiler>>#genLoadCStackPointer */ static sqInt NoDbgRegParms genLoadCStackPointer(AbstractInstruction * self_in_genLoadCStackPointer) { sqInt address; /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); return 0; } /* Load the frame and stack pointer registers with those of the C stack, effecting a switch to the C stack. Used when machine code calls into the CoInterpreter run-time (e.g. to invoke interpreter primitives). */ /* CogARMCompiler>>#genLoadCStackPointers */ static sqInt NoDbgRegParms genLoadCStackPointers(AbstractInstruction * self_in_genLoadCStackPointers) { sqInt address; sqInt address1; /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); /* begin MoveAw:R: */ address1 = cFramePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, FPReg)); return 0; } /* Switch back to the Smalltalk stack. Assign SPReg first because typically it is used immediately afterwards. */ /* CogARMCompiler>>#genLoadStackPointers */ static sqInt NoDbgRegParms genLoadStackPointers(AbstractInstruction * self_in_genLoadStackPointers) { sqInt address; sqInt address1; /* begin MoveAw:R: */ address = stackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); /* begin MoveAw:R: */ address1 = framePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, FPReg)); return 0; } /* Use SMULL to produce a 64-bit result, explicitly in RISCTempReg,regDest. - ARM_ARM v7 DDI10406 pp. A8-354-5 By comparing RISCTempReg with regDest ASR 31(which effectively makes it 0 or -1) we know that the result being EQ means the hi reg and the top bit of the lo reg are the same - ie no overflow. The condition code can then be forced to oVerflow by use of MSR APSR_nzcvq, #1, lsl 28 */ /* CogARMCompiler>>#genMulR:R: */ static AbstractInstruction * NoDbgRegParms genMulRR(AbstractInstruction * self_in_genMulRR, sqInt regSource, sqInt regDest) { AbstractInstruction *first; /* result in RISCTempReg,regDest */ first = genoperandoperand(SMULL, regSource, regDest); genoperandoperand(CMPSMULL, RISCTempReg, regDest); genoperand(MSR, 1); return first; } /* 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. */ /* 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 sp -> outerRetpc (send site retpc) linkReg = innerRetpc (PIC abort/miss retpc) to base -> receiver (arg0) (arg1) sp -> outerRetpc (send site retpc) sp -> linkReg/innerRetpc (PIC abort/miss retpc) */ /* CogARMCompiler>>#genPushRegisterArgsForAbortMissNumArgs: */ static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForAbortMissNumArgs(AbstractInstruction * self_in_genPushRegisterArgsForAbortMissNumArgs, sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; if (numArgs <= 2 /* numRegArgs */) { assert((numRegArgs()) <= 2); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, SPReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, ReceiverResultReg, 0, SPReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } if (numArgs > 0) { genoperand(PushR, Arg0Reg); if (numArgs > 1) { genoperand(PushR, Arg1Reg); } } genoperand(PushR, TempReg); } genoperand(PushR, LinkReg); return self_in_genPushRegisterArgsForAbortMissNumArgs; } /* Ensure that the register args are pushed before the retpc for arity <= self numRegArgs. */ /* This is easy on a RISC like ARM because the return address is in the link register. 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 NOTA BENE: we do NOT push the return address here, which means it must be dealt with later. */ /* CogARMCompiler>>#genPushRegisterArgsForNumArgs:scratchReg: */ static AbstractInstruction * NoDbgRegParms genPushRegisterArgsForNumArgsscratchReg(AbstractInstruction * self_in_genPushRegisterArgsForNumArgsscratchReg, sqInt numArgs, sqInt ignored) { if (numArgs <= 2 /* numRegArgs */) { assert((numRegArgs()) <= 2); genoperand(PushR, ReceiverResultReg); if (numArgs > 0) { genoperand(PushR, Arg0Reg); if (numArgs > 1) { genoperand(PushR, Arg1Reg); } } } return self_in_genPushRegisterArgsForNumArgsscratchReg; } /* Save the frame and stack pointer registers to the framePointer and stackPointer variables. Used to save the machine code frame for use by the run-time when calling into the CoInterpreter run-time. */ /* CogARMCompiler>>#genSaveStackPointers */ static sqInt NoDbgRegParms genSaveStackPointers(AbstractInstruction * self_in_genSaveStackPointers) { sqInt address; sqInt address1; /* begin MoveR:Aw: */ address = framePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, FPReg, address)); /* begin MoveR:Aw: */ address1 = stackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, SPReg, address1)); return 0; } /* CogARMCompiler>>#genSubstituteReturnAddress: */ static AbstractInstruction * NoDbgRegParms genSubstituteReturnAddress(AbstractInstruction * self_in_genSubstituteReturnAddress, sqInt retpc) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(retpc, genoperandoperand(MoveCwR, retpc, LR)); } /* Answer the instruction immediately preceding followingAddress. */ /* CogARMCompiler>>#instructionBeforeAddress: */ static sqInt NoDbgRegParms instructionBeforeAddress(AbstractInstruction * self_in_instructionBeforeAddress, sqInt followingAddress) { return longAt(followingAddress - 4); } /* is this a BLX <targetReg> instruction? */ /* CogARMCompiler>>#instructionIsBLX: */ static sqInt NoDbgRegParms instructionIsBLX(AbstractInstruction * self_in_instructionIsBLX, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBLX, instr)) && ((instr & 0xFFFFFF0) == 19922736); } /* is this a BL <offset> instruction? */ /* CogARMCompiler>>#instructionIsBL: */ static sqInt NoDbgRegParms instructionIsBL(AbstractInstruction * self_in_instructionIsBL, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBL, instr)) && ((instr & (15U << 24)) == (11U << 24)); } /* is this a BX <targetReg> instruction? */ /* CogARMCompiler>>#instructionIsBX: */ static sqInt NoDbgRegParms instructionIsBX(AbstractInstruction * self_in_instructionIsBX, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsBX, instr)) && ((instr & 0xFFFFFF0) == 19922704); } /* is this a B <offset> instruction? */ /* CogARMCompiler>>#instructionIsB: */ static sqInt NoDbgRegParms instructionIsB(AbstractInstruction * self_in_instructionIsB, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsB, instr)) && ((instr & (15U << 24)) == (10U << 24)); } /* is this a CMP instruction? */ /* CogARMCompiler>>#instructionIsCMP: */ static sqInt NoDbgRegParms instructionIsCMP(AbstractInstruction * self_in_instructionIsCMP, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsCMP, instr)) && (((((usqInt) instr) >> 21) & 0x7F) == CmpOpcode); } /* is this any kind of LDR instruction? c.f. memMxr:reg:base:u:b:l:imm: */ /* CogARMCompiler>>#instructionIsLDR: */ static sqInt NoDbgRegParms instructionIsLDR(AbstractInstruction * self_in_instructionIsLDR, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsLDR, instr)) && (((((usqInt) instr) >> 20) & 197) == 65); } /* is this an ORR instruction? */ /* CogARMCompiler>>#instructionIsOR: */ static sqInt NoDbgRegParms instructionIsOR(AbstractInstruction * self_in_instructionIsOR, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsOR, instr)) && (((((usqInt) instr) >> 21) & 0x7F) == (16 | OrOpcode)); } /* is this a push -str r??, [sp, #-4] - instruction? */ /* CogARMCompiler>>#instructionIsPush: */ static sqInt NoDbgRegParms instructionIsPush(AbstractInstruction * self_in_instructionIsPush, sqInt instr) { return (conditionIsNotNever(self_in_instructionIsPush, instr)) && ((instr & 268374015) == 86835204); } /* Answer the instruction size at pc.Simple on ARM ;-) */ /* CogARMCompiler>>#instructionSizeAt: */ static sqInt NoDbgRegParms instructionSizeAt(AbstractInstruction * self_in_instructionSizeAt, sqInt pc) { return 4; } /* Several of the opcodes are inverses. Answer the inverse for an opcode if it has one. See Table A3-2 in sec A3.4 Data-processing instructions of the AARM. */ /* CogARMCompiler>>#inverseOpcodeFor: */ static sqInt NoDbgRegParms inverseOpcodeFor(AbstractInstruction * self_in_inverseOpcodeFor, sqInt armOpcode) { switch (armOpcode) { case AddOpcode: return SubOpcode; case AndOpcode: return BicOpcode; case BicOpcode: return AndOpcode; case CmpOpcode: return CmpNotOpcode; case MoveOpcode: return MoveNotOpcode; case MoveNotOpcode: return MoveOpcode; case SubOpcode: return AddOpcode; default: error("opcode has no inverse"); return -1; } } /* Assuming mcpc is a send return pc answer if the instruction before it is a call (not a CallFull). */ /* There are two types of calls: BL and/BLX encoding */ /* CogARMCompiler>>#isCallPrecedingReturnPC: */ static sqInt NoDbgRegParms isCallPrecedingReturnPC(AbstractInstruction * self_in_isCallPrecedingReturnPC, sqInt mcpc) { sqInt call; /* begin instructionBeforeAddress: */ call = longAt(mcpc - 4); return (instructionIsBL(self_in_isCallPrecedingReturnPC, call)) || (instructionIsBLX(self_in_isCallPrecedingReturnPC, call)); } /* ARM calls and jumps span +/- 32 mb, more than enough for intra-zone calls and jumps. */ /* CogARMCompiler>>#isInImmediateJumpRange: */ static sqInt NoDbgRegParms isInImmediateJumpRange(AbstractInstruction * self_in_isInImmediateJumpRange, usqIntptr_t operand) { return (((((int) operand)) >= -33554432) && ((((int) operand)) <= 0x1FFFFFC)); } /* CogARMCompiler>>#isJumpAt: */ static sqInt NoDbgRegParms isJumpAt(AbstractInstruction * self_in_isJumpAt, sqInt pc) { int instr; instr = long32At(pc); return (instructionIsB(self_in_isJumpAt, instr)) || (instructionIsBX(self_in_isJumpAt, instr)); } /* add xx, pc, blah or sub xx, pc, blah */ /* CogARMCompiler>>#isPCRelativeValueLoad: */ static sqInt NoDbgRegParms isPCRelativeValueLoad(AbstractInstruction * self_in_isPCRelativeValueLoad, unsigned int instr) { return ((((usqInt) instr) >> 16) == 57999) || ((((usqInt) instr) >> 16) == 57935); } /* Branch/Call ranges. Jump[Cond] can be generated as short as possible. Call/Jump[Cond]Long must be generated in the same number of bytes irrespective of displacement since their targets may be updated, but they need only span 16Mb, the maximum size of the code zone. This allows e.g. ARM to use single-word call and jump instructions for most calls and jumps. CallFull/JumpFull must also be generated in the same number of bytes irrespective of displacement for the same reason, but they must be able to span the full (32-bit or 64-bit) address space because they are used to call code in the C runtime, which may be distant from the code zone */ /* CogARMCompiler>>#jumpLongByteSize */ static sqInt NoDbgRegParms jumpLongByteSize(AbstractInstruction * self_in_jumpLongByteSize) { return 4; } /* CogARMCompiler>>#jumpLongConditionalByteSize */ static sqInt NoDbgRegParms jumpLongConditionalByteSize(AbstractInstruction * self_in_jumpLongConditionalByteSize) { /* begin jumpLongByteSize */ return 4; } /* Answer the target address for the long jump immediately preceding mcpc */ /* CogARMCompiler>>#jumpLongTargetBeforeFollowingAddress: */ static sqInt NoDbgRegParms jumpLongTargetBeforeFollowingAddress(AbstractInstruction * self_in_jumpLongTargetBeforeFollowingAddress, sqInt mcpc) { return callTargetFromReturnAddress(self_in_jumpLongTargetBeforeFollowingAddress, mcpc); } /* CogARMCompiler>>#jumpTargetPCAt: */ static usqInt NoDbgRegParms jumpTargetPCAt(AbstractInstruction * self_in_jumpTargetPCAt, sqInt pc) { int operand; int word; word = long32At(pc); operand = word & 0xFFFFFF; if (operand & 0x800000) { operand -= 0x1000000; } return ((operand * 4) + pc) + 8; } /* LDRB destReg, [baseReg, 'u' immediate12bitValue] u=0 -> - ARM_ARM v7 DDI10406 pp. A8-128-9 Note that this is a very low level interface that does not check the sign of the immediate, nor validity. See for example #concretizeMoveMbrR */ /* CogARMCompiler>>#ldrb:rn:plus:imm: */ static sqInt NoDbgRegParms ldrbrnplusimm(AbstractInstruction * self_in_ldrbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrbrnplusimm, AL, destReg, baseReg, u, 1, 1, immediate12bitValue); } /* LDRB destReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-132-3 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldrb:rn:rm: */ static sqInt NoDbgRegParms ldrbrnrm(AbstractInstruction * self_in_ldrbrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_ldrbrnrm, AL, destReg, baseReg, 1, 1, 1, 0, 1, offsetReg); } /* LDRH destReg, [baseReg, 'u' immediate8bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-152-3 */ /* CogARMCompiler>>#ldrh:rn:plus:imm: */ static sqInt NoDbgRegParms ldrhrnplusimm(AbstractInstruction * self_in_ldrhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue) { return memM16xrregbasepuwloffset(self_in_ldrhrnplusimm, AL, destReg, baseReg, 1, u, 0, 1, immediate8bitValue); } /* LDRH destReg, [baseReg, +offsetReg] - ARM_ARM v7 DDI10406 pp. A8-156-7 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldrh:rn:rm: */ static sqInt NoDbgRegParms ldrhrnrm(AbstractInstruction * self_in_ldrhrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memM16xrregbasepuwlrm(self_in_ldrhrnrm, AL, destReg, baseReg, 1, 1, 0, 1, offsetReg); } /* LDR destReg, [baseReg, +immediate12bitValue] - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#ldr:rn:plusImm: */ static sqInt NoDbgRegParms ldrrnplusImm(AbstractInstruction * self_in_ldrrnplusImm, sqInt destReg, sqInt baseReg, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrrnplusImm, AL, destReg, baseReg, 1, 0, 1, immediate12bitValue); } /* LDR destReg, [baseReg, immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#ldr:rn:plus:imm: */ static sqInt NoDbgRegParms ldrrnplusimm(AbstractInstruction * self_in_ldrrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_ldrrnplusimm, AL, destReg, baseReg, u, 0, 1, immediate12bitValue); } /* LDR destReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-124-5 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#ldr:rn:rm: */ static sqInt NoDbgRegParms ldrrnrm(AbstractInstruction * self_in_ldrrnrm, sqInt destReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_ldrrnrm, AL, destReg, baseReg, 1, 1, 0, 0, 1, offsetReg); } /* Load the operand into the destination register, answering the size of the instructions generated to do so. */ /* CogARMCompiler>>#loadCwInto: */ static usqInt NoDbgRegParms loadCwInto(AbstractInstruction * self_in_loadCwInto, sqInt destReg) { sqInt aWord; sqInt aWord1; sqInt distance; sqInt i; sqInt immediate; sqInt negate; usqInt operand; sqInt rot; sqInt value; operand = ((self_in_loadCwInto->operands))[0]; if ((addressIsInInstructions(((AbstractInstruction *) operand))) || ((((AbstractInstruction *) operand)) == (methodLabel()))) { operand = ((((AbstractInstruction *) operand))->address); } if (((((usqInt)operand)) >= ((methodLabel->address))) && ((((usqInt)operand)) < (youngReferrers()))) { distance = operand - (((self_in_loadCwInto->address)) + 8); /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ value = distance; while (1) { if ((value & 0xFF) == value) { negate = distance != value; /* begin machineCodeAt:put: */ aWord = (negate ? subrnimmror(self_in_loadCwInto, destReg, PC, value, 0) : addrnimmror(self_in_loadCwInto, destReg, PC, value, 0)); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord; return 4; goto l2; } for (i = 2; i <= 30; i += 2) { if ((value & (((0xFFU << i) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i)))) == value) { rot = 32 - i; immediate = (((usqInt) value) >> i) | ((((sqInt)((usqInt)(value) << (32 - i)))) & 0xFFFFFFFFU); negate = distance != value; /* begin machineCodeAt:put: */ aWord = (negate ? subrnimmror(self_in_loadCwInto, destReg, PC, immediate, rot) : addrnimmror(self_in_loadCwInto, destReg, PC, immediate, rot)); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord; return 4; goto l2; } } if (!((value == distance) && (distance != 0))) break; value = -distance; } assert(!((isAnInstruction(self_in_loadCwInto, ((AbstractInstruction *) (((self_in_loadCwInto->operands))[0])))))); l2: /* end rotateable8bitSignedImmediate:ifTrue:ifFalse: */; } /* begin moveCw:intoR: */ assert(addressIsInCurrentCompilation((((self_in_loadCwInto->dependent))->address))); assert((SQABS((((((self_in_loadCwInto->dependent))->address)) - (((self_in_loadCwInto->address)) + 8)))) < (1U << 12)); /* begin machineCodeAt:put: */ aWord1 = ldrrnplusimm(self_in_loadCwInto, destReg, PC, (((((self_in_loadCwInto->dependent))->address)) >= (((self_in_loadCwInto->address)) + 8) ? 1 : 0), SQABS((((((self_in_loadCwInto->dependent))->address)) - (((self_in_loadCwInto->address)) + 8)))); ((self_in_loadCwInto->machineCode))[0 / 4] = aWord1; return ((self_in_loadCwInto->machineCodeSize) = 4); } /* Answer the byte size of a MoveCwR opcode's corresponding machine code when the argument is a PIC. This is for the self-reference at the end of a closed PIC. On ARM this is a single instruction pc-relative register load. */ /* CogARMCompiler>>#loadPICLiteralByteSize */ static sqInt NoDbgRegParms loadPICLiteralByteSize(AbstractInstruction * self_in_loadPICLiteralByteSize) { return 4; } /* Answer the maximum number of bytes of machine code generated for any abstract instruction. e.g. CmpCwR => mov R3, #<addressByte1>, 12 orr R3, R3, #<addressByte2>, 8 orr R3, R3, #<addressByte3>, 4 orr R3, R3, #<addressByte4>, 0 cmp R?, R3 */ /* CogARMCompiler>>#machineCodeBytes */ static sqInt NoDbgRegParms machineCodeBytes(AbstractInstruction * self_in_machineCodeBytes) { return 20; } /* Answer the maximum number of words of machine code generated for any abstract instruction. e.g. CmpCwR => mov R3, #<addressByte1>, 12 orr R3, R3, #<addressByte2>, 8 orr R3, R3, #<addressByte3>, 4 orr R3, R3, #<addressByte4>, 0 cmp R?, R3 */ /* CogARMCompiler>>#machineCodeWords */ static sqInt NoDbgRegParms machineCodeWords(AbstractInstruction * self_in_machineCodeWords) { return 5; } /* build an ARM [base +/- offset8] half-word memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memM16xr:reg:base:p:u:w:l:offset: */ static sqInt NoDbgRegParms memM16xrregbasepuwloffset(AbstractInstruction * self_in_memM16xrregbasepuwloffset, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offset8) { return (((sqInt)((usqInt)(cond) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((1U << 22) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | ((((sqInt)((usqInt)((offset8 & 240)) << 4))) | ((11U << 4) | (offset8 & 15))))))))))); } /* build an ARM [base +/- offsetReg] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memM16xr:reg:base:p:u:w:l:rm: */ static sqInt NoDbgRegParms memM16xrregbasepuwlrm(AbstractInstruction * self_in_memM16xrregbasepuwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)(cond) << 28))) | ((0U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((0U << 22) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | (176 | offsetReg))))))))); } /* build an ARM [base +/- offset] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:imm: */ static sqInt NoDbgRegParms memMxrregbasepubwlimm(AbstractInstruction * self_in_memMxrregbasepubwlimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offset) { return (((sqInt)((usqInt)(cond) << 28))) | ((2U << 25) | ((((sqInt)((usqInt)(postpreoffset) << 24))) | ((((sqInt)((usqInt)(updown) << 23))) | ((((sqInt)((usqInt)(byteword) << 22))) | ((((sqInt)((usqInt)(weirdstuff) << 21))) | ((((sqInt)((usqInt)(loadstore) << 20))) | ((((sqInt)((usqInt)(baseReg) << 16))) | ((((sqInt)((usqInt)(destReg) << 12))) | offset)))))))); } /* build an ARM [base +/- offsetReg lsl #2] memory instruction - see also #memMxr:reg:base:p:u:b:w:l:rm: and keep them correlated properly p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:rmLsl2: */ static sqInt NoDbgRegParms memMxrregbasepubwlrmLsl2(AbstractInstruction * self_in_memMxrregbasepubwlrmLsl2, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((3U << 25) | ((((sqInt)((usqInt)((postpreoffset & 1)) << 24))) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((weirdstuff & 1)) << 21))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (256 | (offsetReg & 15)))))))))); } /* build an ARM [base +/- offsetReg] memory instruction p -> pre-index (1) or post-index (0) the offset. Combines with W to do some odd things. u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) w -> write-back (1) if pre-indexing. l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:p:u:b:w:l:rm: */ static sqInt NoDbgRegParms memMxrregbasepubwlrm(AbstractInstruction * self_in_memMxrregbasepubwlrm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt postpreoffset, sqInt updown, sqInt byteword, sqInt weirdstuff, sqInt loadstore, sqInt offsetReg) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((3U << 25) | ((((sqInt)((usqInt)((postpreoffset & 1)) << 24))) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((weirdstuff & 1)) << 21))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (offsetReg & 15))))))))); } /* This is the lowest level build of an ARM [base +/- immediate 12bit offset] memory instruction u -> up (1) or down (0) ie + or - for the offset b -> byte(1) or word (0) l -> load (1) or store (0) */ /* CogARMCompiler>>#memMxr:reg:base:u:b:l:imm: */ static sqInt NoDbgRegParms memMxrregbaseublimm(AbstractInstruction * self_in_memMxrregbaseublimm, sqInt cond, sqInt destReg, sqInt baseReg, sqInt updown, sqInt byteword, sqInt loadstore, sqInt immediate12bitValue) { return (((sqInt)((usqInt)((cond & 15)) << 28))) | ((5U << 24) | ((((sqInt)((usqInt)((updown & 1)) << 23))) | ((((sqInt)((usqInt)((byteword & 1)) << 22))) | ((((sqInt)((usqInt)((loadstore & 1)) << 20))) | ((((sqInt)((usqInt)((baseReg & 15)) << 16))) | ((((sqInt)((usqInt)((destReg & 15)) << 12))) | (immediate12bitValue & 0xFFF))))))); } /* MOVS destReg, srcReg - ARM_ARM v7 DDI10406 pp. A8-196-7 */ /* CogARMCompiler>>#movs:rn: */ static sqInt NoDbgRegParms movsrn(AbstractInstruction * self_in_movsrn, sqInt destReg, sqInt srcReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (1U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (srcReg & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. MOV destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-194-5 */ /* CogARMCompiler>>#mov:imm:ror: */ static sqInt NoDbgRegParms movimmror(AbstractInstruction * self_in_movimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* MOV destReg, srcReg - ARM_ARM v7 DDI10406 pp. A8-196-7 */ /* CogARMCompiler>>#mov:rn: */ static sqInt NoDbgRegParms movrn(AbstractInstruction * self_in_movrn, sqInt destReg, sqInt srcReg) { return (((((int)((usqInt)(AL) << 28))) | ((0U << 25) | ((((int)((usqInt)(MoveOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (srcReg & 0xFFF); } /* Generate an MSR CPSR_f, #flags instruction. Note that a) CPSR_f is equivalent to APSR_nzcvq (ARM ARM DDI0406A p A8-209 & A2-14) b) We only have business with the NZCV flags so the generated instruction shifts the flags value <<28 - which is a ROR 4 */ /* CogARMCompiler>>#msr: */ static sqInt NoDbgRegParms msr(AbstractInstruction * self_in_msr, sqInt flags) { return (321449984 + (2U << 8)) + (flags & 15); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. MVN destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-214-5 */ /* CogARMCompiler>>#mvn:imm:ror: */ static sqInt NoDbgRegParms mvnimmror(AbstractInstruction * self_in_mvnimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(MoveNotOpcode) << 21))) | (0U << 20)))) | ((0U << 16) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* CogARMCompiler>>#numIntRegArgs */ static sqInt NoDbgRegParms numIntRegArgs(AbstractInstruction * self_in_numIntRegArgs) { return 4; } /* Remember the ROR is doubled by the cpu so use 30>>1 etc. ORR destReg, #immediate8BitValue ROR rot - ARM_ARM v7 DDI10406 pp. A8-228-9 */ /* CogARMCompiler>>#orr:imm:ror: */ static sqInt NoDbgRegParms orrimmror(AbstractInstruction * self_in_orrimmror, sqInt destReg, sqInt immediate8bitValue, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(OrOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(destReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate8bitValue) & 0xFFF); } /* CogARMCompiler>>#padIfPossibleWithStopsFrom:to: */ static AbstractInstruction * NoDbgRegParms padIfPossibleWithStopsFromto(AbstractInstruction * self_in_padIfPossibleWithStopsFromto, sqInt startAddr, sqInt endAddr) { sqInt nullBytes; sqInt p; nullBytes = ((endAddr - startAddr) + 1) % 4; stopsFromto(self_in_padIfPossibleWithStopsFromto, startAddr, endAddr - nullBytes); for (p = ((endAddr - nullBytes) + 1); p <= endAddr; p += 1) { byteAtput(p, 0xFF); } return self_in_padIfPossibleWithStopsFromto; } /* pop word off TOS LDR srcReg, [sp] #4 - ARM_ARM v7 DDI10406 pp. A8-120-1 */ /* CogARMCompiler>>#popR: */ static sqInt NoDbgRegParms popR(AbstractInstruction * self_in_popR, sqInt dstReg) { return memMxrregbasepubwlimm(self_in_popR, AL, dstReg, SP, 0, 1, 0, 0, 1, 4); } /* CogARMCompiler>>#pushLinkRegisterByteSize */ static sqInt NoDbgRegParms pushLinkRegisterByteSize(AbstractInstruction * self_in_pushLinkRegisterByteSize) { return 4; } /* push word to TOS STR srcReg, [sp, #-4]! - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#pushR: */ static sqInt NoDbgRegParms pushR(AbstractInstruction * self_in_pushR, sqInt srcReg) { return memMxrregbasepubwlimm(self_in_pushR, AL, srcReg, SP, 1, 0, 0, 1, 0, 4); } /* CogARMCompiler>>#relocateCallBeforeReturnPC:by: */ static AbstractInstruction * NoDbgRegParms relocateCallBeforeReturnPCby(AbstractInstruction * self_in_relocateCallBeforeReturnPCby, sqInt retpc, sqInt delta) { sqInt distanceDiv4; sqInt instr; assert((delta % 4) == 0); if (delta != 0) { /* begin instructionBeforeAddress: */ instr = longAt(retpc - 4); assert((instructionIsB(self_in_relocateCallBeforeReturnPCby, instr)) || (instructionIsBL(self_in_relocateCallBeforeReturnPCby, instr))); distanceDiv4 = instr & 0xFFFFFF; distanceDiv4 += delta / 4; longAtput(retpc - 4, (instr & 0xFF000000U) | (distanceDiv4 & 0xFFFFFF)); } return self_in_relocateCallBeforeReturnPCby; } /* Rewrite a call instruction to call a different target. This variant is used to link PICs in ceSendMiss et al,. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteCallAt:target: */ static sqInt NoDbgRegParms rewriteCallAttarget(AbstractInstruction * self_in_rewriteCallAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { return rewriteTransferAttarget(self_in_rewriteCallAttarget, callSiteReturnAddress, callTargetAddress); } /* Rewrite a callFull instruction to jump to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'blx ip' instruction for the actual call. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteCallFullAt:target: */ static sqInt NoDbgRegParms rewriteCallFullAttarget(AbstractInstruction * self_in_rewriteCallFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteFullTransferAttargetexpectedInstruction(self_in_rewriteCallFullAttarget, callSiteReturnAddress, callTargetAddress, 3778019132U); } /* Rewrite a full jump instruction to jump to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'bx ip' instruction for the actual jump. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteJumpFullAt:target: */ static sqInt NoDbgRegParms rewriteJumpFullAttarget(AbstractInstruction * self_in_rewriteJumpFullAttarget, sqInt callSiteReturnAddress, sqInt callTargetAddress) { return rewriteFullTransferAttargetexpectedInstruction(self_in_rewriteJumpFullAttarget, callSiteReturnAddress, callTargetAddress, 3778019100U); } /* Rewrite a jump instruction to call a different target. This variant is used to reset the jumps in the prototype CPIC to suit each use,. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogARMCompiler>>#rewriteJumpLongAt:target: */ static sqInt NoDbgRegParms rewriteJumpLongAttarget(AbstractInstruction * self_in_rewriteJumpLongAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { return rewriteTransferAttarget(self_in_rewriteJumpLongAttarget, callSiteReturnAddress, callTargetAddress); } /* Rewrite a call/jump instruction to call a different target. This variant is used to link PICs in ceSendMiss et al, and to rewrite call/jumps in CPICs. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* for debug - [cogit disassembleFrom: callSiteReturnAddress - 10 to: callSiteReturnAddress - 1]. */ /* CogARMCompiler>>#rewriteTransferAt:target: */ static sqInt NoDbgRegParms rewriteTransferAttarget(AbstractInstruction * self_in_rewriteTransferAttarget, usqInt callSiteReturnAddress, usqInt callTargetAddress) { usqInt callDistance; sqInt instr; if (!(callTargetAddress >= (minCallAddress()))) { error("linking callsite to invalid address"); } /* pc offset */ /* return offset */ callDistance = ((usqInt) (callTargetAddress - ((callSiteReturnAddress + 8) - 4))); assert(isInImmediateJumpRange(self_in_rewriteTransferAttarget, callDistance)); /* begin instructionBeforeAddress: */ instr = longAt(callSiteReturnAddress - 4); assert((instructionIsB(self_in_rewriteTransferAttarget, instr)) || (instructionIsBL(self_in_rewriteTransferAttarget, instr))); longAtput(callSiteReturnAddress - 4, (instr & 0xFF000000U) | ((callDistance / 4) & 0xFFFFFF)); assert((callTargetFromReturnAddress(self_in_rewriteTransferAttarget, callSiteReturnAddress)) == callTargetAddress); return 4; } /* to save Slang from having to be a real compiler (it can't inline switches that return) */ /* Answer if the receiver's opcode sets the condition codes correctly for the given conditional jump opcode. ARM has to check carefully since the V flag is not affected by non-comparison instructions */ /* CogARMCompiler>>#setsConditionCodesFor: */ static sqInt NoDbgRegParms setsConditionCodesFor(AbstractInstruction * self_in_setsConditionCodesFor, sqInt aConditionalJumpOpcode) { switch ((self_in_setsConditionCodesFor->opcode)) { case ArithmeticShiftRightCqR: case ArithmeticShiftRightRR: case LogicalShiftLeftCqR: case LogicalShiftLeftRR: return shiftSetsConditionCodesFor(self_in_setsConditionCodesFor, aConditionalJumpOpcode); case XorRR: return 1; default: haltmsg("unhandled opcode in setsConditionCodesFor:"); return 0; } } /* check what flags the opcdoe needs setting - ARM doesn't set V when simply MOVing */ /* CogARMCompiler>>#shiftSetsConditionCodesFor: */ static sqInt NoDbgRegParms shiftSetsConditionCodesFor(AbstractInstruction * self_in_shiftSetsConditionCodesFor, sqInt aConditionalJumpOpcode) { switch (aConditionalJumpOpcode) { case JumpNegative: case JumpZero: case JumpLess: return 1; default: haltmsg("unhandled opcode in setsConditionCodesFor:"); return 0; } } /* Return a minimum amount of headroom for each stack page (in bytes). In a JIT the stack has to have room for interrupt handlers which will run on the stack. According to ARM architecture v5 reference manual chapter A2.6, the basic interrupt procedure does not push anything onto the stack. It uses SPSR_err and R14_err to preserve state. Afterwards, it calls an interrupt procedure. So leave some room. */ /* CogARMCompiler>>#stackPageInterruptHeadroomBytes */ static sqInt NoDbgRegParms stackPageInterruptHeadroomBytes(AbstractInstruction * self_in_stackPageInterruptHeadroomBytes) { return 128; } /* CogARMCompiler>>#stopsFrom:to: */ static AbstractInstruction * NoDbgRegParms stopsFromto(AbstractInstruction * self_in_stopsFromto, sqInt startAddr, sqInt endAddr) { sqInt addr; assert((((endAddr - startAddr) + 1) % 4) == 0); for (addr = startAddr; addr <= endAddr; addr += 4) { longAtput(addr, (((int)((usqInt)(AL) << 28))) | ((66U << 20) | (7U << 4))); } return self_in_stopsFromto; } /* STRB destReg, [baseReg, 'u' immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-388-9 */ /* CogARMCompiler>>#strb:rn:plus:imm: */ static sqInt NoDbgRegParms strbrnplusimm(AbstractInstruction * self_in_strbrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strbrnplusimm, AL, destReg, baseReg, u, 1, 0, immediate12bitValue); } /* STRB srcReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-390-1 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#strb:rn:rm: */ static sqInt NoDbgRegParms strbrnrm(AbstractInstruction * self_in_strbrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_strbrnrm, AL, srcReg, baseReg, 1, 1, 1, 0, 0, offsetReg); } /* STRH destReg, [baseReg, 'u' immediate8bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-408-9 */ /* CogARMCompiler>>#strh:rn:plus:imm: */ static sqInt NoDbgRegParms strhrnplusimm(AbstractInstruction * self_in_strhrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate8bitValue) { return memM16xrregbasepuwloffset(self_in_strhrnplusimm, AL, destReg, baseReg, 1, u, 0, 0, immediate8bitValue); } /* STRH srcReg, [baseReg, +offsetReg] - ARM_ARM v7 DDI10406 pp. A8-410-1 */ /* CogARMCompiler>>#strh:rn:rm: */ static sqInt NoDbgRegParms strhrnrm(AbstractInstruction * self_in_strhrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memM16xrregbasepuwlrm(self_in_strhrnrm, AL, srcReg, baseReg, 1, 1, 0, 0, offsetReg); } /* STR srcReg, [baseReg, +immediate12bitValue] - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#str:rn:plusImm: */ static sqInt NoDbgRegParms strrnplusImm(AbstractInstruction * self_in_strrnplusImm, sqInt srcReg, sqInt baseReg, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strrnplusImm, AL, srcReg, baseReg, 1, 0, 0, immediate12bitValue); } /* STR destReg, [baseReg, 'u' immediate12bitValue] u=0 -> subtract imm; =1 -> add imm - ARM_ARM v7 DDI10406 pp. A8-382-3 */ /* CogARMCompiler>>#str:rn:plus:imm: */ static sqInt NoDbgRegParms strrnplusimm(AbstractInstruction * self_in_strrnplusimm, sqInt destReg, sqInt baseReg, sqInt u, sqInt immediate12bitValue) { return memMxrregbaseublimm(self_in_strrnplusimm, AL, destReg, baseReg, u, 0, 0, immediate12bitValue); } /* STR srcReg, [baseReg, + offsetReg] - ARM_ARM v7 DDI10406 pp. A8-384-5 The contents of offsetReg are assumed to be correctly signed */ /* CogARMCompiler>>#str:rn:rm: */ static sqInt NoDbgRegParms strrnrm(AbstractInstruction * self_in_strrnrm, sqInt srcReg, sqInt baseReg, sqInt offsetReg) { return memMxrregbasepubwlrm(self_in_strrnrm, AL, srcReg, baseReg, 1, 1, 0, 0, 0, offsetReg); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc SUBS destReg, srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-418-9 */ /* CogARMCompiler>>#subs:rn:imm:ror: */ static sqInt NoDbgRegParms subsrnimmror(AbstractInstruction * self_in_subsrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc SUB destReg, srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-418-9 */ /* CogARMCompiler>>#sub:rn:imm:ror: */ static sqInt NoDbgRegParms subrnimmror(AbstractInstruction * self_in_subrnimmror, sqInt destReg, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(SubOpcode) << 21))) | (0U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (((sqInt)((usqInt)(destReg) << 12))))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Remember the ROR is doubled by the cpu so use 30>>1 etc */ /* also note that TST has no destReg TST srcReg, #immediate ROR rot - ARM_ARM v7 DDI10406 pp. A8-452-3 */ /* CogARMCompiler>>#tst:rn:imm:ror: */ static sqInt NoDbgRegParms tstrnimmror(AbstractInstruction * self_in_tstrnimmror, sqInt ignored, sqInt srcReg, sqInt immediate, sqInt rot) { return (((((int)((usqInt)(AL) << 28))) | ((1U << 25) | ((((int)((usqInt)(TstOpcode) << 21))) | (1U << 20)))) | ((((sqInt)((usqInt)(srcReg) << 16))) | (0U << 12))) | (((((sqInt)((usqInt)((((usqInt) rot) >> 1)) << 8))) | immediate) & 0xFFF); } /* Answer if Call and JumpLong are relative and hence need to take the caller's relocation delta into account during code compaction, rather than just the callee's delta. */ /* CogARMCompiler>>#zoneCallsAreRelative */ static sqInt NoDbgRegParms zoneCallsAreRelative(AbstractInstruction * self_in_zoneCallsAreRelative) { return 1; } /* CogBlockMethod>>#cmHomeMethod */ static CogMethod * NoDbgRegParms cmHomeMethod(CogBlockMethod * self_in_cmHomeMethod) { return ((self_in_cmHomeMethod->cpicHasMNUCaseOrCMIsFullBlock) ? ((CogMethod *) self_in_cmHomeMethod) : ((CogMethod *) ((((usqInt)self_in_cmHomeMethod)) - ((self_in_cmHomeMethod->homeOffset))))); } /* CogBytecodeDescriptor>>#isBranch */ static sqInt NoDbgRegParms isBranch(BytecodeDescriptor * self_in_isBranch) { return (((self_in_isBranch->spanFunction)) != null) && (!((self_in_isBranch->isBlockCreation))); } /* Cogit>>#AddCq:R: */ static AbstractInstruction * NoDbgRegParms gAddCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* Cogit>>#AndCq:R: */ static AbstractInstruction * NoDbgRegParms gAndCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* Cogit>>#AndCq:R:R: */ static AbstractInstruction * NoDbgRegParms gAndCqRR(sqInt quickConstant, sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *first; /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(AndCqRR, quickConstant, srcReg, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } return anInstruction2; if (srcReg == destReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } first = genoperandoperand(MoveRR, srcReg, destReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return first; } /* Cogit>>#abortOffset */ sqInt abortOffset(void) { return missOffset; } /* Cogit>>#addCleanBlockStarts */ static void addCleanBlockStarts(void) { sqInt i; sqInt iLimiT; sqInt lit; sqInt startPCOrNil; for (i = 1, iLimiT = (literalCountOf(methodObj)); i <= iLimiT; i += 1) { lit = fetchPointerofObject(i, methodObj); startPCOrNil = startPCOrNilOfLiteralin(lit, methodObj); if (!(startPCOrNil == null)) { maxLitIndex = ((maxLitIndex < i) ? i : maxLitIndex); addBlockStartAtnumArgsnumCopiedspan(startPCOrNil - 1, argumentCountOfClosure(lit), copiedValueCountOfClosure(lit), spanForCleanBlockStartingAt(startPCOrNil - 1)); } } } /* Perform an integrity/leak check using the heapMap. Set a bit at each cog method's header. */ /* Cogit>>#addCogMethodsToHeapMap */ void addCogMethodsToHeapMap(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { heapMapAtWordPut(cogMethod, 1); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* Cogit>>#addressIsInCurrentCompilation: */ static sqInt NoDbgRegParms addressIsInCurrentCompilation(sqInt address) { return ((((usqInt)address)) >= ((methodLabel->address))) && ((((usqInt)address)) < (youngReferrers())); } /* Cogit>>#addressIsInFixups: */ static sqInt NoDbgRegParms addressIsInFixups(BytecodeFixup *address) { return (BytecodeFixup *)address >= fixups && (BytecodeFixup *)address < (fixups + numAbstractOpcodes); } /* Cogit>>#addressIsInInstructions: */ static sqInt NoDbgRegParms addressIsInInstructions(AbstractInstruction *address) { return !((usqInt)(address) & BytesPerWord-1) \ && (address) >= &abstractOpcodes[0] \ && (address) < &abstractOpcodes[opcodeIndex]; } /* calculate the end of the n'th case statement - which is complicated because we have case 1 right at the top of our CPIC and then build up from the last one. Yes I know this sounds strange, but trust me - I'm an Engineer, we do things backwards all the emit */ /* Cogit>>#addressOfEndOfCase:inCPIC: */ static sqInt NoDbgRegParms addressOfEndOfCaseinCPIC(sqInt n, CogMethod *cPIC) { assert((n >= 1) && (n <= MaxCPICCases)); return (n == 1 ? (((sqInt)cPIC)) + firstCPICCaseOffset : ((((sqInt)cPIC)) + firstCPICCaseOffset) + (((MaxCPICCases + 1) - n) * cPICCaseSize)); } /* Cogit>>#alignUptoRoutineBoundary: */ static sqInt NoDbgRegParms alignUptoRoutineBoundary(sqInt anAddress) { return (((anAddress + 7) | 7) - 7); } /* Check that all methods have valid selectors, and that all linked sends are to valid targets and have valid cache tags */ /* Cogit>>#allMachineCodeObjectReferencesValid */ static sqInt allMachineCodeObjectReferencesValid(void) { CogMethod *cogMethod; sqInt ok; ok = 1; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if (!(asserta(checkValidOopReference((cogMethod->selector))))) { ok = 0; } if (!(asserta((cogMethodDoesntLookKosher(cogMethod)) == 0))) { ok = 0; } } if ((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)) { if (!(asserta((mapForperformUntilarg(cogMethod, checkIfValidOopRefAndTargetpccogMethod, ((sqInt)cogMethod))) == 0))) { ok = 0; } } if (((cogMethod->cmType)) == CMClosedPIC) { if (!(asserta(noTargetsFreeInClosedPIC(cogMethod)))) { ok = 0; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return ok; } /* Cogit>>#allMethodsHaveCorrectHeader */ static sqInt allMethodsHaveCorrectHeader(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { if (!(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod()))) { return 0; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return 1; } /* Cogit>>#annotateAbsolutePCRef: */ static AbstractInstruction * NoDbgRegParms annotateAbsolutePCRef(AbstractInstruction *abstractInstruction) { (abstractInstruction->annotation = IsAbsPCReference); return abstractInstruction; } /* Cogit>>#annotateBytecode: */ static AbstractInstruction * NoDbgRegParms annotateBytecode(AbstractInstruction *abstractInstruction) { (abstractInstruction->annotation = HasBytecodePC); return abstractInstruction; } /* Cogit>>#annotate:objRef: */ static AbstractInstruction * NoDbgRegParms annotateobjRef(AbstractInstruction *abstractInstruction, sqInt anOop) { if (shouldAnnotateObjectReference(anOop)) { if (isYoungObject(anOop)) { hasYoungReferent = 1; } (abstractInstruction->annotation = IsObjectReference); } return abstractInstruction; } /* Cogit>>#assertSaneJumpTarget: */ static void NoDbgRegParms assertSaneJumpTarget(AbstractInstruction *jumpTarget) { assert((closedPICSize == null) || ((openPICSize == null) || ((addressIsInInstructions(jumpTarget)) || ((((((usqInt)jumpTarget)) >= codeBase) && ((((usqInt)jumpTarget)) <= ((((sqInt)(limitZony()))) + (((closedPICSize < openPICSize) ? openPICSize : closedPICSize))))))))); } /* Evaluate binaryFunction with the block start mcpc and supplied arg for each entry in the block dispatch. If the function answers non-zero answer the value it answered. Used to update back-references to the home method in compaction. */ /* Cogit>>#blockDispatchTargetsFor:perform:arg: */ static sqInt NoDbgRegParms blockDispatchTargetsForperformarg(CogMethod *cogMethod, usqInt (*binaryFunction)(sqInt mcpc, sqInt arg), sqInt arg) { sqInt blockEntry; usqInt end; sqInt pc; sqInt result; usqInt targetpc; if (((cogMethod->blockEntryOffset)) == 0) { return null; } blockEntry = ((cogMethod->blockEntryOffset)) + (((sqInt)cogMethod)); pc = blockEntry; end = (mapEndFor(cogMethod)) - 1; while (pc < end) { if (isJumpAt(backEnd, pc)) { targetpc = jumpTargetPCAt(backEnd, pc); if (targetpc < blockEntry) { result = binaryFunction(targetpc, arg); if (result != 0) { return result; } } } pc += 4 /* instructionSizeAt: */; } return 0; } /* Answer the zero-relative bytecode pc matching the machine code pc argument in cogMethod, given the start of the bytecodes for cogMethod's block or method object. */ /* Cogit>>#bytecodePCFor:startBcpc:in: */ sqInt bytecodePCForstartBcpcin(sqInt mcpc, sqInt startbcpc, CogBlockMethod *cogMethod) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc1; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt targetPC; latestContinuation = 0; /* begin mapFor:bcpc:performUntil:arg: */ assert(((cogMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc1 = (((usqInt)cogMethod)) + ((cogMethod->stackCheckOffset)); result = findIsBackwardBranchMcpcBcpcMatchingMcpc(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc1)), startbcpc, (((void *)mcpc))); if (result != 0) { return result; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogMethod->startpc))); homeMethod = cmHomeMethod(cogMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc1 += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { return 0; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { return 0; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = findIsBackwardBranchMcpcBcpcMatchingMcpc(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc1)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)mcpc))); if (result != 0) { return result; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc1 += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* Cogit>>#CallFullRT:registersToBeSavedMask: */ static AbstractInstruction * NoDbgRegParms CallFullRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved) { sqInt callerSavedRegsToBeSaved; AbstractInstruction *lastInst; callerSavedRegsToBeSaved = CallerSavedRegisterMask & registersToBeSaved; /* begin genPushRegisterMask: */ if (callerSavedRegsToBeSaved == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, callerSavedRegsToBeSaved); } /* begin gen:literal: */ lastInst = checkLiteralforInstruction(callTarget, genoperand(CallFull, callTarget)); /* begin genPopRegisterMask: */ return (callerSavedRegsToBeSaved == 0 ? genoperandoperand(Label, (labelCounter += 1), bytecodePC) : genoperand(PopLDM, callerSavedRegsToBeSaved)); } /* Cogit>>#CallRT:registersToBeSavedMask: */ static AbstractInstruction * NoDbgRegParms CallRTregistersToBeSavedMask(sqInt callTarget, sqInt registersToBeSaved) { AbstractInstruction *abstractInstruction; sqInt callerSavedRegsToBeSaved; AbstractInstruction *lastInst; callerSavedRegsToBeSaved = CallerSavedRegisterMask & registersToBeSaved; /* begin genPushRegisterMask: */ if (callerSavedRegsToBeSaved == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, callerSavedRegsToBeSaved); } /* begin CallRT: */ abstractInstruction = genoperand(Call, callTarget); (abstractInstruction->annotation = IsRelativeCall); lastInst = abstractInstruction; /* begin genPopRegisterMask: */ return (callerSavedRegsToBeSaved == 0 ? genoperandoperand(Label, (labelCounter += 1), bytecodePC) : genoperand(PopLDM, callerSavedRegsToBeSaved)); } /* Cogit>>#Call: */ static AbstractInstruction * NoDbgRegParms gCall(sqInt callTarget) { return genoperand(Call, callTarget); } /* Cogit>>#CmpCq:R: */ static AbstractInstruction * NoDbgRegParms gCmpCqR(sqInt quickConstant, sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } return anInstruction; } /* This is a static version of ceCallCogCodePopReceiverReg for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#callCogCodePopReceiver */ void callCogCodePopReceiver(void) { realCECallCogCodePopReceiverReg(); error("what??"); } /* This is a static version of ceCallCogCodePopReceiverAndClassRegs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#callCogCodePopReceiverAndClassRegs */ void callCogCodePopReceiverAndClassRegs(void) { realCECallCogCodePopReceiverAndClassRegs(); } /* Code entry closed PIC miss. A send has fallen through a closed (finite) polymorphic inline cache. Either extend it or patch the send site to an open PIC. The stack looks like: receiver args sp=> sender return address */ /* Cogit>>#ceCPICMiss:receiver: */ sqInt ceCPICMissreceiver(CogMethod *cPIC, sqInt receiver) { sqInt cacheTag; sqInt errorSelectorOrNil; sqInt methodOrSelectorIndex; sqInt newTargetMethodOrNil; sqInt outerReturn; sqInt result; sqInt selector; if (isOopForwarded(receiver)) { return ceSendFromInLineCacheMiss(cPIC); } outerReturn = stackTop(); assert(!(((inlineCacheTagAt(backEnd, outerReturn)) == (picAbortDiscriminatorValue())))); if (((cPIC->cPICNumCases)) < MaxCPICCases) { /* begin lookup:for:methodAndErrorSelectorInto: */ selector = (cPIC->selector); methodOrSelectorIndex = lookupOrdinaryreceiver(selector, receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { if (!(isOopCompiledMethod(methodOrSelectorIndex))) { newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorCannotInterpret; goto l1; } if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, selector); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = null; goto l1; } if (methodOrSelectorIndex == SelectorDoesNotUnderstand) { methodOrSelectorIndex = lookupMNUreceiver(splObj(SelectorDoesNotUnderstand), receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { assert(isOopCompiledMethod(methodOrSelectorIndex)); if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, splObj(SelectorDoesNotUnderstand)); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = methodOrSelectorIndex; l1: /* end lookup:for:methodAndErrorSelectorInto: */; } else { newTargetMethodOrNil = (errorSelectorOrNil = null); } assert(outerReturn == (stackTop())); cacheTag = inlineCacheTagForInstance(receiver); if ((((cPIC->cPICNumCases)) >= MaxCPICCases) || (((errorSelectorOrNil != null) && (errorSelectorOrNil != SelectorDoesNotUnderstand)) || ((newTargetMethodOrNil == null) || (isYoung(newTargetMethodOrNil))))) { result = patchToOpenPICFornumArgsreceiver((cPIC->selector), (cPIC->cmNumArgs), receiver); assert(!result); return ceSendFromInLineCacheMiss(cPIC); } cogExtendPICCaseNMethodtagisMNUCase(cPIC, newTargetMethodOrNil, cacheTag, errorSelectorOrNil == SelectorDoesNotUnderstand); executeCogPICfromLinkedSendWithReceiverandCacheTag(cPIC, receiver, longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))); return null; } /* Cogit>>#ceFree: */ void ceFree(void *pointer) { free(pointer); } /* Cogit>>#ceMalloc: */ void* ceMalloc(size_t size) { return malloc(size); } /* An in-line cache check in a method has failed. The failing entry check has jumped to the ceMethodAbort abort call at the start of the method which has called this routine. If possible allocate a closed PIC for the current and existing classes. The stack looks like: receiver args sender return address sp=> ceMethodAbort call return address So we can find the method that did the failing entry check at ceMethodAbort call return address - missOffset and we can find the send site from the outer return address. */ /* Cogit>>#ceSICMiss: */ sqInt ceSICMiss(sqInt receiver) { sqInt cacheTag; sqInt entryPoint; sqInt errorSelectorOrNil; sqInt extent; usqInt innerReturn; sqInt methodOrSelectorIndex; sqInt newTargetMethodOrNil; usqInt outerReturn; CogMethod *pic; sqInt result; sqInt selector; CogMethod *targetMethod; /* Whether we can relink to a PIC or not we need to pop off the inner return and identify the target method. */ innerReturn = ((usqInt)(popStack())); targetMethod = ((CogMethod *) (innerReturn - missOffset)); if (isOopForwarded(receiver)) { return ceSendFromInLineCacheMiss(targetMethod); } outerReturn = ((usqInt)(stackTop())); assert(((outerReturn >= methodZoneBase) && (outerReturn <= (freeStart())))); entryPoint = callTargetFromReturnAddress(backEnd, outerReturn); assert(((targetMethod->selector)) != (nilObject())); assert(((((sqInt)targetMethod)) + cmEntryOffset) == entryPoint); /* begin lookup:for:methodAndErrorSelectorInto: */ selector = (targetMethod->selector); methodOrSelectorIndex = lookupOrdinaryreceiver(selector, receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { if (!(isOopCompiledMethod(methodOrSelectorIndex))) { newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorCannotInterpret; goto l1; } if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, selector); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = null; goto l1; } if (methodOrSelectorIndex == SelectorDoesNotUnderstand) { methodOrSelectorIndex = lookupMNUreceiver(splObj(SelectorDoesNotUnderstand), receiver); if ((((usqInt)methodOrSelectorIndex)) > (maxLookupNoMNUErrorCode())) { assert(isOopCompiledMethod(methodOrSelectorIndex)); if ((!(methodHasCogMethod(methodOrSelectorIndex))) && (methodShouldBeCogged(methodOrSelectorIndex))) { /* We assume cog:selector: will *not* reclaim the method zone */ cogselector(methodOrSelectorIndex, splObj(SelectorDoesNotUnderstand)); } newTargetMethodOrNil = methodOrSelectorIndex; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = SelectorDoesNotUnderstand; goto l1; } newTargetMethodOrNil = null; errorSelectorOrNil = methodOrSelectorIndex; l1: /* end lookup:for:methodAndErrorSelectorInto: */; assert(outerReturn == (stackTop())); cacheTag = inlineCacheTagForInstance(receiver); if (((errorSelectorOrNil != null) && (errorSelectorOrNil != SelectorDoesNotUnderstand)) || (((longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))) == 0 /* picAbortDiscriminatorValue */) || ((newTargetMethodOrNil == null) || (isYoung(newTargetMethodOrNil))))) { result = patchToOpenPICFornumArgsreceiver((targetMethod->selector), (targetMethod->cmNumArgs), receiver); assert(!result); return ceSendFromInLineCacheMiss(targetMethod); } pic = openPICWithSelector((targetMethod->selector)); if ((pic == null) || (!1)) { /* otherwise attempt to create a closed PIC for the two cases. */ pic = cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase((targetMethod->selector), (targetMethod->cmNumArgs), targetMethod, newTargetMethodOrNil, cacheTag, errorSelectorOrNil == SelectorDoesNotUnderstand); if ((((((sqInt)pic)) >= MaxNegativeErrorCode) && ((((sqInt)pic)) <= -1))) { /* For some reason the PIC couldn't be generated, most likely a lack of code memory. Continue as if this is an unlinked send. */ if ((((sqInt)pic)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return ceSendFromInLineCacheMiss(targetMethod); } flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); } extent = (((pic->cmType)) == CMOpenPIC ? rewriteInlineCacheAttagtarget(backEnd, outerReturn, inlineCacheValueForSelectorinat((targetMethod->selector), mframeHomeMethodExport(), outerReturn), (((sqInt)pic)) + cmEntryOffset) : rewriteCallAttarget(backEnd, outerReturn, (((sqInt)pic)) + cmEntryOffset)); flushICacheFromto(processor, (((usqInt)outerReturn)) - extent, ((usqInt)outerReturn)); executeCogPICfromLinkedSendWithReceiverandCacheTag(pic, receiver, longAt(pcRelativeAddressAt(backEnd, ((usqInt)(outerReturn - 8))))); return null; } /* Cogit>>#checkAssertsEnabledInCogit */ void checkAssertsEnabledInCogit(void) { sqInt assertsAreEnabledInCogit; assertsAreEnabledInCogit = 0; assert(assertsAreEnabledInCogit); } /* Check for a valid object reference, if any, at a map entry. Answer a code unique to each error for debugging. */ /* Cogit>>#checkIfValidOopRefAndTarget:pc:cogMethod: */ static sqInt NoDbgRegParms checkIfValidOopRefAndTargetpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt entryPoint; sqInt entryPoint1; sqInt literal; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj; CogMethod *targetMethod1; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (!(asserta(checkValidOopReference(literal)))) { return 1; } if ((couldBeObject(literal)) && (isReallyYoungObject(literal))) { if (!(asserta(((((CogMethod *) cogMethod))->cmRefersToYoung)))) { return 2; } } } if (annotation >= IsSendCall) { if (!(asserta((((((CogMethod *) cogMethod))->cmType)) == CMMethod))) { return 3; } /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj = entryPointTagIsSelector(entryPoint1); entryPoint = entryPoint1; if (tagCouldBeObj) { if (couldBeObject(cacheTag1)) { if (!(asserta(checkValidOopReference(cacheTag1)))) { return 4; } } else { if (!(asserta(validInlineCacheTag(cacheTag1)))) { return 5; } } if ((couldBeObject(cacheTag1)) && (isReallyYoungObject(cacheTag1))) { if (!(asserta(((((CogMethod *) cogMethod))->cmRefersToYoung)))) { return 6; } } } else { if (!(asserta(validInlineCacheTag(cacheTag1)))) { return 9; } } if (entryPoint > methodZoneBase) { /* It's a linked send; find which kind. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (!(asserta((((targetMethod1->cmType)) == CMMethod) || ((((targetMethod1->cmType)) == CMClosedPIC) || (((targetMethod1->cmType)) == CMOpenPIC))))) { return 10; } } } return 0; } /* Check for a valid object reference, if any, at a map entry. Answer a code unique to each error for debugging. */ /* Cogit>>#checkIfValidOopRef:pc:cogMethod: */ static sqInt NoDbgRegParms checkIfValidOopRefpccogMethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt entryPoint; sqInt literal; sqInt offset; sqInt offset1; sqInt selectorOrCacheTag; sqInt *sendTable; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (!(checkValidOopReference(literal))) { print("object ref leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint <= methodZoneBase) { offset = entryPoint; } else { /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable = superSendTrampolines; } } } offset = offset1; } selectorOrCacheTag = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); if ((entryPoint > methodZoneBase) && ((offset != cmNoCheckEntryOffset) && ((((((CogMethod *) (entryPoint - offset)))->cmType)) != CMOpenPIC))) { /* linked non-super send, cacheTag is a cacheTag */ if (!(validInlineCacheTag(selectorOrCacheTag))) { print("cache tag leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } else { /* unlinked send or super send; cacheTag is a selector unless 64-bit, in which case it is an index. */ if (!(checkValidOopReference(selectorOrCacheTag))) { print("selector leak in CM "); printHex(((sqInt)cogMethod)); print(" @ "); printHex(((sqInt)mcpc)); cr(); return 1; } } } return 0; } /* Answer if all references to objects in machine-code are valid. */ /* Cogit>>#checkIntegrityOfObjectReferencesInCode: */ sqInt checkIntegrityOfObjectReferencesInCode(sqInt gcModes) { CogMethod *cogMethod; sqInt count; sqInt ok; cogMethod = ((CogMethod *) methodZoneBase); ok = 1; while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if ((cogMethod->cmRefersToYoung)) { if (((count = occurrencesInYoungReferrers(cogMethod))) != 1) { print("young referrer CM "); printHex(((sqInt)cogMethod)); if (count == 0) { print(" is not in youngReferrers"); cr(); } else { print(" is in youngReferrers "); printNum(count); print(" times!"); cr(); } ok = 0; } } if (!(checkValidOopReference((cogMethod->selector)))) { print("object leak in CM "); printHex(((sqInt)cogMethod)); print(" selector"); cr(); ok = 0; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); if (!(checkValidObjectReference((cogMethod->methodObject)))) { print("object leak in CM "); printHex(((sqInt)cogMethod)); print(" methodObject"); cr(); ok = 0; } if (!(isOopCompiledMethod((cogMethod->methodObject)))) { print("non-method in CM "); printHex(((sqInt)cogMethod)); print(" methodObject"); cr(); ok = 0; } if ((mapForperformUntilarg(cogMethod, checkIfValidOopRefpccogMethod, ((sqInt)cogMethod))) != 0) { ok = 0; } if (((isYoungObject((cogMethod->methodObject))) || (isYoung((cogMethod->selector)))) && (!((cogMethod->cmRefersToYoung)))) { print("CM "); printHex(((sqInt)cogMethod)); print(" refers to young but not marked as such"); cr(); ok = 0; } } else { if (((cogMethod->cmType)) == CMClosedPIC) { if (!(checkValidObjectReferencesInClosedPIC(cogMethod))) { ok = 0; } } else { if (((cogMethod->cmType)) == CMOpenPIC) { if ((mapForperformUntilarg(cogMethod, checkIfValidOopRefpccogMethod, ((sqInt)cogMethod))) != 0) { ok = 0; } } } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return ok; } /* Cogit>>#checkMaybeObjRefInClosedPIC: */ static sqInt NoDbgRegParms checkMaybeObjRefInClosedPIC(sqInt maybeObject) { if (maybeObject == 0) { return 1; } if (!(couldBeObject(maybeObject))) { return 1; } return checkValidObjectReference(maybeObject); } /* Cogit>>#checkValidObjectReferencesInClosedPIC: */ static sqInt NoDbgRegParms checkValidObjectReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt ok; sqInt pc; ok = 1; /* first we check the obj ref at the beginning of the CPIC */ pc = (((sqInt)cPIC)) + firstCPICCaseOffset; if (!(checkMaybeObjRefInClosedPIC(literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */)))) { print("object leak in CPIC "); printHex(((sqInt)cPIC)); print(" @ "); printHex(pc - 4 /* jumpLongByteSize */); cr(); ok = 0; } /* For each case we check any object reference at the end address - sizeof(conditional instruction) and then increment the end address by case size */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (!(checkMaybeObjRefInClosedPIC(literalBeforeFollowingAddress(backEnd, (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)))) { print("object leak in CPIC "); printHex(((sqInt)cPIC)); print(" @ "); printHex(pc - (jumpLongConditionalByteSize(backEnd))); cr(); ok = 0; } pc += cPICCaseSize; } return ok; } /* i.e. this should never be called, so keep it out of the main path. */ /* Cogit>>#cleanUpFailingCogCodeConstituents: */ static sqInt NoDbgRegParms NeverInline cleanUpFailingCogCodeConstituents(CogMethod *cogMethodArg) { CogMethod *cogMethod; cogMethod = cogMethodArg; while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMClosedPIC) { (cogMethod->methodObject = 0); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } popRemappableOop(); return null; } /* Answer if the ClosedPIC refers to any unmarked objects or freed/freeable target methods, applying markAndTraceOrFreeCogMethod:firstVisit: to those targets to determine if freed/freeable. */ /* Cogit>>#closedPICRefersToUnmarkedObject: */ static sqInt NoDbgRegParms closedPICRefersToUnmarkedObject(CogMethod *cPIC) { sqInt i; sqInt object; sqInt pc; if (!((isImmediate((cPIC->selector))) || (isMarked((cPIC->selector))))) { return 1; } pc = addressOfEndOfCaseinCPIC(1, cPIC); if (couldBeObject((object = literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */)))) { if (!(isMarked(object))) { return 1; } } if (markAndTraceOrFreePICTargetin(jumpLongTargetBeforeFollowingAddress(backEnd, pc), cPIC)) { return 1; } for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (couldBeObject((object = literalBeforeFollowingAddress(backEnd, (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)))) { if (!(isMarked(object))) { return 1; } } if (markAndTraceOrFreePICTargetin(jumpLongTargetBeforeFollowingAddress(backEnd, pc), cPIC)) { return 1; } } return 0; } /* Cogit>>#codeEntryFor: */ char * codeEntryFor(char *address) { sqInt i; for (i = 0; i <= (trampolineTableIndex - 3); i += 2) { if (((address >= (trampolineAddresses[i + 1])) && (address <= ((trampolineAddresses[i + 3]) - 1)))) { return trampolineAddresses[i + 1]; } } return null; } /* Cogit>>#codeEntryNameFor: */ char * codeEntryNameFor(char *address) { sqInt i; for (i = 0; i <= (trampolineTableIndex - 3); i += 2) { if (((address >= (trampolineAddresses[i + 1])) && (address <= ((trampolineAddresses[i + 3]) - 1)))) { return trampolineAddresses[i]; } } return null; } /* Cogit>>#cogCodeBase */ sqInt cogCodeBase(void) { return codeBase; } /* Answer the contents of the code zone as an array of pair-wise element, address in ascending address order. Answer a string for a runtime routine or abstract label (beginning, end, etc), a CompiledMethod for a CMMethod, or a selector (presumably a Symbol) for a PIC. If withDetails is true - answer machine-code to bytecode pc mapping information for methods - answer class, target pair information for closed PIC N.B. Since the class tag for the first case of a closed PIC is stored at the send site, it must be collected by scanning methods (see collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method:). Since closed PICs are never shared they always come after the method that references them, so we don't need an extra pass to collect the first case class tags, which are (temporarily) assigned to each closed PIC's methodObject field. But we do need to reset the methodObject fields to zero. This is done in createPICData:, unless memory runs out, in which case it is done by cleanUpFailingCogCodeConstituents:. */ /* Cogit>>#cogCodeConstituents: */ sqInt cogCodeConstituents(sqInt withDetails) { CogMethod *cogMethod; sqInt constituents; sqInt count; sqInt i; sqInt label; sqInt profileData; sqInt value; /* + 3 for start, freeStart and end */ count = (trampolineTableIndex / 2) + 3; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { count += 1; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } constituents = instantiateClassindexableSize(classArray(), count * 2); if (!(constituents)) { return constituents; } pushRemappableOop(constituents); if ((((label = stringForCString("CogCode"))) == null) || (((value = positive32BitIntegerFor(codeBase))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(0, constituents, label); storePointerUncheckedofObjectwithValue(1, constituents, value); for (i = 0; i < trampolineTableIndex; i += 2) { if ((((label = stringForCString(trampolineAddresses[i]))) == null) || (((value = positive32BitIntegerFor(((usqInt)(trampolineAddresses[i + 1]))))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(2 + i, constituents, label); storePointerUncheckedofObjectwithValue(3 + i, constituents, value); } count = trampolineTableIndex + 2; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { profileData = (((cogMethod->cmType)) == CMMethod ? (cogMethod->methodObject) : (withDetails && (((cogMethod->cmType)) == CMClosedPIC) ? createCPICData(cogMethod) : (cogMethod->selector))); if (!(profileData)) { return cleanUpFailingCogCodeConstituents(cogMethod); } storePointerUncheckedofObjectwithValue(count, constituents, profileData); if (withDetails) { value = collectCogMethodConstituent(cogMethod); } else { value = positive32BitIntegerFor(((usqInt)cogMethod)); } if (!(value)) { return cleanUpFailingCogCodeConstituents(cogMethod); } storePointerUncheckedofObjectwithValue(count + 1, constituents, value); count += 2; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if ((((label = stringForCString("CCFree"))) == null) || (((value = positive32BitIntegerFor(mzFreeStart))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(count, constituents, label); storePointerUncheckedofObjectwithValue(count + 1, constituents, value); if ((((label = stringForCString("CCEnd"))) == null) || (((value = positive32BitIntegerFor(limitAddress))) == null)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(count + 2, constituents, label); storePointerUncheckedofObjectwithValue(count + 3, constituents, value); constituents = popRemappableOop(); beRootIfOld(constituents); return constituents; } /* Extend the cPIC with the supplied case. If caseNMethod is cogged dispatch direct to its unchecked entry-point. If caseNMethod is not cogged, jump to the fast interpreter dispatch, and if isMNUCase then dispatch to fast MNU invocation and mark the cPIC as having the MNU case for cache flushing. */ /* Cogit>>#cogExtendPIC:CaseNMethod:tag:isMNUCase: */ static sqInt NoDbgRegParms cogExtendPICCaseNMethodtagisMNUCase(CogMethod *cPIC, sqInt caseNMethod, sqInt caseNTag, sqInt isMNUCase) { sqInt address; usqInt addressFollowingJump; sqInt operand; sqInt target; compilationBreakpointisMNUCase((cPIC->selector), numBytesOf((cPIC->selector)), isMNUCase); assert(!(inlineCacheTagIsYoung(caseNTag))); assert((caseNMethod != null) && (!(isYoung(caseNMethod)))); if ((!isMNUCase) && (methodHasCogMethod(caseNMethod))) { /* this isn't an MNU and we have an already cogged method to jump to */ operand = 0; target = (((sqInt)(cogMethodOf(caseNMethod)))) + cmNoCheckEntryOffset; } else { operand = caseNMethod; if (isMNUCase) { /* this is an MNU so tag the CPIC header and setup a jump to the MNUAbort */ /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) cPIC))->cpicHasMNUCaseOrCMIsFullBlock) = 1; target = (((sqInt)cPIC)) + (sizeof(CogMethod)); } else { /* setup a jump to the interpretAborth so we can cog the target method */ target = (((sqInt)cPIC)) + (picInterpretAbortOffset()); } } address = addressOfEndOfCaseinCPIC(((cPIC->cPICNumCases)) + 1, cPIC); rewriteCPICCaseAttagobjReftarget(address, caseNTag, operand, target); /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, address - cPICCaseSize); flushICacheFromto(processor, ((usqInt)cPIC), (((usqInt)cPIC)) + closedPICSize); (cPIC->cPICNumCases = ((cPIC->cPICNumCases)) + 1); return 0; } /* Attempt to produce a machine code method for the bytecode method object aMethodObj. N.B. If there is no code memory available do *NOT* attempt to reclaim the method zone. Certain clients (e.g. ceSICMiss:) depend on the zone remaining constant across method generation. */ /* Cogit>>#cogFullBlockMethod:numCopied: */ CogMethod * cogFullBlockMethodnumCopied(sqInt aMethodObj, sqInt numCopied) { CogMethod *cogMethod; /* inline exclude: */ assert(!((methodHasCogMethod(aMethodObj)))); assert(isOopCompiledMethod(ultimateLiteralOf(aMethodObj))); if (aMethodObj == breakMethod) { haltmsg("Compilation of breakMethod"); } if (methodUsesAlternateBytecodeSet(aMethodObj)) { if ((numElementsIn(generatorTable)) <= 256) { return null; } bytecodeSetOffset = 256; } else { bytecodeSetOffset = 0; } ensureNoForwardedLiteralsIn(aMethodObj); methodObj = aMethodObj; methodHeader = methodHeaderOf(aMethodObj); receiverTags = receiverTagBitsForMethod(methodObj); cogMethod = compileCogFullBlockMethod(numCopied); if ((((((sqInt)cogMethod)) >= MaxNegativeErrorCode) && ((((sqInt)cogMethod)) <= -1))) { if ((((sqInt)cogMethod)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return null; } return cogMethod; } /* Cogit>>#cogitPostGCAction: */ void cogitPostGCAction(sqInt gcMode) { # if SPURVM if (gcMode == GCModeBecome) { followForwardedLiteralsInOpenPICList(); } # endif /* SPURVM */ assert(allMethodsHaveCorrectHeader()); assert(((gcMode & (GCModeFull + GCModeNewSpace)) == 0) || (kosherYoungReferrers())); } /* Check that the header fields onf a non-free method are consistent with the type. Answer 0 if it is ok, otherwise answer a code for the error. */ /* Cogit>>#cogMethodDoesntLookKosher: */ sqInt cogMethodDoesntLookKosher(CogMethod *cogMethod) { if (((((cogMethod->blockSize)) & (BytesPerWord - 1)) != 0) || ((((cogMethod->blockSize)) < (sizeof(CogMethod))) || (((cogMethod->blockSize)) >= 32768))) { return 1; } if (((cogMethod->cmType)) == CMFree) { return 2; } if (((cogMethod->cmType)) == CMMethod) { if (!((((cogMethod->methodHeader)) & 1))) { return 11; } if (!(couldBeObject((cogMethod->methodObject)))) { return 12; } if ((((cogMethod->stackCheckOffset)) > 0) && (((cogMethod->stackCheckOffset)) < cmNoCheckEntryOffset)) { return 13; } return 0; } if (((cogMethod->cmType)) == CMOpenPIC) { if (((cogMethod->blockSize)) != openPICSize) { return 21; } if (((cogMethod->methodHeader)) != 0) { return 22; } if (((cogMethod->objectHeader)) >= 0) { if (!((((cogMethod->methodObject)) == 0) || (compactionInProgress || (((cogMethod->methodObject)) == (((usqInt)(methodFor((cogMethod->methodObject))))))))) { return 23; } } if (((cogMethod->stackCheckOffset)) != 0) { return 24; } return 0; } if (((cogMethod->cmType)) == CMClosedPIC) { if (((cogMethod->blockSize)) != closedPICSize) { return 0x1F; } if (!(((((cogMethod->cPICNumCases)) >= 1) && (((cogMethod->cPICNumCases)) <= MaxCPICCases)))) { return 32; } if (((cogMethod->methodHeader)) != 0) { return 33; } if (((cogMethod->methodObject)) != 0) { return 34; } return 0; } return 9; } /* Attempt to create a one-case PIC for an MNU. The tag for the case is at the send site and so doesn't need to be generated. */ /* Cogit>>#cogMNUPICSelector:receiver:methodOperand:numArgs: */ CogMethod * cogMNUPICSelectorreceivermethodOperandnumArgs(sqInt selector, sqInt rcvr, sqInt methodOperand, sqInt numArgs) { CogMethod *pic; usqInt startAddress; if ((isYoung(selector)) || ((inlineCacheTagForInstance(rcvr)) == 0 /* picAbortDiscriminatorValue */)) { return 0; } compilationBreakpointisMNUCase(selector, numBytesOf(selector), 1); assert(endCPICCase0 != null); startAddress = allocate(closedPICSize); if (startAddress == 0) { callForCogCompiledCodeCompaction(); return 0; } memcpy(((CogMethod *) startAddress), ((CogMethod *) cPICPrototype), closedPICSize); configureMNUCPICmethodOperandnumArgsdelta(((CogMethod *) startAddress), methodOperand, numArgs, startAddress - cPICPrototype); /* begin fillInCPICHeader:numArgs:numCases:hasMNUCase:selector: */ pic = ((CogMethod *) startAddress); assert(!(isYoung(selector))); (pic->cmType = CMClosedPIC); (pic->objectHeader = 0); (pic->blockSize = closedPICSize); (pic->methodObject = 0); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); (pic->cmRefersToYoung = 0); (pic->cmUsageCount = initialClosedPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = 1; (pic->cPICNumCases = 1); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMClosedPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert(((pic->cPICNumCases)) == 1); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(closedPICSize == (roundUpLength(closedPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Create an Open PIC. Temporarily create a direct call of ceSendFromOpenPIC:. Should become a probe of the first-level method lookup cache followed by a call of ceSendFromOpenPIC: if the probe fails. */ /* Cogit>>#cogOpenPICSelector:numArgs: */ static CogMethod * NoDbgRegParms cogOpenPICSelectornumArgs(sqInt selector, sqInt numArgs) { sqInt codeSize; sqInt end; sqInt fixupSize; sqInt mapSize; sqInt opcodeSize; CogMethod *pic; usqInt startAddress; compilationBreakpointisMNUCase(selector, numBytesOf(selector), 0); startAddress = allocate(openPICSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } (methodLabel->address = startAddress); (methodLabel->dependent = null); /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 100; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; compileOpenPICnumArgs(selector, numArgs); computeMaximumSizes(); concretizeAt(methodLabel, startAddress); codeSize = generateInstructionsAt(startAddress + (sizeof(CogMethod))); mapSize = generateMapAtstart((startAddress + openPICSize) - 1, startAddress + cmNoCheckEntryOffset); assert((((entry->address)) - startAddress) == cmEntryOffset); assert(((roundUpLength((sizeof(CogMethod)) + codeSize)) + (roundUpLength(mapSize))) <= openPICSize); end = outputInstructionsAt(startAddress + (sizeof(CogMethod))); /* begin fillInOPICHeader:numArgs:selector: */ pic = ((CogMethod *) startAddress); (pic->cmType = CMOpenPIC); (pic->objectHeader = 0); (pic->blockSize = openPICSize); addToOpenPICList(pic); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); if ((pic->cmRefersToYoung = isYoung(selector))) { addToYoungReferrers(pic); } (pic->cmUsageCount = initialOpenPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = 0; (pic->cPICNumCases = 0); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMOpenPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(openPICSize == (roundUpLength(openPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + openPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Attempt to create a two-case PIC for case0CogMethod and case1Method,case1Tag. The tag for case0CogMethod is at the send site and so doesn't need to be generated. case1Method may be any of - a Cog method; link to its unchecked entry-point - a CompiledMethod; link to ceInterpretMethodFromPIC: - a CompiledMethod; link to ceMNUFromPICMNUMethod:receiver: */ /* Cogit>>#cogPICSelector:numArgs:Case0Method:Case1Method:tag:isMNUCase: */ static CogMethod * NoDbgRegParms cogPICSelectornumArgsCase0MethodCase1MethodtagisMNUCase(sqInt selector, sqInt numArgs, CogMethod *case0CogMethod, sqInt case1MethodOrNil, sqInt case1Tag, sqInt isMNUCase) { CogMethod *pic; usqInt startAddress; if (isYoung(selector)) { return ((CogMethod *) YoungSelectorInPIC); } compilationBreakpointisMNUCase(selector, numBytesOf(selector), isMNUCase); startAddress = allocate(closedPICSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } memcpy(((CogMethod *) startAddress), ((CogMethod *) cPICPrototype), closedPICSize); configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(((CogMethod *) startAddress), case0CogMethod, case1MethodOrNil, case1Tag, isMNUCase, numArgs, startAddress - cPICPrototype); /* begin fillInCPICHeader:numArgs:numCases:hasMNUCase:selector: */ pic = ((CogMethod *) startAddress); assert(!(isYoung(selector))); (pic->cmType = CMClosedPIC); (pic->objectHeader = 0); (pic->blockSize = closedPICSize); (pic->methodObject = 0); (pic->methodHeader = 0); (pic->selector = selector); (pic->cmNumArgs = numArgs); (pic->cmRefersToYoung = 0); (pic->cmUsageCount = initialClosedPICUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) pic))->cpicHasMNUCaseOrCMIsFullBlock) = isMNUCase; (pic->cPICNumCases = 2); (pic->blockEntryOffset = 0); assert(((pic->cmType)) == CMClosedPIC); assert(((pic->selector)) == selector); assert(((pic->cmNumArgs)) == numArgs); assert(((pic->cPICNumCases)) == 2); assert((callTargetFromReturnAddress(backEnd, (((sqInt)pic)) + missOffset)) == (picAbortTrampolineFor(numArgs))); assert(closedPICSize == (roundUpLength(closedPICSize))); flushICacheFromto(processor, ((usqInt)pic), (((usqInt)pic)) + closedPICSize); /* begin maybeEnableSingleStep */ return pic; } /* Attempt to produce a machine code method for the bytecode method object aMethodObj. N.B. If there is no code memory available do *NOT* attempt to reclaim the method zone. Certain clients (e.g. ceSICMiss:) depend on the zone remaining constant across method generation. */ /* Cogit>>#cog:selector: */ CogMethod * cogselector(sqInt aMethodObj, sqInt aSelectorOop) { CogMethod *cogMethod; sqInt selector; /* inline exclude:selector: */ assert(!((methodHasCogMethod(aMethodObj)))); assert(!((isOopCompiledMethod(ultimateLiteralOf(aMethodObj))))); /* coInterpreter stringOf: selector */ selector = (aSelectorOop == (nilObject()) ? maybeSelectorOfMethod(aMethodObj) : aSelectorOop); if (!(selector == null)) { compilationBreakpointisMNUCase(selector, lengthOf(selector), 0); } if (aMethodObj == breakMethod) { haltmsg("Compilation of breakMethod"); } if (methodUsesAlternateBytecodeSet(aMethodObj)) { if ((numElementsIn(generatorTable)) <= 256) { return null; } bytecodeSetOffset = 256; } else { bytecodeSetOffset = 0; } ensureNoForwardedLiteralsIn(aMethodObj); methodObj = aMethodObj; methodHeader = methodHeaderOf(aMethodObj); receiverTags = receiverTagBitsForMethod(methodObj); cogMethod = compileCogMethod(aSelectorOop); if ((((((sqInt)cogMethod)) >= MaxNegativeErrorCode) && ((((sqInt)cogMethod)) <= -1))) { if ((((sqInt)cogMethod)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return null; } return cogMethod; } /* Cogit>>#collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method: */ static sqInt NoDbgRegParms collectCogConstituentForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg) { sqInt address; sqInt annotation; sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; if (!(descriptor)) { return 0; } if (!((descriptor->isMapped))) { return 0; } address = positive32BitIntegerFor(mcpc); if (!(address)) { return PrimErrNoMemory; } storePointerUncheckedofObjectwithValue(cogConstituentIndex, topRemappableOop(), address); storePointerUncheckedofObjectwithValue(cogConstituentIndex + 1, topRemappableOop(), (((usqInt)bcpc << 1) | 1)); /* Collect any first case classTags for closed PICs. */ cogConstituentIndex += 2; if (((isBackwardBranchAndAnnotation & 1) == 0) && (((((usqInt) isBackwardBranchAndAnnotation) >> 1) >= IsSendCall) || (0))) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* send is linked */ /* begin targetMethodAndSendTableFor:annotation:into: */ annotation = ((usqInt) isBackwardBranchAndAnnotation) >> 1; /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmType)) == CMClosedPIC) { (targetMethod1->methodObject = classForInlineCacheTag(longAt(pcRelativeAddressAt(backEnd, ((usqInt)(mcpc - 8)))))); } } } return 0; } /* Answer a description of the mapping between machine code pointers and bytecode pointers for the Cog Method. First value is the address of the cog method. Following values are pairs of machine code pc and bytecode pc */ /* Cogit>>#collectCogMethodConstituent: */ static sqInt NoDbgRegParms collectCogMethodConstituent(CogMethod *cogMethod) { sqInt address; sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; sqInt cm; CogBlockMethod *cogBlockMethod; sqInt data; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; sqInt errCode; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt nSlots; sqInt result; sqInt startbcpc; sqInt targetPC; latestContinuation = 0; if (!(((cogMethod->cmType)) == CMMethod)) { return positive32BitIntegerFor(((usqInt)cogMethod)); } cogBlockMethod = ((CogBlockMethod *) cogMethod); if (((cogBlockMethod->stackCheckOffset)) == 0) { /* isFrameless ? */ return positive32BitIntegerFor(((usqInt)cogMethod)); } cm = (cogMethod->methodObject); /* +1 for first address */ nSlots = ((((byteSizeOf(cm)) - (startPCOfMethod(cm))) * 2) + (minSlotsForShortening())) + 1; data = instantiateClassindexableSize(splObj(ClassArray), nSlots); if (!(data)) { return null; } pushRemappableOop(data); address = positive32BitIntegerFor(((usqInt)cogMethod)); if (!(address)) { popRemappableOop(); return null; } storePointerUncheckedofObjectwithValue(0, topRemappableOop(), address); cogConstituentIndex = 1; /* begin mapFor:bcpc:performUntil:arg: */ startbcpc = startPCOfMethod((cogMethod->methodObject)); assert(((cogBlockMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogBlockMethod)) + ((cogBlockMethod->stackCheckOffset)); result = collectCogConstituentForAnnotationMcpcBcpcMethod(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc)), startbcpc, (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogBlockMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogBlockMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogBlockMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogBlockMethod->startpc))); homeMethod = cmHomeMethod(cogBlockMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogBlockMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { errCode = 0; goto l7; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { errCode = 0; goto l7; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = collectCogConstituentForAnnotationMcpcBcpcMethod(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } errCode = 0; l7: /* end mapFor:bcpc:performUntil:arg: */; if (errCode != 0) { popRemappableOop(); return null; } if (cogConstituentIndex < nSlots) { shortentoIndexableSize(topRemappableOop(), cogConstituentIndex); } return popRemappableOop(); } /* Cogit>>#compactCogCompiledCode */ void compactCogCompiledCode(void) { assert(noCogMethodsMaximallyMarked()); markActiveMethodsAndReferents(); freeOlderMethodsForCompaction(); compactPICsWithFreedTargets(); planCompaction(); updateStackZoneReferencesToCompiledCodePreCompaction(); relocateMethodsPreCompaction(); compactCompiledCode(); assert(allMethodsHaveCorrectHeader()); assert(kosherYoungReferrers()); stopsFromto(backEnd, freeStart(), (youngReferrers()) - 1); flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(youngReferrers()))); } /* Cogit>>#compactPICsWithFreedTargets */ static void compactPICsWithFreedTargets(void) { CogMethod *cogMethod; sqInt count; cogMethod = ((CogMethod *) methodZoneBase); count = 0; while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICCompactAndIsNowEmpty(cogMethod))) { (cogMethod->cmType = CMFree); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); count += 1; } assert(count == (numMethods())); } /* The start of a CogMethod has a call to a run-time abort routine that either handles an in-line cache failure or a stack overflow. The routine selects the path depending on ReceiverResultReg; if zero it takes the stack overflow path; if nonzero the in-line cache miss path. Neither of these paths returns. The abort routine must be called; In the callee the method is located by adding the relevant offset to the return address of the call. N.B. This code must match that in compilePICAbort: so that the offset of the return address of the call is the same in methods and closed PICs. */ /* Cogit>>#compileAbort */ static AbstractInstruction * compileAbort(void) { AbstractInstruction *anInstruction; sqInt callTarget; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } stackOverflowCall = anInstruction; /* If there is a link register it must be saved (pushed onto the stack) before it is smashed by the abort call, and hence needs to be manually handled here */ sendMiss = genoperand(PushR, LinkReg); /* begin Call: */ callTarget = methodAbortTrampolineFor(methodOrBlockNumArgs); return genoperand(Call, callTarget); } /* Cogit>>#compileBlockDispatchFrom:to: */ static sqInt NoDbgRegParms compileBlockDispatchFromto(sqInt lowBlockStartIndex, sqInt highBlockStartIndex) { AbstractInstruction *anInstruction; BlockStart *blockStart; sqInt halfWay; AbstractInstruction *jmp; sqInt literal; if (lowBlockStartIndex == highBlockStartIndex) { blockStart = blockStartAt(lowBlockStartIndex); genoperand(Jump, ((sqInt)((blockStart->entryLabel)))); return null; } halfWay = (highBlockStartIndex + lowBlockStartIndex) / 2; assert(((halfWay >= lowBlockStartIndex) && (halfWay <= highBlockStartIndex))); /* N.B. FLAGS := TempReg - startpc */ blockStart = blockStartAt(halfWay); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)(((blockStart->startpc)) + 1) << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)(((blockStart->startpc)) + 1) << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } if (lowBlockStartIndex == halfWay) { genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)((blockStart->entryLabel)))); compileBlockDispatchFromto(halfWay + 1, highBlockStartIndex); return null; } if ((halfWay + 1) == highBlockStartIndex) { blockStart = blockStartAt(highBlockStartIndex); genConditionalBranchoperand(JumpGreater, ((sqInt)((blockStart->entryLabel)))); return compileBlockDispatchFromto(lowBlockStartIndex, halfWay); } jmp = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); compileBlockDispatchFromto(lowBlockStartIndex, halfWay); if (halfWay == highBlockStartIndex) { blockStart = blockStartAt(highBlockStartIndex); jmpTarget(jmp, (blockStart->entryLabel)); } else { jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); compileBlockDispatchFromto(halfWay + 1, highBlockStartIndex); } return 0; } /* Compile a block's entry. This looks like a dummy CogBlockMethod header (for frame parsing) followed by either a frame build, if a frame is required, or nothing. The CogMethodHeader's objectHeader field is a back pointer to the method, but this can't be filled in until code generation. */ /* Cogit>>#compileBlockEntry: */ static void NoDbgRegParms compileBlockEntry(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; sqInt alignment; /* begin AlignmentNops: */ alignment = blockAlignment(); genoperand(AlignmentNops, alignment); (blockStart->fakeHeader = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); switch (sizeof(CogBlockMethod)) { case 8: genoperand(Fill32, 0); genoperand(Fill32, 0); break; case 12: genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); break; case 16: genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); genoperand(Fill32, 0); break; default: error("Case not found and no otherwise clause"); } (blockStart->entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (needsFrame) { compileBlockFrameBuild(blockStart); if (recordBlockTrace()) { /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceBlockActivationTrampoline); (abstractInstruction->annotation = IsRelativeCall); } } else { compileBlockFramelessEntry(blockStart); } } /* Generate a call to aRoutine with up to 4 arguments. If resultRegOrNone is not NoReg assign the C result to resultRegOrNone. If saveRegs, save all registers. Hack: a negative arg value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#compileCallFor:numArgs:arg:arg:arg:arg:resultReg:regsToSave: */ static void NoDbgRegParms compileCallFornumArgsargargargargresultRegregsToSave(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt resultRegOrNone, sqInt regMask) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; const int cStackAlignment = STACK_ALIGN_BYTES; sqInt delta; sqInt numRegsPushed; sqInt operand1; usqInt regMaskCopy; sqInt regsToSave; sqInt wordsPushedModAlignment; regsToSave = (resultRegOrNone == NoReg ? regMask : ((regMask | (1U << resultRegOrNone)) - (1U << resultRegOrNone))); if (cStackAlignment > BytesPerWord) { /* begin genAlignCStackSavingRegisters:numArgs:wordAlignment: */ regMaskCopy = ((usqInt)regsToSave); numRegsPushed = 0; while (regMaskCopy != 0) { numRegsPushed += regMaskCopy & 1; regMaskCopy = ((usqInt) regMaskCopy >> 1); } if ((numRegsPushed == 0) && (4 /* numIntRegArgs */ >= numArgs)) { goto l4; } wordsPushedModAlignment = (numRegsPushed + numArgs) % (cStackAlignment / BytesPerWord); if (wordsPushedModAlignment != 0) { delta = (cStackAlignment / BytesPerWord) - wordsPushedModAlignment; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, delta * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(delta * BytesPerWord)); } } l4: /* end genAlignCStackSavingRegisters:numArgs:wordAlignment: */; } /* begin genSaveRegs: */ if (regsToSave == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, regsToSave); } /* begin genMarshallNArgs:arg:arg:arg:arg: */ if (numArgs == 0) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst0 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, -2 - regOrConst0, CArg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(-2 - regOrConst0)); } } else { genoperandoperand(MoveRR, regOrConst0, CArg0Reg); } if (numArgs == 1) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst1 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, -2 - regOrConst1, CArg1Reg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(-2 - regOrConst1)); } } else { genoperandoperand(MoveRR, regOrConst1, CArg1Reg); } if (numArgs == 2) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst2 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(MoveCqR, -2 - regOrConst2, CArg2Reg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(-2 - regOrConst2)); } } else { genoperandoperand(MoveRR, regOrConst2, CArg2Reg); } if (numArgs == 3) { ((AbstractInstruction *) backEnd); goto l7; } if (regOrConst3 < NoReg) { /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, -2 - regOrConst3, CArg3Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(-2 - regOrConst3)); } } else { genoperandoperand(MoveRR, regOrConst3, CArg3Reg); } ((AbstractInstruction *) backEnd); l7: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ operand1 = ((usqInt)aRoutine); checkLiteralforInstruction(operand1, genoperand(CallFull, operand1)); if (resultRegOrNone != NoReg) { genWriteCResultIntoReg(backEnd, resultRegOrNone); } /* begin genRemoveNArgsFromStack: */ assert(numArgs <= 4); /* begin genRestoreRegs: */ if (regsToSave == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PopLDM, regsToSave); } } /* Compile the cache tag computation and the first comparison. Answer the address of that comparison. */ /* Cogit>>#compileCPICEntry */ static AbstractInstruction * compileCPICEntry(void) { entry = genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, TempReg, 1); /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* Compile the abstract instructions for the entire full block method. */ /* Cogit>>#compileEntireFullBlockMethod: */ static sqInt NoDbgRegParms compileEntireFullBlockMethod(sqInt numCopied) { sqInt result; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compileFullBlockEntry(); compileFullBlockMethodFrameBuild(numCopied); if (((result = compileMethodBody())) < 0) { return result; } assert(blockCount == 0); return 0; } /* The entry code to a method checks that the class of the current receiver matches that in the inline cache. Other non-obvious elements are that its alignment must be different from the alignment of the noCheckEntry so that the method map machinery can distinguish normal and super sends (super sends bind to the noCheckEntry). */ /* Cogit>>#compileEntry */ static void compileEntry(void) { AbstractInstruction *abstractInstruction; AbstractInstruction * inst; entry = genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, TempReg, 1); /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); genConditionalBranchoperand(JumpNonZero, ((sqInt)sendMiss)); noCheckEntry = genoperandoperand(Label, (labelCounter += 1), bytecodePC); if (compileSendTrace()) { /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceLinkedSendTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); } } /* Compile the abstract instructions for the entire method, including blocks. */ /* Abort for stack overflow on full block activation (no inline cache miss possible). The flag is SendNumArgsReg. */ /* Cogit>>#compileFullBlockEntry */ static sqInt compileFullBlockEntry(void) { sqInt alignment; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt callTarget; AbstractInstruction * jumpNoContextSwitch; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } stackOverflowCall = anInstruction; /* begin PushR: */ genoperand(PushR, LinkReg); /* begin Call: */ callTarget = methodAbortTrampolineFor(methodOrBlockNumArgs); genoperand(Call, callTarget); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } fullBlockNoContextSwitchEntry = anInstruction1; jumpNoContextSwitch = genoperand(Jump, ((sqInt)0)); /* begin AlignmentNops: */ alignment = ((BytesPerWord < 8) ? 8 : BytesPerWord); genoperand(AlignmentNops, alignment); fullBlockEntry = genoperandoperand(MoveRR, ReceiverResultReg, SendNumArgsReg); jmpTarget(jumpNoContextSwitch, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Compile the top-level method body. */ /* Cogit>>#compileMethodBody */ static sqInt compileMethodBody(void) { if (endPC < initialPC) { return 0; } return compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); } /* The start of a PIC has a call to a run-time abort routine that either handles a dispatch to an interpreted method or a dispatch of an MNU case. The routine selects the path by testing ClassReg, which holds the inline cache tag; if equal to the picAbortDiscriminatorValue (zero) it takes the MNU path; if nonzero the dispatch to interpreter path. Neither of these paths returns. The abort routine must be called; In the callee the PIC is located by adding the relevant offset to the return address of the call. N.B. This code must match that in compileAbort so that the offset of the return address of the call is the same in methods and closed PICs. */ /* Cogit>>#compilePICAbort: */ static sqInt NoDbgRegParms compilePICAbort(sqInt numArgs) { AbstractInstruction *anInstruction; sqInt callTarget; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0 /* picAbortDiscriminatorValue */, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0 /* picAbortDiscriminatorValue */)); } picMNUAbort = anInstruction; /* If there is a link register it must be saved (pushed onto the stack) before it is smashed by the abort call, and hence needs to be manually handled here */ picInterpretAbort = genoperand(PushR, LinkReg); /* begin Call: */ callTarget = picAbortTrampolineFor(numArgs); genoperand(Call, callTarget); return 0; } /* Generate a trampoline with up to four arguments. Generate either a call or a jump to aRoutine as requested by callJumpBar. If generating a call and resultRegOrNone is not NoReg pass the C result back in resultRegOrNone. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#compileTrampolineFor:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg: */ static void NoDbgRegParms compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(void *aRoutine, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone) { genSmalltalkToCStackSwitch(pushLinkReg); compileCallFornumArgsargargargargresultRegregsToSave(aRoutine, numArgs, regOrConst0, regOrConst1, regOrConst2, regOrConst3, resultRegOrNone, regMask); genLoadStackPointers(backEnd); if (pushLinkReg && (1)) { genoperand(PopR, PCReg); } else { genoperand(RetN, 0); } } /* Generate the entry code for a method to determine cmEntryOffset and cmNoCheckEntryOffset. We need cmNoCheckEntryOffset up front to be able to generate the map starting from cmNoCheckEntryOffset */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#computeEntryOffsets */ static void computeEntryOffsets(void) { sqInt fixupSize; sqInt opcodeSize; AbstractInstruction *sendMissCall; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 24; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; methodOrBlockNumArgs = 0; sendMissCall = compileAbort(); compileEntry(); computeMaximumSizes(); generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); cmEntryOffset = ((entry->address)) - methodZoneBase; cmNoCheckEntryOffset = ((noCheckEntry->address)) - methodZoneBase; missOffset = (((sendMissCall->address)) + ((sendMissCall->machineCodeSize))) - methodZoneBase; entryPointMask = BytesPerWord - 1; while ((cmEntryOffset & entryPointMask) == (cmNoCheckEntryOffset & entryPointMask)) { entryPointMask = (entryPointMask + entryPointMask) + 1; } if (entryPointMask >= (roundUpLength(1))) { error("cannot differentiate checked and unchecked entry-points with current cog method alignment"); } checkedEntryAlignment = cmEntryOffset & entryPointMask; uncheckedEntryAlignment = cmNoCheckEntryOffset & entryPointMask; assert(checkedEntryAlignment != uncheckedEntryAlignment); } /* Generate the entry code for a method to determine cmEntryOffset and cmNoCheckEntryOffset. We need cmNoCheckEntryOffset up front to be able to generate the map starting from cmNoCheckEntryOffset */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#computeFullBlockEntryOffsets */ static void computeFullBlockEntryOffsets(void) { sqInt fixupSize; sqInt opcodeSize; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 24; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; methodOrBlockNumArgs = 0; compileFullBlockEntry(); computeMaximumSizes(); generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); cbEntryOffset = ((fullBlockEntry->address)) - methodZoneBase; cbNoSwitchEntryOffset = ((fullBlockNoContextSwitchEntry->address)) - methodZoneBase; } /* This pass assigns maximum sizes to all abstract instructions and eliminates jump fixups. It hence assigns the maximum address an instruction will occur at which allows the next pass to conservatively size jumps. */ /* Cogit>>#computeMaximumSizes */ static void computeMaximumSizes(void) { AbstractInstruction *abstractInstruction; sqInt i; sqInt relativeAddress; dumpLiterals(0); relativeAddress = 0; for (i = 0; i < opcodeIndex; i += 1) { abstractInstruction = abstractInstructionAt(i); (abstractInstruction->address = relativeAddress); (abstractInstruction->maxSize = computeMaximumSize(abstractInstruction)); relativeAddress += (abstractInstruction->maxSize); } } /* Configure a copy of the prototype CPIC for a two-case PIC for case0CogMethod and case1Method case1Tag. The tag for case0CogMethod is at the send site and so doesn't need to be generated. case1Method may be any of - a Cog method; jump to its unchecked entry-point - a CompiledMethod; jump to the ceInterpretFromPIC trampoline - nil; call ceMNUFromPIC addDelta is the address change from the prototype to the new CPIC location, needed because the loading of the CPIC label at the end may use a literal instead of a pc relative load. */ /* self disassembleFrom: cPIC asInteger + (self sizeof: CogMethod) to: cPIC asInteger + closedPICSize */ /* Cogit>>#configureCPIC:Case0:Case1Method:tag:isMNUCase:numArgs:delta: */ static sqInt NoDbgRegParms configureCPICCase0Case1MethodtagisMNUCasenumArgsdelta(CogMethod *cPIC, CogMethod *case0CogMethod, sqInt case1Method, sqInt case1Tag, sqInt isMNUCase, sqInt numArgs, sqInt addrDelta) { sqInt caseEndAddress; sqInt operand; sqInt targetEntry; assert(case1Method != null); rewriteCallAttarget(backEnd, (((sqInt)cPIC)) + missOffset, picAbortTrampolineFor(numArgs)); assert(!(inlineCacheTagIsYoung(case1Tag))); if ((!isMNUCase) && (methodHasCogMethod(case1Method))) { operand = 0; targetEntry = (((sqInt)(cogMethodOf(case1Method)))) + cmNoCheckEntryOffset; } else { /* We do not scavenge PICs, hence we cannot cache the MNU method if it is in new space. */ operand = ((case1Method == null) || (isYoungObject(case1Method)) ? 0 : case1Method); targetEntry = (case1Method == null ? (((sqInt)cPIC)) + (sizeof(CogMethod)) : (((sqInt)cPIC)) + (picInterpretAbortOffset())); } rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + firstCPICCaseOffset, (((sqInt)case0CogMethod)) + cmNoCheckEntryOffset); /* update the cpic case */ caseEndAddress = addressOfEndOfCaseinCPIC(2, cPIC); rewriteCPICCaseAttagobjReftarget(caseEndAddress, case1Tag, operand, ((sqInt)((isMNUCase ? (((sqInt)cPIC)) + (sizeof(CogMethod)) : targetEntry)))); relocateMethodReferenceBeforeAddressby(backEnd, ((((sqInt)cPIC)) + cPICEndOfCodeOffset) - 4 /* jumpLongByteSize */, addrDelta); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, cPICMissTrampolineFor(numArgs)); return 0; } /* Configure a copy of the prototype CPIC for a one-case MNU CPIC that calls ceMNUFromPIC for case0Tag The tag for case0 is at the send site and so doesn't need to be generated. addDelta is the address change from the prototype to the new CPIC location, needed because the loading of the CPIC label at the end may be a literal instead of a pc-relative load. */ /* adjust the jump at missOffset, the ceAbortXArgs */ /* Cogit>>#configureMNUCPIC:methodOperand:numArgs:delta: */ static sqInt NoDbgRegParms configureMNUCPICmethodOperandnumArgsdelta(CogMethod *cPIC, sqInt methodOperand, sqInt numArgs, sqInt addrDelta) { usqInt addressFollowingJump; int operand; sqInt target; rewriteCallAttarget(backEnd, (((sqInt)cPIC)) + missOffset, picAbortTrampolineFor(numArgs)); /* set the jump to the case0 method */ operand = ((methodOperand == null) || (isYoungObject(methodOperand)) ? 0 : methodOperand); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + firstCPICCaseOffset, (((sqInt)cPIC)) + (sizeof(CogMethod))); storeLiteralbeforeFollowingAddress(backEnd, operand, ((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */); rewriteJumpLongAttarget(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, cPICMissTrampolineFor(numArgs)); relocateMethodReferenceBeforeAddressby(backEnd, ((((sqInt)cPIC)) + cPICEndOfCodeOffset) - 4 /* jumpLongByteSize */, addrDelta); /* begin rewriteCPIC:caseJumpTo: */ target = addressOfEndOfCaseinCPIC(2, cPIC); /* begin rewriteCPICJumpAt:target: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, target); return 0; } /* Scan the CPIC for target methods that have been freed and eliminate them. Since the first entry cannot be eliminated, answer that the PIC should be freed if the first entry is to a free target. Answer if the PIC is now empty or should be freed. */ /* Cogit>>#cPICCompactAndIsNowEmpty: */ static sqInt NoDbgRegParms cPICCompactAndIsNowEmpty(CogMethod *cPIC) { usqInt addressFollowingJump; usqInt addressFollowingJump1; sqInt entryPoint; sqInt followingAddress; sqInt i; sqInt methods[MaxCPICCases]; sqInt pc; int tags[MaxCPICCases]; CogMethod *targetMethod; sqInt targets[MaxCPICCases]; sqInt used; sqInt valid; used = 0; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } /* Collect all target triples except for triples whose entry-point is a freed method */ valid = 1; if (!(((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint))))) { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); if (((targetMethod->cmType)) == CMFree) { if (i == 1) { return 1; } valid = 0; } } if (valid) { tags[used] = ((i > 1 ? (/* begin literal32BeforeFollowingAddress: */ (followingAddress = pc - (jumpLongConditionalByteSize(backEnd))), literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), followingAddress)) : 0)); targets[used] = entryPoint; methods[used] = (literalBeforeFollowingAddress(backEnd, pc - ((i == 1 ? /* begin jumpLongByteSize */ 4 : (jumpLongConditionalByteSize(backEnd)) + 8 /* cmpC32RTempByteSize */)))); used += 1; } } if (used == ((cPIC->cPICNumCases))) { return 0; } if (used == 0) { return 1; } (cPIC->cPICNumCases = used); if (used == 1) { pc = addressOfEndOfCaseinCPIC(2, cPIC); /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump, pc); return 0; } for (i = 1; i < used; i += 1) { pc = addressOfEndOfCaseinCPIC(i + 1, cPIC); rewriteCPICCaseAttagobjReftarget(pc, tags[i], methods[i], targets[i]); } /* begin rewriteCPIC:caseJumpTo: */ addressFollowingJump1 = (((((sqInt)cPIC)) + firstCPICCaseOffset) - 4 /* jumpLongByteSize */) - 4 /* loadLiteralByteSize */; rewriteTransferAttarget(((AbstractInstruction *) backEnd), addressFollowingJump1, pc - cPICCaseSize); return 0; } /* The first case in a CPIC doesn't have a class reference so we need only step over actually usd subsequent cases. */ /* Cogit>>#cPICHasForwardedClass: */ static sqInt NoDbgRegParms cPICHasForwardedClass(CogMethod *cPIC) { sqInt classIndex; sqInt i; sqInt pc; /* start by finding the address of the topmost case, the cPICNumCases'th one */ pc = (addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC)) - (jumpLongConditionalByteSize(backEnd)); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { /* begin literal32BeforeFollowingAddress: */ classIndex = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (isForwardedClassIndex(classIndex)) { return 1; } pc += cPICCaseSize; } return 0; } /* scan the CPIC for target methods that have been freed. */ /* Cogit>>#cPICHasFreedTargets: */ static sqInt NoDbgRegParms cPICHasFreedTargets(CogMethod *cPIC) { sqInt entryPoint; sqInt i; sqInt pc; CogMethod *targetMethod; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (!(((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint))))) { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); if (((targetMethod->cmType)) == CMFree) { return 1; } } } return 0; } /* Whimsey; we want 16rCA5E10 + cPICPrototypeCaseOffset to be somewhere in the middle of the zone. */ /* Cogit>>#cPICPrototypeCaseOffset */ static sqInt cPICPrototypeCaseOffset(void) { return ((methodZoneBase + (youngReferrers())) / 2) - 13262352; } /* Are any of the jumps from this CPIC to targetMethod? */ /* Cogit>>#cPIC:HasTarget: */ static sqInt NoDbgRegParms cPICHasTarget(CogMethod *cPIC, CogMethod *targetMethod) { sqInt i; sqInt pc; sqInt target; target = (((usqInt)targetMethod)) + cmNoCheckEntryOffset; /* Since this is a fast test doing simple compares we don't need to care that some cases have nonsense addresses in there. Just zip on through. */ /* First jump is unconditional; subsequent ones are conditional */ pc = (((sqInt)cPIC)) + firstCPICCaseOffset; if (target == (jumpLongTargetBeforeFollowingAddress(backEnd, pc))) { return 1; } for (i = 2; i <= MaxCPICCases; i += 1) { pc += cPICCaseSize; if (target == (jumpLongTargetBeforeFollowingAddress(backEnd, pc))) { return 1; } } return 0; } /* Answer an Array of the PIC's selector, followed by class and targetMethod/doesNotUnderstand: for each entry in the PIC. */ /* Cogit>>#createCPICData: */ static sqInt NoDbgRegParms createCPICData(CogMethod *cPIC) { sqInt class; sqInt entryPoint; sqInt i; sqInt pc; sqInt picData; sqInt target; CogMethod *targetMethod; assert((((cPIC->methodObject)) == 0) || (addressCouldBeOop((cPIC->methodObject)))); picData = instantiateClassindexableSize(classArray(), (((cPIC->cPICNumCases)) * 2) + 1); if (!(picData)) { return picData; } storePointerUncheckedofObjectwithValue(0, picData, (cPIC->selector)); for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { /* first case may have been collected and stored here by collectCogConstituentFor:Annotation:Mcpc:Bcpc:Method: */ class = (cPIC->methodObject); if (class == 0) { class = nilObject(); } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { class = classForInlineCacheTag(literal32BeforeFollowingAddress(backEnd, pc - (jumpLongConditionalByteSize(backEnd)))); /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { target = splObj(SelectorDoesNotUnderstand); } else { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert(((targetMethod->cmType)) == CMMethod); target = (targetMethod->methodObject); } storePointerUncheckedofObjectwithValue((i * 2) - 1, picData, class); storePointerUncheckedofObjectwithValue(i * 2, picData, target); } beRootIfOld(picData); (cPIC->methodObject = 0); return picData; } /* Division is a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#DivR:R:Quo:Rem: */ static AbstractInstruction * NoDbgRegParms gDivRRQuoRem(sqInt rDivisor, sqInt rDividend, sqInt rQuotient, sqInt rRemainder) { genDivRRQuoRem(backEnd, rDivisor, rDividend, rQuotient, rRemainder); return abstractInstructionAt(opcodeIndex - 1); } /* Return the default number of bytes to allocate for native code at startup. The actual value can be set via vmParameterAt: and/or a preference in the ini file. */ /* Cogit>>#defaultCogCodeSize */ sqInt defaultCogCodeSize(void) { return 1024 * 1280; } /* Answer the number of bytecodes to skip to get to the first bytecode past the primitive call and any store of the error code. */ /* Cogit>>#deltaToSkipPrimAndErrorStoreIn:header: */ static sqInt NoDbgRegParms deltaToSkipPrimAndErrorStoreInheader(sqInt aMethodObj, sqInt aMethodHeader) { return (((primitiveIndexOfMethodheader(aMethodObj, aMethodHeader)) > 0) && ((longStoreBytecodeForHeader(aMethodHeader)) == (fetchByteofObject((startPCOfMethod(aMethodObj)) + (sizeOfCallPrimitiveBytecode(aMethodHeader)), aMethodObj))) ? (sizeOfCallPrimitiveBytecode(aMethodHeader)) + (sizeOfLongStoreTempBytecode(aMethodHeader)) : 0); } /* Cogit>>#endPCOf: */ static sqInt NoDbgRegParms endPCOf(sqInt aMethod) { sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt end; sqInt latestContinuation; sqInt nExts; sqInt pc; sqInt prim; sqInt targetPC; pc = (latestContinuation = startPCOfMethod(aMethod)); if (((prim = primitiveIndexOf(aMethod))) > 0) { if (isQuickPrimitiveIndex(prim)) { return pc - 1; } } /* begin bytecodeSetOffsetFor: */ bsOffset = # if MULTIPLEBYTECODESETS (methodUsesAlternateBytecodeSet(aMethod) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; nExts = 0; end = numBytesOf(aMethod); while (pc <= end) { byte = fetchByteofObject(pc, aMethod); descriptor = generatorAt(byte + bsOffset); if (((descriptor->isReturn)) && (pc >= latestContinuation)) { end = pc; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { distance = ((descriptor->spanFunction))(descriptor, pc, nExts, aMethod); targetPC = (pc + ((descriptor->numBytes))) + distance; latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); if ((descriptor->isBlockCreation)) { pc += distance; } } else { latestContinuation = latestContinuation; } nExts = ((descriptor->isExtension) ? nExts + 1 : 0); pc += (descriptor->numBytes); } return end; } /* This is a static version of ceEnterCogCodePopReceiverReg for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* Cogit>>#enterCogCodePopReceiver */ void enterCogCodePopReceiver(void) { realCEEnterCogCodePopReceiverReg(); error("what??"); } /* Answer if the entryPoint's tag is expected to be a selector reference, as opposed to a class tag. */ /* Cogit>>#entryPointTagIsSelector: */ static sqInt NoDbgRegParms entryPointTagIsSelector(sqInt entryPoint) { return (entryPoint < methodZoneBase) || (((entryPoint & entryPointMask) == uncheckedEntryAlignment) || (((entryPoint & entryPointMask) == checkedEntryAlignment) && ((((((CogMethod *) (entryPoint - cmEntryOffset)))->cmType)) == CMOpenPIC))); } /* Use asserts to check if the ClosedPICPrototype is as expected from compileClosedPICPrototype, and can be updated as required via rewriteCPICCaseAt:tag:objRef:target:. If all asserts pass, answer 0, otherwise answer a bit mask identifying all the errors. */ /* self disassembleFrom: methodZoneBase + (self sizeof: CogMethod) to: methodZoneBase + closedPICSize */ /* Cogit>>#expectedClosedPICPrototype: */ static sqInt NoDbgRegParms expectedClosedPICPrototype(CogMethod *cPIC) { sqInt classTag; sqInt classTagPC; sqInt entryPoint; sqInt errors; sqInt i; sqInt methodObjPC; sqInt object; sqInt pc; errors = 0; /* First jump is unconditional; subsequent ones are conditional */ pc = (((usqInt)cPIC)) + firstCPICCaseOffset; object = literalBeforeFollowingAddress(backEnd, pc - 4 /* jumpLongByteSize */); if (!(asserta(object == (firstPrototypeMethodOop())))) { errors = 1; } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); if (!(asserta(entryPoint == ((cPICPrototypeCaseOffset()) + 13262352)))) { errors += 2; } for (i = 1; i < MaxCPICCases; i += 1) { /* verify information in case is as expected. */ pc += cPICCaseSize; methodObjPC = (pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */; object = literalBeforeFollowingAddress(backEnd, methodObjPC); if (!(asserta(object == ((subsequentPrototypeMethodOop()) + i)))) { errors = errors | 4; } classTagPC = pc - (jumpLongConditionalByteSize(backEnd)); /* begin literal32BeforeFollowingAddress: */ classTag = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), classTagPC); if (!(asserta(classTag == (3133021973U + i)))) { errors = errors | 8; } /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (!(asserta(entryPoint == (((cPICPrototypeCaseOffset()) + 13262352) + (i * 16))))) { errors = errors | 16; } rewriteCPICCaseAttagobjReftarget(pc, classTag ^ 1515870810, object ^ 2779096485U, entryPoint ^ 5614160); object = literalBeforeFollowingAddress(backEnd, methodObjPC); if (!(asserta(object == (((subsequentPrototypeMethodOop()) + i) ^ 2779096485U)))) { errors = errors | 32; } /* begin literal32BeforeFollowingAddress: */ classTag = literalBeforeFollowingAddress(((AbstractInstruction *) backEnd), classTagPC); if (!(asserta(classTag == ((3133021973U + i) ^ 1515870810)))) { errors = errors | 64; } /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); if (!(asserta(entryPoint == ((((cPICPrototypeCaseOffset()) + 13262352) + (i * 16)) ^ 5614160)))) { errors = errors | 128; } rewriteCPICCaseAttagobjReftarget(pc, classTag ^ 1515870810, object ^ 2779096485U, entryPoint ^ 5614160); } entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, (pc + cPICEndSize) - (endSizeOffset())); if (!(asserta(entryPoint == (cPICMissTrampolineFor(0))))) { errors += 256; } return errors; } /* 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev * 256 + Ext A) */ /* Cogit>>#extABytecode */ static sqInt extABytecode(void) { extA = (((usqInt) extA << 8)) + byte1; return 0; } /* 225 11100001 sbbbbbbb Extend B (Ext B = Ext B prev * 256 + Ext B) */ /* Cogit>>#extBBytecode */ static sqInt extBBytecode(void) { extB = ((numExtB == 0) && (byte1 > 0x7F) ? byte1 - 256 : (((usqInt) extB << 8)) + byte1); numExtB += 1; return 0; } /* Fill in the block headers now we know the exact layout of the code. */ /* Cogit>>#fillInBlockHeadersAt: */ static sqInt NoDbgRegParms fillInBlockHeadersAt(sqInt startAddress) { CogBlockMethod *blockHeader; BlockStart *blockStart; sqInt i; if (!(needsFrame && (blockCount > 0))) { return null; } if (blockNoContextSwitchOffset == null) { blockNoContextSwitchOffset = ((blockEntryLabel->address)) - ((blockEntryNoContextSwitch->address)); } else { assert(blockNoContextSwitchOffset == (((blockEntryLabel->address)) - ((blockEntryNoContextSwitch->address)))); } for (i = 0; i < blockCount; i += 1) { blockStart = blockStartAt(i); blockHeader = ((CogBlockMethod *) ((((blockStart->fakeHeader))->address))); (blockHeader->homeOffset = ((((blockStart->fakeHeader))->address)) - startAddress); (blockHeader->startpc = (blockStart->startpc)); (blockHeader->cmType = CMBlock); (blockHeader->cmNumArgs = (blockStart->numArgs)); (blockHeader->cbUsesInstVars = (blockStart->hasInstVarRef)); (blockHeader->stackCheckOffset = (((blockStart->stackCheckLabel)) == null ? 0 : ((((blockStart->stackCheckLabel))->address)) - ((((blockStart->fakeHeader))->address)))); } return 0; } /* Cogit>>#fillInMethodHeader:size:selector: */ static CogMethod * NoDbgRegParms fillInMethodHeadersizeselector(CogMethod *method, sqInt size, sqInt selector) { CogMethod *originalMethod; sqInt rawHeader; (method->cmType = CMMethod); (method->objectHeader = nullHeaderForMachineCodeMethod()); (method->blockSize = size); (method->methodObject = methodObj); /* If the method has already been cogged (e.g. Newspeak accessors) then leave the original method attached to its cog method, but get the right header. */ rawHeader = rawHeaderOf(methodObj); if (isCogMethodReference(rawHeader)) { originalMethod = ((CogMethod *) rawHeader); assert(((originalMethod->blockSize)) == size); assert(methodHeader == ((originalMethod->methodHeader))); } else { rawHeaderOfput(methodObj, ((sqInt)method)); } (method->methodHeader = methodHeader); (method->selector = selector); (method->cmNumArgs = argumentCountOfMethodHeader(methodHeader)); if ((method->cmRefersToYoung = hasYoungReferent)) { addToYoungReferrers(method); } (method->cmUsageCount = initialMethodUsageCount()); /* begin cpicHasMNUCase: */ ((((CogBlockMethod *) method))->cpicHasMNUCaseOrCMIsFullBlock) = 0; (method->cmUsesPenultimateLit = maxLitIndex >= ((literalCountOfMethodHeader(methodHeader)) - 2)); (method->blockEntryOffset = (blockEntryLabel != null ? ((blockEntryLabel->address)) - (((sqInt)method)) : 0)); if (needsFrame) { if (!((((stackCheckLabel->address)) - (((sqInt)method))) <= MaxStackCheckOffset)) { error("too much code for stack check offset"); } } (method->stackCheckOffset = (needsFrame ? ((stackCheckLabel->address)) - (((sqInt)method)) : 0)); assert((callTargetFromReturnAddress(backEnd, (((sqInt)method)) + missOffset)) == (methodAbortTrampolineFor((method->cmNumArgs)))); assert(size == (roundUpLength(size))); flushICacheFromto(processor, ((usqInt)method), (((usqInt)method)) + size); /* begin maybeEnableSingleStep */ return method; } /* Cogit>>#findBackwardBranch:IsBackwardBranch:Mcpc:Bcpc:MatchingBcpc: */ static sqInt NoDbgRegParms findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetBcpc) { return ((isBackwardBranchAndAnnotation & 1) && ((((sqInt)targetBcpc)) == bcpc) ? ((sqInt)mcpc) : 0); } /* Cogit>>#findBlockMethodWithEntry:startBcpc: */ static usqInt NoDbgRegParms findBlockMethodWithEntrystartBcpc(sqInt blockEntryMcpc, sqInt startBcpc) { CogBlockMethod *cogBlockMethod; cogBlockMethod = ((CogBlockMethod *) (blockEntryMcpc - (sizeof(CogBlockMethod)))); if (((cogBlockMethod->startpc)) == startBcpc) { return ((usqInt)cogBlockMethod); } return 0; } /* Cogit>>#findMapLocationForMcpc:inMethod: */ static usqInt NoDbgRegParms findMapLocationForMcpcinMethod(usqInt targetMcpc, CogMethod *cogMethod) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; if (mcpc == targetMcpc) { return map; } while (((mapByte = byteAt(map))) != MapEnd) { annotation = ((usqInt) mapByte) >> AnnotationShift; if (annotation != IsAnnotationExtension) { mcpc += 4 /* codeGranularity */ * ((annotation == IsDisplacementX2N ? ((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift)) : mapByte & DisplacementMask)); } if (mcpc >= targetMcpc) { assert(mcpc == targetMcpc); if (annotation == IsDisplacementX2N) { map -= 1; mapByte = byteAt(map); annotation = ((usqInt) mapByte) >> AnnotationShift; assert(annotation > IsAnnotationExtension); } return map; } map -= 1; } return 0; } /* Find the CMMethod or CMBlock that has zero-relative startbcpc as its first bytecode pc. As this is for cannot resume processing and/or conversion to machine-code on backward branch, it doesn't have to be fast. Enumerate block returns and map to bytecode pcs. */ /* Cogit>>#findMethodForStartBcpc:inHomeMethod: */ CogBlockMethod * findMethodForStartBcpcinHomeMethod(sqInt startbcpc, CogMethod *cogMethod) { assert(((cogMethod->cmType)) == CMMethod); if (startbcpc == (startPCOfMethodHeader((cogMethod->methodHeader)))) { return ((CogBlockMethod *) cogMethod); } assert(((cogMethod->blockEntryOffset)) != 0); return ((CogBlockMethod *) (blockDispatchTargetsForperformarg(cogMethod, findBlockMethodWithEntrystartBcpc, startbcpc))); } /* Machine code addresses map to the following bytecode for all bytecodes except backward branches, where they map to the backward branch itself. This is so that loops continue, rather than terminate prematurely. */ /* Cogit>>#find:IsBackwardBranch:Mcpc:Bcpc:MatchingMcpc: */ static sqInt NoDbgRegParms findIsBackwardBranchMcpcBcpcMatchingMcpc(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *targetMcpc) { return (targetMcpc == mcpc ? ((descriptor == null) || (isBackwardBranchAndAnnotation & 1) ? bcpc : bcpc + ((descriptor->numBytes))) : 0); } /* Cogit>>#firstMappedPCFor: */ static sqInt NoDbgRegParms firstMappedPCFor(CogMethod *cogMethod) { return ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); } /* Answer a fake value for the first method oop in the PIC prototype. Since we use MoveUniqueCw:R: it must not be confused with a method-relative address. */ /* Cogit>>#firstPrototypeMethodOop */ static sqInt firstPrototypeMethodOop(void) { return (((((usqInt)99282957)) >= ((methodLabel->address))) && ((((usqInt)99282957)) < (youngReferrers())) ? 212332557 : 99282957); } /* Cogit>>#fixupAt: */ static BytecodeFixup * NoDbgRegParms fixupAt(sqInt fixupPC) { return fixupAtIndex(fixupPC - initialPC); } /* Cogit>>#followForwardedLiteralsIn: */ void followForwardedLiteralsIn(CogMethod *cogMethod) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; assert((((cogMethod->cmType)) != CMMethod) || (!(isForwarded((cogMethod->methodObject))))); if (shouldRemapOop((cogMethod->selector))) { (cogMethod->selector = remapObj((cogMethod->selector))); if (isYoung((cogMethod->selector))) { ensureInYoungReferrers(cogMethod); } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#followForwardedMethods */ void followForwardedMethods(void) { CogMethod *cogMethod; sqInt freedPIC; freedPIC = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { if (isForwarded((cogMethod->methodObject))) { (cogMethod->methodObject = followForwarded((cogMethod->methodObject))); if (isYoungObject((cogMethod->methodObject))) { ensureInYoungReferrers(cogMethod); } } } if (((cogMethod->cmType)) == CMClosedPIC) { if (followMethodReferencesInClosedPIC(cogMethod)) { freedPIC = 1; freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedPIC) { unlinkSendsToFree(); } } /* Follow a potential object reference from a closed PIC. This may be a method reference or null. Answer if the followed literal is young. 'mcpc' refers to the jump/branch instruction at the end of each cpic case */ /* Cogit>>#followMaybeObjRefInClosedPICAt: */ static sqInt NoDbgRegParms followMaybeObjRefInClosedPICAt(sqInt mcpc) { sqInt object; sqInt subject; object = literalBeforeFollowingAddress(backEnd, mcpc); if (!(couldBeObject(object))) { return 0; } if (!(isForwarded(object))) { return isYoungObject(object); } subject = followForwarded(object); storeLiteralbeforeFollowingAddress(backEnd, subject, mcpc); codeModified = 1; return isYoungObject(subject); } /* Remap all object references in the closed PIC. Answer if any references are young. Set codeModified if any modifications are made. */ /* Cogit>>#followMethodReferencesInClosedPIC: */ static sqInt NoDbgRegParms followMethodReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt pc; sqInt refersToYoung; /* first we check the potential method oop load at the beginning of the CPIC */ pc = addressOfEndOfCaseinCPIC(1, cPIC); /* We find the end address of the cPICNumCases'th case and can then just step forward by the case size thereafter */ refersToYoung = followMaybeObjRefInClosedPICAt(pc - 4 /* jumpLongByteSize */); /* Next we check the potential potential method oop load for each case. */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (followMaybeObjRefInClosedPICAt((pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)) { refersToYoung = 1; } pc += cPICCaseSize; } return refersToYoung; } /* Free machine-code methods whose compiled methods are unmarked and open PICs whose selectors are not marked, and closed PICs that refer to unmarked objects. */ /* Cogit>>#freeUnmarkedMachineCode */ void freeUnmarkedMachineCode(void) { CogMethod *cogMethod; sqInt freedMethod; freedMethod = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (!(isMarked((cogMethod->methodObject))))) { freedMethod = 1; freeMethod(cogMethod); } if ((((cogMethod->cmType)) == CMOpenPIC) && ((!(isImmediate((cogMethod->selector)))) && (!(isMarked((cogMethod->selector)))))) { freedMethod = 1; freeMethod(cogMethod); } if ((((cogMethod->cmType)) == CMClosedPIC) && (closedPICRefersToUnmarkedObject(cogMethod))) { freedMethod = 1; freeMethod(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedMethod) { unlinkSendsToFree(); } } /* Call ceSendMustBeBooleanTo: via the relevant trampoline. */ /* Cogit>>#genCallMustBeBooleanFor: */ static AbstractInstruction * NoDbgRegParms genCallMustBeBooleanFor(sqInt boolean) { AbstractInstruction *abstractInstruction; sqInt callTarget; /* begin CallRT: */ callTarget = (boolean == (falseObject()) ? ceSendMustBeBooleanAddFalseTrampoline : ceSendMustBeBooleanAddTrueTrampoline); /* begin annotateCall: */ abstractInstruction = genoperand(Call, callTarget); (abstractInstruction->annotation = IsRelativeCall); return abstractInstruction; } /* Cogit>>#genCheckForInterruptsTrampoline */ static sqInt genCheckForInterruptsTrampoline(void) { sqInt address; zeroOpcodeIndex(); /* begin MoveR:Aw: */ address = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, LinkReg, address)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceCheckForInterrupts, "ceCheckForInterruptsTrampoline", 0, null, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Cogit>>#genConditionalBranch:operand: */ static AbstractInstruction * NoDbgRegParms genConditionalBranchoperand(sqInt opcode, sqInt operandOne) { AbstractInstruction *branch; /* begin noteFollowingConditionalBranch: */ branch = genoperand(opcode, operandOne); return branch; } /* 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. BEFORE AFTER (stacks grow down) whatever stackPointer -> whatever target address => reg1 = reg1val, etc reg1val pc = target address reg2val stackPointer -> reg3val */ /* Cogit>>#genEnilopmartFor:and:and:forCall:called: */ static void (*genEnilopmartForandandforCallcalled(sqInt regArg1, sqInt regArg2OrNone, sqInt regArg3OrNone, sqInt forCall, char *trampolineName))(void) { AbstractInstruction *anInstruction; sqInt endAddress; sqInt enilopmart; sqInt quickConstant; sqInt size; zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } genLoadStackPointers(backEnd); if (regArg3OrNone != NoReg) { genoperand(PopR, regArg3OrNone); } if (regArg2OrNone != NoReg) { genoperand(PopR, regArg2OrNone); } genoperand(PopR, regArg1); genEnilopmartReturn(forCall); computeMaximumSizes(); size = generateInstructionsAt(methodZoneBase); endAddress = outputInstructionsAt(methodZoneBase); assert((methodZoneBase + size) == endAddress); enilopmart = methodZoneBase; methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(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. At the point the enilopmart enters machine code via a return instruction, any argument registers have been loaded with their values and the stack, if for call, looks like ret pc stackPointer -> target address and if not for call, looks like whatever stackPointer -> target address If forCall and running on a CISC, ret pc must be left on the stack. If forCall and running on a RISC, ret pc must be popped into LinkReg. In either case, target address must be removed from the stack and jumped/returned to. */ /* Cogit>>#genEnilopmartReturn: */ static void NoDbgRegParms genEnilopmartReturn(sqInt forCall) { if (forCall) { genoperand(PopR, RISCTempReg); genoperand(PopR, LinkReg); genoperand(JumpR, RISCTempReg); } else { genoperand(PopR, PCReg); } } /* Generate the routine that writes the current values of the C frame and stack pointers into variables. These are used to establish the C stack in trampolines back into the C run-time. This is a presumptuous quick hack for x86. It is presumptuous for two reasons. Firstly the system's frame and stack pointers may differ from those we use in generated code, e.g. on register-rich RISCs. Secondly the ABI may not support a simple frameless call as written here (for example 128-bit stack alignment on Mac OS X). */ /* Cogit>>#generateCaptureCStackPointers: */ static void NoDbgRegParms generateCaptureCStackPointers(sqInt captureFramePointer) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt fixupSize; sqInt opcodeSize; sqInt quickConstant; sqInt quickConstant1; sqInt startAddress; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 32; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; /* Must happen first; value may be used in accessing any of the following addresses */ startAddress = methodZoneBase; /* begin PushR: */ genoperand(PushR, VarBaseReg); /* begin MoveCq:R: */ quickConstant1 = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant1, VarBaseReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } if (captureFramePointer) { /* begin MoveR:Aw: */ address = cFramePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, FPReg, address)); } genoperandoperand(MoveRR, SPReg, TempReg); /* begin AddCq:R: */ quickConstant = 0 /* leafCallStackPointerDelta */ + BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin MoveR:Aw: */ address1 = cStackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin PopR: */ genoperand(PopR, VarBaseReg); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); flushICacheFromto(processor, ((usqInt)startAddress), ((usqInt)methodZoneBase)); recordGeneratedRunTimeaddress("ceCaptureCStackPointers", startAddress); ceCaptureCStackPointers = ((void (*)(void)) startAddress); } /* Generate the prototype ClosedPIC to determine how much space as full PIC takes. When we first allocate a closed PIC it only has one or two cases and we want to grow it. So we have to determine how big a full one is before hand. */ /* Cogit>>#generateClosedPICPrototype */ static void generateClosedPICPrototype(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; CogMethod *cPIC; AbstractInstruction * cPICEndOfCodeLabel; sqInt endAddress; AbstractInstruction * endCPICCase1; sqInt fixupSize; sqInt h; AbstractInstruction *jumpNext; sqInt jumpTarget; sqInt jumpTarget1; sqInt jumpTarget2; sqInt numArgs; sqInt opcode; sqInt opcodeSize; sqInt operandOne; sqInt wordConstant; sqInt wordConstant1; /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = MaxCPICCases * 9; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; (methodLabel->address = methodZoneBase); (methodLabel->dependent = null); /* begin compileClosedPICPrototype */ compilePICAbort((numArgs = 0)); /* At the end of the entry code we need to jump to the first case code, which is actually the last chunk. On each entension we must update this jump to move back one case. */ jumpNext = compileCPICEntry(); /* begin MoveUniqueCw:R: */ wordConstant1 = firstPrototypeMethodOop(); /* begin uniqueLiteral:forInstruction: */ anInstruction1 = genoperandoperand(MoveCwR, wordConstant1, SendNumArgsReg); assert(usesOutOfLineLiteral(anInstruction1)); (anInstruction1->dependent = allocateLiteral(wordConstant1)); /* begin JumpLong: */ jumpTarget1 = (((methodZoneBase + (youngReferrers())) / 2) - 13262352) + 13262352; genoperand(JumpLong, jumpTarget1); endCPICCase0 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); for (h = 1; h < MaxCPICCases; h += 1) { if (h == (MaxCPICCases - 1)) { jmpTarget(jumpNext, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin MoveUniqueCw:R: */ wordConstant = (subsequentPrototypeMethodOop()) + h; /* begin uniqueLiteral:forInstruction: */ anInstruction = genoperandoperand(MoveCwR, wordConstant, SendNumArgsReg); assert(usesOutOfLineLiteral(anInstruction)); (anInstruction->dependent = allocateLiteral(wordConstant)); /* begin gen:literal:operand: */ opcode = CmpCwR; checkLiteralforInstruction(3133021973U + h, genoperandoperand(opcode, 3133021973U + h, TempReg)); /* begin JumpLongZero: */ jumpTarget = ((((methodZoneBase + (youngReferrers())) / 2) - 13262352) + 13262352) + (h * 16); genConditionalBranchoperand(JumpLongZero, ((sqInt)jumpTarget)); if (h == 1) { endCPICCase1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } } /* begin gen:literal:operand: */ operandOne = (methodLabel->address); checkLiteralforInstruction(operandOne, genoperandoperand(MoveCwR, operandOne, ClassReg)); /* begin JumpLong: */ jumpTarget2 = cPICMissTrampolineFor(numArgs); genoperand(JumpLong, jumpTarget2); cPICEndOfCodeLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); dumpLiterals(0); computeMaximumSizes(); cPIC = ((CogMethod *) methodZoneBase); closedPICSize = (sizeof(CogMethod)) + (generateInstructionsAt(methodZoneBase + (sizeof(CogMethod)))); endAddress = outputInstructionsAt(methodZoneBase + (sizeof(CogMethod))); assert((methodZoneBase + closedPICSize) == endAddress); firstCPICCaseOffset = ((endCPICCase0->address)) - methodZoneBase; cPICEndOfCodeOffset = ((cPICEndOfCodeLabel->address)) - methodZoneBase; cPICCaseSize = ((endCPICCase1->address)) - ((endCPICCase0->address)); cPICEndSize = closedPICSize - (((MaxCPICCases - 1) * cPICCaseSize) + firstCPICCaseOffset); closedPICSize = roundUpLength(closedPICSize); assert(((picInterpretAbort->address)) == (((methodLabel->address)) + (picInterpretAbortOffset()))); assert((expectedClosedPICPrototype(cPIC)) == 0); storeLiteralbeforeFollowingAddress(backEnd, 0, ((endCPICCase0->address)) - 4 /* jumpLongByteSize */); methodZoneBase = alignUptoRoutineBoundary(endAddress); cPICPrototype = cPIC; } /* We handle jump sizing simply. First we make a pass that asks each instruction to compute its maximum size. Then we make a pass that sizes jumps based on the maxmimum sizes. Then we make a pass that fixes up jumps. When fixing up a jump the jump is not allowed to choose a smaller offset but must stick to the size set in the second pass. */ /* Cogit>>#generateCogFullBlock */ static CogMethod * generateCogFullBlock(void) { sqInt codeSize; usqIntptr_t headerSize; sqInt mapSize; CogMethod *method; sqInt result; usqInt startAddress; sqInt totalSize; headerSize = sizeof(CogMethod); (methodLabel->address = freeStart()); computeMaximumSizes(); concretizeAt(methodLabel, freeStart()); codeSize = generateInstructionsAt(((methodLabel->address)) + headerSize); mapSize = generateMapAtstart(null, ((methodLabel->address)) + cbNoSwitchEntryOffset); totalSize = roundUpLength((headerSize + codeSize) + mapSize); if (totalSize > MaxMethodSize) { return ((CogMethod *) MethodTooBig); } startAddress = allocate(totalSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } assert((startAddress + cbEntryOffset) == ((fullBlockEntry->address))); assert((startAddress + cbNoSwitchEntryOffset) == ((fullBlockNoContextSwitchEntry->address))); result = outputInstructionsAt(startAddress + headerSize); assert(((startAddress + headerSize) + codeSize) == result); padIfPossibleWithStopsFromto(backEnd, result, ((startAddress + totalSize) - mapSize) - 1); generateMapAtstart((startAddress + totalSize) - 1, startAddress + cbNoSwitchEntryOffset); flag("TOCHECK"); method = fillInMethodHeadersizeselector(((CogMethod *) startAddress), totalSize, nilObject()); (method->cpicHasMNUCaseOrCMIsFullBlock = 1); if (!(postCompileHook == null)) { postCompileHook(method); postCompileHook = null; } return method; } /* We handle jump sizing simply. First we make a pass that asks each instruction to compute its maximum size. Then we make a pass that sizes jumps based on the maxmimum sizes. Then we make a pass that fixes up jumps. When fixing up a jump the jump is not allowed to choose a smaller offset but must stick to the size set in the second pass. */ /* Cogit>>#generateCogMethod: */ static CogMethod * NoDbgRegParms generateCogMethod(sqInt selector) { sqInt codeSize; usqIntptr_t headerSize; sqInt mapSize; CogMethod *method; sqInt result; usqInt startAddress; sqInt totalSize; headerSize = sizeof(CogMethod); (methodLabel->address = freeStart()); computeMaximumSizes(); concretizeAt(methodLabel, freeStart()); codeSize = generateInstructionsAt(((methodLabel->address)) + headerSize); mapSize = generateMapAtstart(null, ((methodLabel->address)) + cmNoCheckEntryOffset); totalSize = roundUpLength((headerSize + codeSize) + mapSize); if (totalSize > MaxMethodSize) { return ((CogMethod *) MethodTooBig); } startAddress = allocate(totalSize); if (startAddress == 0) { return ((CogMethod *) InsufficientCodeSpace); } assert((startAddress + cmEntryOffset) == ((entry->address))); assert((startAddress + cmNoCheckEntryOffset) == ((noCheckEntry->address))); result = outputInstructionsAt(startAddress + headerSize); assert(((startAddress + headerSize) + codeSize) == result); padIfPossibleWithStopsFromto(backEnd, result, ((startAddress + totalSize) - mapSize) - 1); generateMapAtstart((startAddress + totalSize) - 1, startAddress + cmNoCheckEntryOffset); fillInBlockHeadersAt(startAddress); method = fillInMethodHeadersizeselector(((CogMethod *) startAddress), totalSize, selector); if (!(postCompileHook == null)) { postCompileHook(method); postCompileHook = null; } return method; } /* Generate the method map at addressrNull (or compute it if addressOrNull is null). Answer the length of the map in byes. Each entry in the map is in two parts. In the least signficant bits are a displacement of how far from the start or previous entry, unless it is an IsAnnotationExtension byte, in which case those bits are the extension. In the most signficant bits are the type of annotation at the point reached. A null byte ends the map. */ /* Cogit>>#generateMapAt:start: */ static sqInt NoDbgRegParms generateMapAtstart(usqInt addressOrNull, usqInt startAddress) { unsigned char annotation; sqInt delta; sqInt i; AbstractInstruction *instruction; sqInt length; usqInt location; sqInt mapEntry; sqInt maxDelta; usqInt mcpc; length = 0; location = startAddress; for (i = 0; i < opcodeIndex; i += 1) { instruction = abstractInstructionAt(i); annotation = (instruction->annotation); if (!(annotation == null)) { /* begin assertValidAnnotation:for: */ assert((annotation != (getIsObjectReference())) || (((instruction->opcode)) == Literal)); mcpc = (((instruction->opcode)) == Literal ? (instruction->address) : ((instruction->address)) + ((instruction->machineCodeSize))); while (((delta = (mcpc - location) / 4 /* codeGranularity */)) > DisplacementMask) { maxDelta = (((((delta < MaxX2NDisplacement) ? delta : MaxX2NDisplacement)) | DisplacementMask) - DisplacementMask); assert((((usqInt) maxDelta) >> AnnotationShift) <= DisplacementMask); if (!(addressOrNull == null)) { /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, (((usqInt) maxDelta) >> AnnotationShift) + DisplacementX2N); } location += maxDelta * 4 /* codeGranularity */; length += 1; } if (!(addressOrNull == null)) { mapEntry = delta + (((sqInt)((usqInt)((((annotation < IsSendCall) ? annotation : IsSendCall))) << AnnotationShift))); /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, mapEntry); } location += delta * 4 /* codeGranularity */; length += 1; if (annotation > IsSendCall) { /* Add the necessary IsAnnotationExtension */ if (!(addressOrNull == null)) { mapEntry = (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift))) + (annotation - IsSendCall); /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, mapEntry); } length += 1; } } } if (!(addressOrNull == null)) { /* begin addToMap:instruction:byte:at:for: */ byteAtput(addressOrNull - length, MapEnd); } return length + 1; } /* Generate the prototype ClosedPIC to determine how much space as full PIC takes. When we first allocate a closed PIC it only has one or two cases and we want to grow it. So we have to determine how big a full one is before hand. */ /* stack allocate the various collections so that they are effectively garbage collected on return. */ /* Cogit>>#generateOpenPICPrototype */ static void generateOpenPICPrototype(void) { sqInt codeSize; sqInt fixupSize; sqInt mapSize; sqInt opcodeSize; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 100; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; (methodLabel->address = methodZoneBase); (methodLabel->dependent = null); compileOpenPICnumArgs(specialSelector(0), 2 /* numRegArgs */); computeMaximumSizes(); concretizeAt(methodLabel, methodZoneBase); codeSize = generateInstructionsAt(methodZoneBase + (sizeof(CogMethod))); mapSize = generateMapAtstart(null, methodZoneBase + cmNoCheckEntryOffset); openPICSize = (roundUpLength((sizeof(CogMethod)) + codeSize)) + (roundUpLength(mapSize)); } /* Generate the run-time entries at the base of the native code zone and update the base. */ /* Cogit>>#generateRunTimeTrampolines */ static void generateRunTimeTrampolines(void) { ceSendMustBeBooleanAddFalseTrampoline = genMustBeBooleanTrampolineForcalled(falseObject(), "ceSendMustBeBooleanAddFalseTrampoline"); ceSendMustBeBooleanAddTrueTrampoline = genMustBeBooleanTrampolineForcalled(trueObject(), "ceSendMustBeBooleanAddTrueTrampoline"); ceNonLocalReturnTrampoline = genNonLocalReturnTrampoline(); /* Neither of the context inst var access trampolines save registers. Their operation could cause arbitrary update of stack frames, so the assumption is that callers flush the stack before calling the context inst var access trampolines, and that everything except the result is dead afterwards. */ ceCheckForInterruptTrampoline = genCheckForInterruptsTrampoline(); ceFetchContextInstVarTrampoline = genTrampolineForcalledargargresult(ceContextinstVar, "ceFetchContextInstVarTrampoline", ReceiverResultReg, SendNumArgsReg, SendNumArgsReg); ceStoreContextInstVarTrampoline = genTrampolineForcalledargargargresult(ceContextinstVarvalue, "ceStoreContextInstVarTrampoline", ReceiverResultReg, SendNumArgsReg, ClassReg, ReceiverResultReg); /* These two are unusual; they are reached by return instructions. */ ceCannotResumeTrampoline = genTrampolineForcalled(ceCannotResume, "ceCannotResumeTrampoline"); ceBaseFrameReturnTrampoline = genReturnTrampolineForcalledarg(ceBaseFrameReturn, "ceBaseFrameReturnTrampoline", ReceiverResultReg); ceReturnToInterpreterTrampoline = genReturnTrampolineForcalledarg(ceReturnToInterpreter, "ceReturnToInterpreterTrampoline", ReceiverResultReg); ceMallocTrampoline = genTrampolineForcalledargresult(ceMalloc, "ceMallocTrampoline", ReceiverResultReg, TempReg); ceFreeTrampoline = genTrampolineForcalledarg(ceFree, "ceFreeTrampoline", ReceiverResultReg); } /* Generate a routine ceCaptureCStackPointers that will capture the C stack pointer, and, if it is in use, the C frame pointer. These are used in trampolines to call run-time routines in the interpreter from machine-code. */ /* Cogit>>#generateStackPointerCapture */ static void generateStackPointerCapture(void) { sqInt oldMethodZoneBase; sqInt oldTrampolineTableIndex; /* For the benefit of the following assert, assume the minimum at first. */ cFramePointerInUse = 0; assertCStackWellAligned(); oldMethodZoneBase = methodZoneBase; oldTrampolineTableIndex = trampolineTableIndex; generateCaptureCStackPointers(1); ceCaptureCStackPointers(); if (!((cFramePointerInUse = isCFramePointerInUse()))) { methodZoneBase = oldMethodZoneBase; trampolineTableIndex = oldTrampolineTableIndex; generateCaptureCStackPointers(0); } assertCStackWellAligned(); } /* Generate the run-time entries and exits at the base of the native code zone and update the base. Read the class-side method trampolines for documentation on the various trampolines */ /* Cogit>>#generateTrampolines */ static void generateTrampolines(void) { sqInt fixupSize; sqInt methodZoneStart; sqInt opcodeSize; methodZoneStart = methodZoneBase; (methodLabel->address = methodZoneStart); /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 80; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; hasYoungReferent = 0; generateSendTrampolines(); generateMissAbortTrampolines(); generateObjectRepresentationTrampolines(); generateRunTimeTrampolines(); generateEnilopmarts(); generateTracingTrampolines(); recordGeneratedRunTimeaddress("methodZoneBase", methodZoneBase); flushICacheFromto(processor, ((usqInt)methodZoneStart), ((usqInt)methodZoneBase)); } /* Cogit>>#generatorForPC: */ static BytecodeDescriptor * NoDbgRegParms generatorForPC(sqInt pc) { return generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); } /* Generate a routine that answers the stack pointer immedately after a leaf call, used for checking stack pointer alignment. */ /* Cogit>>#genGetLeafCallStackPointer */ static void genGetLeafCallStackPointer(void) { sqInt fixupSize; sqInt opcodeSize; sqInt startAddress; /* begin allocateOpcodes:bytecodes: */ numAbstractOpcodes = 4; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; startAddress = methodZoneBase; /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, R0); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceGetFP", startAddress); ceGetFP = ((usqIntptr_t (*)(void)) startAddress); startAddress = methodZoneBase; zeroOpcodeIndex(); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, R0); genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceGetSP", startAddress); ceGetSP = ((usqIntptr_t (*)(void)) startAddress); } /* Generate the abort for a PIC. This abort performs either a call of ceInterpretMethodFromPIC:receiver: to handle invoking an uncogged target or a call of ceMNUFromPICMNUMethod:receiver: to handle an MNU dispatch in a closed PIC. It distinguishes the two by testing ClassReg. If the register is zero then this is an MNU. This poses a problem in 32-bit Spur, where zero is the cache tag for immediate characters (tag pattern 2r10) because SmallIntegers have tag patterns 2r11 and 2r01, so anding with 1 reduces these to 0 & 1. We solve the ambiguity by patching send sites with a 0 cache tag to open PICs instead of closed PICs. */ /* Cogit>>#genInnerPICAbortTrampoline: */ static sqInt NoDbgRegParms genInnerPICAbortTrampoline(char *name) { AbstractInstruction *anInstruction; AbstractInstruction *jumpMNUCase; /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, 0 /* picAbortDiscriminatorValue */, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0 /* picAbortDiscriminatorValue */)); } jumpMNUCase = genConditionalBranchoperand(JumpZero, ((sqInt)0)); compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceInterpretMethodFromPICreceiver, 2, SendNumArgsReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 0, NoReg); jmpTarget(jumpMNUCase, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceMNUFromPICMNUMethodreceiver, name, 2, SendNumArgsReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Cogit>>#genLoadCStackPointersForPrimCall */ static sqInt genLoadCStackPointersForPrimCall(void) { sqInt address; sqInt address1; sqInt address2; AbstractInstruction *anInstruction; if (debugPrimCallStackOffset == 0) { /* begin MoveAw:R: */ address = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, SPReg)); } else { /* begin MoveAw:R: */ address1 = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, debugPrimCallStackOffset, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(debugPrimCallStackOffset)); } genoperandoperand(MoveRR, TempReg, SPReg); } if (cFramePointerInUse) { /* begin MoveAw:R: */ address2 = cFramePointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address2, genoperandoperand(MoveAwR, address2, FPReg)); } return 0; } /* The in-line cache for a send is implemented as a constant load into ClassReg. We always use a 32-bit load, even in 64-bits. In the initial (unlinked) state the in-line cache is notionally loaded with the selector. But since in 64-bits an arbitrary selector oop won't fit in a 32-bit constant load, we instead load the cache with the selector's index, either into the literal frame of the current method, or into the special selector array. Negative values are 1-relative indices into the special selector array. When a send is linked, the load of the selector, or selector index, is overwritten with a load of the receiver's class, or class tag. Hence, the 64-bit VM is currently constrained to use class indices as cache tags. If out-of-line literals are used, distinct caches /must not/ share acche locations, for if they do, send cacheing will be confused by the sharing. Hence we use the MoveUniqueC32:R: instruction that will not share literal locations. */ /* Cogit>>#genLoadInlineCacheWithSelector: */ static void NoDbgRegParms genLoadInlineCacheWithSelector(sqInt selectorIndex) { AbstractInstruction *anInstruction; sqInt cacheValue; sqInt opcode; sqInt selector; assert((selectorIndex < 0 ? (((-selectorIndex) >= 1) && ((-selectorIndex) <= (numSpecialSelectors()))) : ((selectorIndex >= 0) && (selectorIndex <= ((literalCountOf(methodObj)) - 1))))); selector = (selectorIndex < 0 ? specialSelector(-1 - selectorIndex) : getLiteral(selectorIndex)); assert(addressCouldBeOop(selector)); if (isYoung(selector)) { hasYoungReferent = 1; } cacheValue = selector; /* begin gen:uniqueLiteral:operand: */ opcode = MoveCwR; /* begin uniqueLiteral:forInstruction: */ anInstruction = genoperandoperand(opcode, cacheValue, ClassReg); assert(usesOutOfLineLiteral(anInstruction)); (anInstruction->dependent = allocateLiteral(cacheValue)); } /* Cogit>>#genNonLocalReturnTrampoline */ static sqInt genNonLocalReturnTrampoline(void) { sqInt address; zeroOpcodeIndex(); /* begin MoveR:Aw: */ address = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, LinkReg, address)); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceNonLocalReturn, "ceNonLocalReturnTrampoline", 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Generate a trampoline for a routine used as a return address, that has one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genReturnTrampolineFor:called:arg: */ static sqInt NoDbgRegParms genReturnTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 0); } /* If the client requires, then on an ARM-like RISC processor, the return address needs to be pushed to the stack so that the interpreter sees the same stack layout as on CISC. */ /* Cogit>>#genSmalltalkToCStackSwitch: */ static sqInt NoDbgRegParms genSmalltalkToCStackSwitch(sqInt pushLinkReg) { if (pushLinkReg) { genoperand(PushR, LinkReg); } genSaveStackPointers(backEnd); if (cFramePointerInUse) { genLoadCStackPointers(backEnd); } else { genLoadCStackPointer(backEnd); } return 0; } /* Generate a trampoline with no arguments */ /* Cogit>>#genTrampolineFor:called: */ static sqInt NoDbgRegParms genTrampolineForcalled(void *aRoutine, char *aString) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 0, null, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 0); } /* Generate a trampoline with one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg: */ static sqInt NoDbgRegParms genTrampolineForcalledarg(void *aRoutine, char *aString, sqInt regOrConst0) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 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. */ /* Cogit>>#genTrampolineFor:called:arg:arg:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 3, regOrConst0, regOrConst1, regOrConst2, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with two arguments. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:arg:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledargargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 2, regOrConst0, regOrConst1, null, null, regMask, 1, NoReg, 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. */ /* Cogit>>#genTrampolineFor:called:arg:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 2, regOrConst0, regOrConst1, null, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with one argument. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledargregsToSave(void *aRoutine, char *aString, sqInt regOrConst0, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, regMask, 1, NoReg, 0); } /* Generate a trampoline with one argument that answers a result. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:arg:result: */ static sqInt NoDbgRegParms genTrampolineForcalledargresult(void *aRoutine, char *aString, sqInt regOrConst0, sqInt resultReg) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 1, regOrConst0, null, null, null, 0 /* emptyRegisterMask */, 1, resultReg, 0); } /* Generate a trampoline with up to four arguments. Generate either a call or a jump to aRoutineOrNil as requested by callJumpBar. If generating a call and resultRegOrNone is not NoReg pass the C result back in resultRegOrNone. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* Cogit>>#genTrampolineFor:called:numArgs:arg:arg:arg:arg:regsToSave:pushLinkReg:resultReg:appendOpcodes: */ static sqInt NoDbgRegParms genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(void *aRoutine, char *trampolineName, sqInt numArgs, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3, sqInt regMask, sqInt pushLinkReg, sqInt resultRegOrNone, sqInt appendBoolean) { sqInt startAddress; startAddress = methodZoneBase; if (!appendBoolean) { zeroOpcodeIndex(); } compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(aRoutine, numArgs, regOrConst0, regOrConst1, regOrConst2, regOrConst3, regMask, pushLinkReg, resultRegOrNone); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress(trampolineName, startAddress); recordRunTimeObjectReferences(); return startAddress; } /* Generate a trampoline with no arguments */ /* Cogit>>#genTrampolineFor:called:regsToSave: */ static sqInt NoDbgRegParms genTrampolineForcalledregsToSave(void *aRoutine, char *aString, sqInt regMask) { return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 0, null, null, null, null, regMask, 1, NoReg, 0); } /* <Integer> */ /* Cogit>>#gen: */ static AbstractInstruction * NoDbgRegParms gen(sqInt opcode) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand: */ static AbstractInstruction * NoDbgRegParms genoperand(sqInt opcode, sqInt operand) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operand; return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand:operand: */ static AbstractInstruction * NoDbgRegParms genoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operandOne; ((abstractInstruction->operands))[1] = operandTwo; return abstractInstruction; } /* <Integer> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* <Integer|CogAbstractInstruction> */ /* Cogit>>#gen:operand:operand:operand: */ static AbstractInstruction * NoDbgRegParms genoperandoperandoperand(sqInt opcode, sqInt operandOne, sqInt operandTwo, sqInt operandThree) { AbstractInstruction *abstractInstruction; assert(opcodeIndex < numAbstractOpcodes); abstractInstruction = abstractInstructionAt(opcodeIndex); opcodeIndex += 1; (abstractInstruction->opcode = opcode); ((abstractInstruction->operands))[0] = operandOne; ((abstractInstruction->operands))[1] = operandTwo; ((abstractInstruction->operands))[2] = operandThree; return abstractInstruction; } /* Cogit>>#getLiteral: */ static sqInt NoDbgRegParms getLiteral(sqInt litIndex) { if (maxLitIndex < litIndex) { maxLitIndex = litIndex; } return literalofMethod(litIndex, methodObj); } /* Access for the literal manager. */ /* Cogit>>#getOpcodeIndex */ static sqInt getOpcodeIndex(void) { return opcodeIndex; } /* Cogit>>#incrementUsageOfTargetIfLinkedSend:mcpc:ignored: */ static sqInt NoDbgRegParms incrementUsageOfTargetIfLinkedSendmcpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; if (annotation >= IsSendCall) { assert(annotation != IsNSSendCall); entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmUsageCount)) < (CMMaxUsageCount / 2)) { (targetMethod1->cmUsageCount = ((targetMethod1->cmUsageCount)) + 1); } } } return 0; } /* Answer the value to put in an inline-cache that is being loaded with the selector. Usually this is simply the selector, but in 64-bits the cache is only 32-bits wide and so the cache is loaded with the index of the selector. */ /* Cogit>>#indexForSelector:in:at: */ static sqInt NoDbgRegParms indexForSelectorinat(sqInt selector, CogMethod *cogMethod, sqInt mcpc) { sqInt i; sqInt iLimiT; sqInt methodOop; assert(((((usqInt)mcpc)) > (((usqInt)cogMethod))) && (mcpc < ((((usqInt)cogMethod)) + ((cogMethod->blockSize))))); for (i = 0; i < NumSpecialSelectors; i += 1) { if (selector == (specialSelector(i))) { return -1 - i; } } /* Then search the method's literal frame... open code fetchPointer:ofObject: for speed... */ methodOop = (cogMethod->methodObject); for (i = LiteralStart, iLimiT = (literalCountOfMethodHeader((cogMethod->methodHeader))); i <= iLimiT; i += 1) { if ((longAt(((i * BytesPerOop) + BaseHeaderSize) + methodOop)) == selector) { assert(selector == (literalofMethod(i - 1, methodOop))); return i - 1; } } error("could not find selector in method when unlinking send site"); return 0; } /* Answer a usage count that reflects likely long-term usage. */ /* Cogit>>#initialClosedPICUsageCount */ static sqInt initialClosedPICUsageCount(void) { return CMMaxUsageCount / 2; } /* Cogit>>#initializeBackend */ static void initializeBackend(void) { AbstractInstruction *existingInst; sqInt i; sqInt iLimiT; AbstractInstruction *newInst; AbstractInstruction *newLiterals; (methodLabel->machineCodeSize = 0); (methodLabel->opcode = Label); ((methodLabel->operands))[0] = 0; ((methodLabel->operands))[1] = 0; assert(((registerMaskFor(VarBaseReg)) & CallerSavedRegisterMask) == 0); /* begin allocateLiterals: */ if (4 > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(4, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i = 0; i < nextLiteralIndex; i += 1) { existingInst = literalInstructionAt(i); newInst = (&(newLiterals[i])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i = 0, iLimiT = (opcodeIndex - 1); i <= iLimiT; i += 1) { existingInst = abstractInstructionAt(i); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = 4; } /* begin resetLiterals */ /* an impossibly high value */ firstOpcodeIndex = 1U << 16; nextLiteralIndex = (lastDumpedLiteralIndex = 0); } /* Cogit>>#initializeCodeZoneFrom:upTo: */ void initializeCodeZoneFromupTo(sqInt startAddress, sqInt endAddress) { sqInt fixupSize; sqInt numberOfAbstractOpcodes; sqInt opcodeSize; sqInt startAddress1; initializeBackend(); stopsFromto(backEnd, startAddress, endAddress - 1); sqMakeMemoryExecutableFromTo(startAddress, endAddress); codeBase = (methodZoneBase = startAddress); minValidCallAddress = (((((codeBase < (interpretAddress())) ? codeBase : (interpretAddress()))) < (primitiveFailAddress())) ? (((codeBase < (interpretAddress())) ? codeBase : (interpretAddress()))) : (primitiveFailAddress())); manageFromto(methodZoneBase, endAddress); /* begin maybeGenerateCheckFeatures */ /* begin maybeGenerateICacheFlush */ /* begin generateVMOwnerLockFunctions */ # if COGMTVM /* begin allocateOpcodes:bytecodes: */ numberOfAbstractOpcodes = numLowLevelLockOpcodes(backEnd); numAbstractOpcodes = numberOfAbstractOpcodes; opcodeSize = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupSize = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; abstractOpcodes = alloca(opcodeSize + fixupSize); bzero(abstractOpcodes, opcodeSize + fixupSize); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeSize)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; zeroOpcodeIndex(); startAddress1 = methodZoneBase; generateLowLevelTryLock(backEnd, vmOwnerLockAddress()); outputInstructionsForGeneratedRuntimeAt(startAddress1); recordGeneratedRunTimeaddress("ceTryLockVMOwner", startAddress1); ceTryLockVMOwner = ((usqIntptr_t (*)(void)) startAddress1); zeroOpcodeIndex(); initialPC = 0; endPC = numAbstractOpcodes - 1; startAddress1 = methodZoneBase; generateLowLevelUnlock(backEnd, vmOwnerLockAddress()); outputInstructionsForGeneratedRuntimeAt(startAddress1); recordGeneratedRunTimeaddress("ceUnlockVMOwner", startAddress1); ceUnlockVMOwner = ((void (*)(void)) startAddress1); # endif /* COGMTVM */ genGetLeafCallStackPointer(); generateStackPointerCapture(); generateTrampolines(); computeEntryOffsets(); computeFullBlockEntryOffsets(); generateClosedPICPrototype(); manageFromto(methodZoneBase, endAddress); generateOpenPICPrototype(); } /* Answer a usage count that reflects likely long-term usage. Answer 1 for non-primitives or quick primitives (inst var accessors), 2 for methods with interpreter primitives, and 3 for compiled primitives. */ /* Cogit>>#initialMethodUsageCount */ static sqInt initialMethodUsageCount(void) { if ((primitiveIndex == 1) || (isQuickPrimitiveIndex(primitiveIndex))) { return 1; } if (!(primitiveGeneratorOrNil())) { return 2; } return 3; } /* Answer a usage count that reflects likely long-term usage. */ /* Cogit>>#initialOpenPICUsageCount */ static sqInt initialOpenPICUsageCount(void) { return CMMaxUsageCount - 1; } /* Answer the value to put in an inline-cache that is being loaded with the selector. Usually this is simply the selector, but in 64-bits the cache is only 32-bits wide and so the cache is loaded with the index of the selector. */ /* Cogit>>#inlineCacheValueForSelector:in:at: */ static sqInt NoDbgRegParms inlineCacheValueForSelectorinat(sqInt selector, CogMethod *aCogMethod, sqInt mcpc) { return selector; } /* Cogit>>#inverseBranchFor: */ static sqInt NoDbgRegParms 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; } /* See Cogit class>>initializeAnnotationConstants */ /* Cogit>>#isPCMappedAnnotation: */ static sqInt NoDbgRegParms isPCMappedAnnotation(sqInt annotation) { return annotation >= HasBytecodePC; } /* Cogit>>#isPCWithinMethodZone: */ sqInt isPCWithinMethodZone(void *address) { return (((((usqInt)address)) >= methodZoneBase) && ((((usqInt)address)) <= (freeStart()))); } /* Answer if the instruction preceding retpc is a call instruction. */ /* Cogit>>#isSendReturnPC: */ sqInt isSendReturnPC(sqInt retpc) { sqInt target; if (!(isCallPrecedingReturnPC(backEnd, retpc))) { return 0; } target = callTargetFromReturnAddress(backEnd, retpc); return (((target >= firstSend) && (target <= lastSend))) || (((target >= methodZoneBase) && (target <= (freeStart())))); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPEqual(void *jumpTarget) { /* begin genJumpFPEqual: */ return genoperand(JumpFPEqual, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPGreaterOrEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPGreaterOrEqual(void *jumpTarget) { /* begin genJumpFPGreaterOrEqual: */ return genoperand(JumpFPGreaterOrEqual, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPGreater: */ static AbstractInstruction * NoDbgRegParms gJumpFPGreater(void *jumpTarget) { /* begin genJumpFPGreater: */ return genoperand(JumpFPGreater, ((sqInt)jumpTarget)); } /* Floating-point jumps are a little weird on some processors. Defer to the backEnd to allow it to generate any special code it may need to. */ /* Cogit>>#JumpFPNotEqual: */ static AbstractInstruction * NoDbgRegParms gJumpFPNotEqual(void *jumpTarget) { /* begin genJumpFPNotEqual: */ return genoperand(JumpFPNotEqual, ((sqInt)jumpTarget)); } /* Cogit>>#LogicalShiftLeftCq:R: */ static AbstractInstruction * NoDbgRegParms gLogicalShiftLeftCqR(sqInt quickConstant, sqInt reg) { return genoperandoperand(LogicalShiftLeftCqR, quickConstant, reg); } /* Cogit>>#lastOpcode */ static AbstractInstruction * lastOpcode(void) { assert(opcodeIndex > 0); return abstractInstructionAt(opcodeIndex - 1); } /* Cogit>>#linkSendAt:in:to:offset:receiver: */ void linkSendAtintooffsetreceiver(sqInt callSiteReturnAddress, CogMethod *sendingMethod, CogMethod *targetMethod, sqInt theEntryOffset, sqInt receiver) { sqInt address; sqInt extent; sqInt inlineCacheTag; assert((theEntryOffset == cmEntryOffset) || (theEntryOffset == cmNoCheckEntryOffset)); assert(((callSiteReturnAddress >= methodZoneBase) && (callSiteReturnAddress <= (freeStart())))); inlineCacheTag = (theEntryOffset == cmNoCheckEntryOffset ? (targetMethod->selector) : inlineCacheTagForInstance(receiver)); address = (((sqInt)targetMethod)) + theEntryOffset; extent = rewriteInlineCacheAttagtarget(backEnd, callSiteReturnAddress, inlineCacheTag, address); flushICacheFromto(processor, (((usqInt)callSiteReturnAddress)) - extent, ((usqInt)callSiteReturnAddress)); } /* Cogit>>#loadBytesAndGetDescriptor */ static BytecodeDescriptor * loadBytesAndGetDescriptor(void) { BytecodeDescriptor *descriptor; byte0 = (fetchByteofObject(bytecodePC, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); loadSubsequentBytesForDescriptorat(descriptor, bytecodePC); return descriptor; } /* Cogit>>#loadSubsequentBytesForDescriptor:at: */ static void NoDbgRegParms loadSubsequentBytesForDescriptorat(BytecodeDescriptor *descriptor, sqInt pc) { if (((descriptor->numBytes)) > 1) { byte1 = fetchByteofObject(pc + 1, methodObj); if (((descriptor->numBytes)) > 2) { byte2 = fetchByteofObject(pc + 2, methodObj); if (((descriptor->numBytes)) > 3) { byte3 = fetchByteofObject(pc + 3, methodObj); if (((descriptor->numBytes)) > 4) { notYetImplemented(); } } } } } /* Cogit>>#MoveAw:R: */ static AbstractInstruction * NoDbgRegParms gMoveAwR(sqInt address, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, reg)); } /* Cogit>>#MoveCw:R: */ static AbstractInstruction * NoDbgRegParms gMoveCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, reg)); } /* Answer the address of the null byte at the end of the method map. */ /* Cogit>>#mapEndFor: */ static usqInt NoDbgRegParms mapEndFor(CogMethod *cogMethod) { usqInt end; end = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while ((byteAt(end)) != MapEnd) { end -= 1; assert(end > (firstMappedPCFor(cogMethod))); } return end; } /* Unlinking/GC/Disassembly support */ /* Cogit>>#mapFor:performUntil:arg: */ static sqInt NoDbgRegParms mapForperformUntilarg(CogMethod *cogMethod, sqInt (*functionSymbol)(sqInt annotation, char *mcpc, sqInt arg), sqInt arg) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; /* begin firstMappedPCFor: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = functionSymbol(annotation, (((char *) mcpc)), arg); if (result != 0) { return result; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* Remap all object references in the closed PIC. Answer if any references are young. Set codeModified if any modifications are made. */ /* Cogit>>#mapObjectReferencesInClosedPIC: */ static sqInt NoDbgRegParms mapObjectReferencesInClosedPIC(CogMethod *cPIC) { sqInt i; sqInt pc; sqInt refersToYoung; /* first we check the potential method oop load at the beginning of the CPIC */ pc = addressOfEndOfCaseinCPIC(1, cPIC); /* We find the end address of the cPICNumCases'th case and can then just step forward by the case size thereafter */ refersToYoung = remapMaybeObjRefInClosedPICAt(pc - 4 /* jumpLongByteSize */); /* Next we check the potential class ref in the compare instruction, and the potential method oop load for each case. */ pc = addressOfEndOfCaseinCPIC((cPIC->cPICNumCases), cPIC); for (i = 2; i <= ((cPIC->cPICNumCases)); i += 1) { if (remapMaybeObjRefInClosedPICAt((pc - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */)) { refersToYoung = 1; } pc += cPICCaseSize; } return refersToYoung; } /* Update all references to objects in the generated runtime. */ /* Cogit>>#mapObjectReferencesInGeneratedRuntime */ static void mapObjectReferencesInGeneratedRuntime(void) { sqInt i; sqInt literal; sqInt mappedLiteral; usqInt mcpc; for (i = 0; i < runtimeObjectRefIndex; i += 1) { mcpc = objectReferencesInRuntime[i]; literal = longAt(mcpc); mappedLiteral = remapObject(literal); if (mappedLiteral != literal) { /* begin storeLiteral:atAnnotatedAddress:using: */ longAtput(mcpc, mappedLiteral); codeModified = 1; } } } /* Update all references to objects in machine code for a become. Unlike incrementalGC or fullGC a method that does not refer to young may refer to young as a result of the become operation. Unlike incrementalGC or fullGC the reference from a Cog method to its methodObject *must not* change since the two are two halves of the same object. */ /* Cogit>>#mapObjectReferencesInMachineCodeForBecome */ static void mapObjectReferencesInMachineCodeForBecome(void) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; sqInt hasYoungObj; sqInt hasYoungObjPtr; usqInt map; sqInt mapByte; sqInt mcpc; sqInt remappedMethod; sqInt result; sqInt val; val = 0; hasYoungObj = 0; hasYoungObjPtr = ((sqInt)((&hasYoungObj))); codeModified = (freedPIC = 0); mapObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { assert(!hasYoungObj); if (((cogMethod->cmType)) != CMFree) { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->selector = remapOop((cogMethod->selector))); if (((cogMethod->cmType)) == CMClosedPIC) { if ((isYoung((cogMethod->selector))) || (mapObjectReferencesInClosedPIC(cogMethod))) { freedPIC = 1; freeMethod(cogMethod); } } else { if (isYoung((cogMethod->selector))) { hasYoungObj = 1; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); remappedMethod = remapOop((cogMethod->methodObject)); if (remappedMethod != ((cogMethod->methodObject))) { if (methodHasCogMethod(remappedMethod)) { error("attempt to become two cogged methods"); } if (!(withoutForwardingOnandwithsendToCogit((cogMethod->methodObject), remappedMethod, (cogMethod->cmUsesPenultimateLit), methodhasSameCodeAscheckPenultimate))) { error("attempt to become cogged method into different method"); } if ((rawHeaderOf((cogMethod->methodObject))) == (((sqInt)cogMethod))) { rawHeaderOfput((cogMethod->methodObject), (cogMethod->methodHeader)); (cogMethod->methodHeader = rawHeaderOf(remappedMethod)); (cogMethod->methodObject = remappedMethod); rawHeaderOfput(remappedMethod, ((sqInt)cogMethod)); } else { assert((noAssertMethodClassAssociationOf((cogMethod->methodObject))) == (nilObject())); (cogMethod->methodHeader = rawHeaderOf(remappedMethod)); (cogMethod->methodObject = remappedMethod); } } if (isYoung((cogMethod->methodObject))) { hasYoungObj = 1; } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), hasYoungObjPtr); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; if (hasYoungObj) { ensureInYoungReferrers(cogMethod); hasYoungObj = 0; } else { (cogMethod->cmRefersToYoung = 0); } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } pruneYoungReferrers(); if (freedPIC) { unlinkSendsToFree(); } if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)codeBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code for a full gc. Since the current (New)ObjectMemory GC makes everything old in a full GC a method not referring to young will not refer to young afterwards */ /* Cogit>>#mapObjectReferencesInMachineCodeForFullGC */ static void mapObjectReferencesInMachineCodeForFullGC(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; codeModified = 0; mapObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->selector = remapOop((cogMethod->selector))); if (((cogMethod->cmType)) == CMClosedPIC) { assert(!((cogMethod->cmRefersToYoung))); mapObjectReferencesInClosedPIC(cogMethod); } else { if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); (cogMethod->methodObject = remapOop((cogMethod->methodObject))); } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } pruneYoungReferrers(); if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)codeBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code for either a Spur scavenging gc or a Squeak V3 incremental GC. Avoid scanning all code by using the youngReferrers list. In a young gc a method referring to young may no longer refer to young, but a method not referring to young cannot and will not refer to young afterwards. */ /* Cogit>>#mapObjectReferencesInMachineCodeForYoungGC */ static void mapObjectReferencesInMachineCodeForYoungGC(void) { sqInt annotation; CogMethod *cogMethod; sqInt hasYoungObj; sqInt hasYoungObjPtr; usqInt map; sqInt mapByte; sqInt mcpc; usqInt pointer; sqInt result; sqInt val; val = 0; hasYoungObj = 0; hasYoungObjPtr = ((sqInt)((&hasYoungObj))); codeModified = 0; pointer = youngReferrers(); while (pointer < limitAddress) { assert(!hasYoungObj); cogMethod = ((CogMethod *) (longAt(pointer))); if (((cogMethod->cmType)) == CMFree) { assert(!((cogMethod->cmRefersToYoung))); } else { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if ((cogMethod->cmRefersToYoung)) { assert((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)); (cogMethod->selector = remapOop((cogMethod->selector))); if (isYoung((cogMethod->selector))) { hasYoungObj = 1; } if (((cogMethod->cmType)) == CMMethod) { assert(((cogMethod->objectHeader)) == (nullHeaderForMachineCodeMethod())); (cogMethod->methodObject = remapOop((cogMethod->methodObject))); if (isYoung((cogMethod->methodObject))) { hasYoungObj = 1; } } /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = remapIfObjectRefpchasYoung(annotation, (((char *) mcpc)), hasYoungObjPtr); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; if (hasYoungObj) { hasYoungObj = 0; } else { (cogMethod->cmRefersToYoung = 0); } } } pointer += BytesPerWord; } pruneYoungReferrers(); if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Update all references to objects in machine code. */ /* Cogit>>#mapObjectReferencesInMachineCode: */ void mapObjectReferencesInMachineCode(sqInt gcMode) { switch (gcMode) { case GCModeNewSpace: mapObjectReferencesInMachineCodeForYoungGC(); break; case GCModeFull: mapObjectReferencesInMachineCodeForFullGC(); break; case GCModeBecome: mapObjectReferencesInMachineCodeForBecome(); break; default: error("Case not found and no otherwise clause"); } if (!(asserta((freeStart()) <= (youngReferrers())))) { error("youngReferrers list overflowed"); } } /* Mark objects in machine-code of marked methods (or open PICs with marked selectors). */ /* Cogit>>#markAndTraceMachineCodeOfMarkedMethods */ void markAndTraceMachineCodeOfMarkedMethods(void) { sqInt annotation; sqInt annotation1; CogMethod *cogMethod; usqInt map; usqInt map1; sqInt mapByte; sqInt mapByte1; sqInt mcpc; sqInt mcpc1; sqInt result; sqInt result1; sqInt val; sqInt val1; val = 0; val1 = 0; if (leakCheckFullGC()) { asserta(allMachineCodeObjectReferencesValid()); } codeModified = 0; markAndTraceObjectReferencesInGeneratedRuntime(); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) { /* begin markAndTraceLiteralsIn: */ assert(((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) || ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector)))))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = markLiteralspcmethod(annotation, (((char *) mcpc)), (((sqInt)cogMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } if ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector))))) { /* begin markAndTraceLiteralsIn: */ assert(((((cogMethod->cmType)) == CMMethod) && (isMarked((cogMethod->methodObject)))) || ((((cogMethod->cmType)) == CMOpenPIC) && ((isImmediate((cogMethod->selector))) || (isMarked((cogMethod->selector)))))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc1 = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map1 = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte1 = byteAt(map1))) != MapEnd) { if (mapByte1 >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc1 += (mapByte1 & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation1 = ((usqInt) mapByte1) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte1 = byteAt(map1 - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation1 += mapByte1 & DisplacementMask; map1 -= 1; } result1 = markLiteralspcmethod(annotation1, (((char *) mcpc1)), (((sqInt)cogMethod))); if (result1 != 0) { goto l4; } } else { if (mapByte1 < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc1 += (((sqInt)((usqInt)((mapByte1 - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map1 -= 1; } l4: /* end mapFor:performUntil:arg: */; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (leakCheckFullGC()) { asserta(allMachineCodeObjectReferencesValid()); } if (codeModified) { /* After updating oops in inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Mark and trace any object references in the generated run-time. */ /* Cogit>>#markAndTraceObjectReferencesInGeneratedRuntime */ static void markAndTraceObjectReferencesInGeneratedRuntime(void) { sqInt i; sqInt literal; usqInt mcpc; for (i = 0; i < runtimeObjectRefIndex; i += 1) { mcpc = objectReferencesInRuntime[i]; literal = longAt(mcpc); markAndTraceLiteralinatpc(literal, ((CogMethod *) null), ((usqInt)mcpc)); } } /* Mark and trace objects in the argument and free if it is appropriate. Answer if the method has been freed. firstVisit is a hint used to avoid scanning methods we've already seen. False positives are fine. For a CMMethod this frees if the bytecode method isnt marked, marks and traces object literals and selectors, unlinks sends to targets that should be freed. For a CMClosedPIC this frees if it refers to anything that should be freed or isn't marked. For a CMOpenPIC this frees if the selector isn't marked. */ /* this recurses at most one level down */ /* Cogit>>#markAndTraceOrFreeCogMethod:firstVisit: */ static sqInt NoDbgRegParms markAndTraceOrFreeCogMethodfirstVisit(CogMethod *cogMethod, sqInt firstVisit) { sqInt annotation; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; sqInt val; val = 0; if (((cogMethod->cmType)) == CMFree) { return 1; } assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if (((cogMethod->cmType)) == CMMethod) { if (!(isMarked((cogMethod->methodObject)))) { freeMethod(cogMethod); return 1; } if (firstVisit) { /* begin markLiteralsAndUnlinkUnmarkedSendsIn: */ assert(((cogMethod->cmType)) == CMMethod); assert(isMarked((cogMethod->methodObject))); markAndTraceLiteralinat((cogMethod->selector), cogMethod, (&((cogMethod->selector)))); maybeMarkCountersIn(cogMethod); /* begin maybeMarkIRCsIn: */ /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = markLiteralsAndUnlinkIfUnmarkedSendpcmethod(annotation, (((char *) mcpc)), (((sqInt)cogMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } return 0; } if (((cogMethod->cmType)) == CMClosedPIC) { if (!(closedPICRefersToUnmarkedObject(cogMethod))) { return 0; } freeMethod(cogMethod); return 1; } if (((cogMethod->cmType)) == CMOpenPIC) { if (isMarked((cogMethod->selector))) { return 0; } freeMethod(cogMethod); return 1; } assert((((cogMethod->cmType)) == CMMethod) || ((((cogMethod->cmType)) == CMClosedPIC) || (((cogMethod->cmType)) == CMOpenPIC))); return 0; } /* If entryPoint is that of some method, then mark and trace objects in it and free if it is appropriate. Answer if the method has been freed. */ /* Cogit>>#markAndTraceOrFreePICTarget:in: */ static sqInt NoDbgRegParms markAndTraceOrFreePICTargetin(sqInt entryPoint, CogMethod *cPIC) { CogMethod *targetMethod; assert((entryPoint > methodZoneBase) && (entryPoint < (freeStart()))); if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { return 0; } targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert((((targetMethod->cmType)) == CMMethod) || (((targetMethod->cmType)) == CMFree)); return markAndTraceOrFreeCogMethodfirstVisit(targetMethod, (((usqInt)targetMethod)) > (((usqInt)cPIC))); } /* Mark and trace literals. Unlink sends that have unmarked cache tags or targets. */ /* Cogit>>#markLiteralsAndUnlinkIfUnmarkedSend:pc:method: */ static sqInt NoDbgRegParms markLiteralsAndUnlinkIfUnmarkedSendpcmethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt cacheTagMarked; sqInt entryPoint1; sqInt literal; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj1; CogMethod *targetMethod1; sqInt unlinkedRoutine; sqInt val; literal = 0; val = 0; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (markAndTraceLiteralinatpc(literal, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); cacheTagMarked = tagCouldBeObj1 && (cacheTagIsMarked(cacheTag1)); if (entryPoint1 > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint1 - offset1)); if ((!cacheTagMarked) || (markAndTraceOrFreeCogMethodfirstVisit(targetMethod1, (((usqInt)targetMethod1)) > (((usqInt)mcpc))))) { /* Either the cacheTag is unmarked (e.g. new class) or the target has been freed (because it is unmarked), so unlink the send. */ /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod1->selector), unlinkedRoutine); codeModified = 1; markAndTraceLiteralinat((targetMethod1->selector), targetMethod1, (&((targetMethod1->selector)))); } } else { /* cacheTag is selector */ if (markAndTraceCacheTagLiteralinatpc(cacheTag1, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } } return 0; } /* Mark and trace literals. Additionally in Newspeak, void push implicits that have unmarked classes. */ /* Cogit>>#markLiterals:pc:method: */ static sqInt NoDbgRegParms markLiteralspcmethod(sqInt annotation, char *mcpc, sqInt cogMethod) { sqInt cacheTag1; sqInt entryPoint1; sqInt literal; sqInt tagCouldBeObj1; literal = 0; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (markAndTraceLiteralinatpc(literal, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { codeModified = 1; } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); if (tagCouldBeObj1) { if (markAndTraceCacheTagLiteralinatpc(cacheTag1, ((CogMethod *) cogMethod), ((usqInt)mcpc))) { /* cacheTag is selector */ codeModified = 1; } } } return 0; } /* Cogit>>#markMethodAndReferents: */ void markMethodAndReferents(CogBlockMethod *aCogMethod) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; assert((((aCogMethod->cmType)) == CMMethod) || (((aCogMethod->cmType)) == CMBlock)); cogMethod = (((aCogMethod->cmType)) == CMMethod ? ((CogMethod *) aCogMethod) : cmHomeMethod(aCogMethod)); (cogMethod->cmUsageCount = CMMaxUsageCount); /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = incrementUsageOfTargetIfLinkedSendmcpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#maxCogMethodAddress */ usqInt maxCogMethodAddress(void) { return ((usqInt)(limitZony())); } /* If this is the Newspeak VM and the objectRepresentation supports pinning then allocate space for the implicit receiver caches on the heap. */ /* Cogit>>#maybeAllocAndInitIRCs */ static sqInt maybeAllocAndInitIRCs(void) { return 1; } /* Check that the header fields are consistent with the type. Answer 0 if it is ok, otherwise answer a code for the error. */ /* Cogit>>#maybeFreeCogMethodDoesntLookKosher: */ static sqInt NoDbgRegParms maybeFreeCogMethodDoesntLookKosher(CogMethod *cogMethod) { sqInt result; result = cogMethodDoesntLookKosher(cogMethod); return (result == 2 ? 0 : result); } /* In SIsta Spur counters are held on the heap in pinned objects which must be marked to avoid them being garbage collected. This is the hook through which that happens. */ /* Cogit>>#maybeMarkCountersIn: */ static void NoDbgRegParms maybeMarkCountersIn(CogMethod *cogMethod) { } /* Cogit>>#mclassIsSmallInteger */ static sqInt mclassIsSmallInteger(void) { return (receiverTags & 1); } /* Answer the absolute machine code pc matching the zero-relative bytecode pc of a backward branch in cogMethod, given the start of the bytecodes for cogMethod's block or method object. */ /* Cogit>>#mcPCForBackwardBranch:startBcpc:in: */ usqInt mcPCForBackwardBranchstartBcpcin(sqInt bcpc, sqInt startbcpc, CogBlockMethod *cogMethod) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc1; sqInt bsOffset; sqInt byte; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt targetPC; latestContinuation = 0; /* begin mapFor:bcpc:performUntil:arg: */ assert(((cogMethod->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogMethod)) + ((cogMethod->stackCheckOffset)); result = (((0 + (((int)((usqInt)(HasBytecodePC) << 1)))) & 1) && ((((sqInt)(((void *)bcpc)))) == startbcpc) ? ((sqInt)(((char *) mcpc))) : 0); if (result != 0) { return result; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc1 = startbcpc; if (((cogMethod->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc1 += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc1 == ((cogMethod->startpc))); homeMethod = cmHomeMethod(cogMethod); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc1 = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc1, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc1 + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc1, -1, aMethodObj)) : 0)); bcpc1 = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc1, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc1 >= endbcpc) { return 0; } } else { if (((descriptor->isReturn)) && (bcpc1 >= latestContinuation)) { return 0; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj); targetPC = (bcpc1 + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc1 + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc1 = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc1, nExts, aMethodObj)) < 0)); result = findBackwardBranchIsBackwardBranchMcpcBcpcMatchingBcpc(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc1 - (2 * nExts) : bcpc1)), (((void *)bcpc))); if (result != 0) { return result; } bcpc1 = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } return 0; } /* For the purposes of become: see if the two methods are similar, i.e. can be safely becommed. This is pretty strict. All literals and bytecodes must be identical. Only trailer bytes and header flags can differ. */ /* Cogit>>#method:hasSameCodeAs:checkPenultimate: */ static sqInt NoDbgRegParms methodhasSameCodeAscheckPenultimate(sqInt methodA, sqInt methodB, sqInt comparePenultimateLiteral) { sqInt bi; sqInt endPCA; sqInt headerA; sqInt headerB; sqInt li; sqInt numLitsA; headerA = methodHeaderOf(methodA); headerB = methodHeaderOf(methodB); numLitsA = literalCountOfMethodHeader(headerA); endPCA = endPCOf(methodA); if (((argumentCountOfMethodHeader(headerA)) != (argumentCountOfMethodHeader(headerB))) || (((temporaryCountOfMethodHeader(headerA)) != (temporaryCountOfMethodHeader(headerB))) || (((primitiveIndexOfMethodheader(methodA, headerA)) != (primitiveIndexOfMethodheader(methodB, headerB))) || ((numLitsA != (literalCountOfMethodHeader(headerB))) || (endPCA > (numBytesOf(methodB))))))) { return 0; } for (li = 1; li < numLitsA; li += 1) { if ((fetchPointerofObject(li, methodA)) != (fetchPointerofObject(li, methodB))) { if ((li < (numLitsA - 1)) || (comparePenultimateLiteral)) { return 0; } } } for (bi = (startPCOfMethod(methodA)); bi <= endPCA; bi += 1) { if ((fetchByteofObject(bi, methodA)) != (fetchByteofObject(bi, methodB))) { return 0; } } return 1; } /* Cogit>>#minCogMethodAddress */ sqInt minCogMethodAddress(void) { return methodZoneBase; } /* Cogit>>#mnuOffset */ sqInt mnuOffset(void) { return missOffset; } /* Cogit>>#needsFrameIfImmutability: */ static sqInt NoDbgRegParms needsFrameIfImmutability(sqInt stackDelta) { return IMMUTABILITY; } /* Cogit>>#needsFrameIfInBlock: */ static sqInt NoDbgRegParms needsFrameIfInBlock(sqInt stackDelta) { return inBlock > 0; } /* Cogit>>#needsFrameNever: */ static sqInt NoDbgRegParms needsFrameNever(sqInt stackDelta) { return 0; } /* Cogit>>#noAssertMethodClassAssociationOf: */ static sqInt NoDbgRegParms noAssertMethodClassAssociationOf(sqInt methodPointer) { return literalofMethod((literalCountOfMethodHeader(noAssertHeaderOf(methodPointer))) - 1, methodPointer); } /* Check that no method is maximally marked. A maximal mark is an indication the method has been scanned to increase the usage count of its referent methods. */ /* Cogit>>#noCogMethodsMaximallyMarked */ static sqInt noCogMethodsMaximallyMarked(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->cmUsageCount)) == CMMaxUsageCount)) { return 0; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return 1; } /* Answer if all targets in the PIC are in-use methods. */ /* Cogit>>#noTargetsFreeInClosedPIC: */ static sqInt NoDbgRegParms noTargetsFreeInClosedPIC(CogMethod *cPIC) { return !(cPICHasFreedTargets(cPIC)); } /* Store the generated machine code, answering the last address */ /* Cogit>>#outputInstructionsAt: */ static sqInt NoDbgRegParms outputInstructionsAt(sqInt startAddress) { sqInt absoluteAddress; AbstractInstruction *abstractInstruction; sqInt i; sqInt j; absoluteAddress = startAddress; for (i = 0; i < opcodeIndex; i += 1) { abstractInstruction = abstractInstructionAt(i); assert(((abstractInstruction->address)) == absoluteAddress); /* begin outputMachineCodeAt: */ for (j = 0; j < ((abstractInstruction->machineCodeSize)); j += 4) { longAtput(absoluteAddress + j, ((abstractInstruction->machineCode))[j / 4]); } absoluteAddress += (abstractInstruction->machineCodeSize); } return absoluteAddress; } /* Output instructions generated for one of the generated run-time routines, a trampoline, etc */ /* Cogit>>#outputInstructionsForGeneratedRuntimeAt: */ static sqInt NoDbgRegParms outputInstructionsForGeneratedRuntimeAt(sqInt startAddress) { sqInt endAddress; sqInt size; computeMaximumSizes(); (methodLabel->address = startAddress); size = generateInstructionsAt(startAddress); endAddress = outputInstructionsAt(startAddress); assert((startAddress + size) == endAddress); methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(backEnd, endAddress, methodZoneBase - 1); return startAddress; } /* Cogit>>#PushCw: */ static AbstractInstruction * NoDbgRegParms gPushCw(sqInt wordConstant) { /* begin gen:literal: */ return checkLiteralforInstruction(wordConstant, genoperand(PushCw, wordConstant)); } /* Code entry closed PIC full or miss to an instance of a young class or to a young target method. Attempt to patch the send site to an open PIC. Answer if the attempt succeeded; in fact it will only return if the attempt failed. The stack looks like: receiver args sp=> sender return address */ /* Cogit>>#patchToOpenPICFor:numArgs:receiver: */ sqInt patchToOpenPICFornumArgsreceiver(sqInt selector, sqInt numArgs, sqInt receiver) { sqInt extent; CogMethod *oPIC; sqInt outerReturn; /* See if an Open PIC is already available. */ outerReturn = stackTop(); oPIC = openPICWithSelector(selector); if (!(oPIC)) { /* otherwise attempt to create an Open PIC. */ oPIC = cogOpenPICSelectornumArgs(selector, numArgs); if ((((((sqInt)oPIC)) >= MaxNegativeErrorCode) && ((((sqInt)oPIC)) <= -1))) { /* For some reason the PIC couldn't be generated, most likely a lack of code memory. */ if ((((sqInt)oPIC)) == InsufficientCodeSpace) { callForCogCompiledCodeCompaction(); } return 0; } } extent = rewriteInlineCacheAttagtarget(backEnd, outerReturn, inlineCacheValueForSelectorinat(selector, mframeHomeMethodExport(), outerReturn), (((sqInt)oPIC)) + cmEntryOffset); flushICacheFromto(processor, (((usqInt)outerReturn)) - extent, ((usqInt)outerReturn)); flushICacheFromto(processor, ((usqInt)oPIC), (((usqInt)oPIC)) + openPICSize); executeCogMethodfromLinkedSendWithReceiver(oPIC, receiver); return 1; } /* This value is used to decide between MNU processing or interpretation in the closed PIC aborts. */ /* Cogit>>#picAbortDiscriminatorValue */ static sqInt picAbortDiscriminatorValue(void) { return 0; } /* Answer the start of the abort sequence for invoking the interpreter in a closed PIC. */ /* Cogit>>#picInterpretAbortOffset */ static sqInt picInterpretAbortOffset(void) { return (interpretOffset()) - (4 /* pushLinkRegisterByteSize */ + 4 /* callInstructionByteSize */); } /* Cogit>>#printCogMethodFor: */ void printCogMethodFor(void *address) { CogMethod *cogMethod; cogMethod = methodFor(address); if (cogMethod == 0) { if ((codeEntryFor(address)) == null) { print("not a method"); cr(); } else { print("trampoline "); print(codeEntryNameFor(address)); cr(); } } else { printCogMethod(cogMethod); } } /* Cogit>>#printTrampolineTable */ void printTrampolineTable(void) { sqInt i; for (i = 0; i < trampolineTableIndex; i += 2) { printHex(((sqInt)(trampolineAddresses[i + 1]))); print(": "); print(((char *) (trampolineAddresses[i]))); cr(); } } /* Cogit>>#processorHasDivQuoRemAndMClassIsSmallInteger */ static sqInt processorHasDivQuoRemAndMClassIsSmallInteger(void) { return mclassIsSmallInteger(); } /* Cogit>>#processorHasMultiplyAndMClassIsSmallInteger */ static sqInt processorHasMultiplyAndMClassIsSmallInteger(void) { return mclassIsSmallInteger(); } /* Cogit>>#recordGeneratedRunTime:address: */ static void NoDbgRegParms recordGeneratedRunTimeaddress(char *aString, sqInt address) { trampolineAddresses[trampolineTableIndex] = aString; trampolineAddresses[trampolineTableIndex + 1] = (((char *) address)); trampolineTableIndex += 2; } /* This one for C support code. */ /* Cogit>>#recordPrimTraceFunc */ sqInt recordPrimTraceFunc(void) { return recordPrimTrace(); } /* Cogit>>#recordRunTimeObjectReferences */ static void recordRunTimeObjectReferences(void) { sqInt i; AbstractInstruction *instruction; for (i = 0; i < opcodeIndex; i += 1) { instruction = abstractInstructionAt(i); if (((instruction->annotation)) == IsObjectReference) { assert(runtimeObjectRefIndex < NumObjRefsInRuntime); assert(!hasYoungReferent); if (hasYoungReferent) { error("attempt to generate run-time routine containing young object reference. Cannot initialize Cogit run-time."); } objectReferencesInRuntime[runtimeObjectRefIndex] = (((usqInt)((((instruction->opcode)) == Literal ? (instruction->address) : ((instruction->address)) + ((instruction->machineCodeSize)))))); runtimeObjectRefIndex += 1; } } } /* Cogit>>#registerMaskFor: */ static sqInt NoDbgRegParms registerMaskFor(sqInt reg) { return 1U << reg; } /* Cogit>>#relocateCallsAndSelfReferencesInMethod: */ static void NoDbgRegParms relocateCallsAndSelfReferencesInMethod(CogMethod *cogMethod) { sqInt annotation; sqInt callDelta; usqInt map; sqInt mapByte; sqInt mcpc; sqLong refDelta; sqInt result; refDelta = (cogMethod->objectHeader); callDelta = refDelta; assert((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)); assert((callTargetFromReturnAddress(backEnd, (((sqInt)cogMethod)) + missOffset)) == ((((cogMethod->cmType)) == CMMethod ? methodAbortTrampolineFor((cogMethod->cmNumArgs)) : picAbortTrampolineFor((cogMethod->cmNumArgs))))); relocateCallBeforeReturnPCby(backEnd, (((sqInt)cogMethod)) + missOffset, -callDelta); /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = relocateIfCallOrMethodReferencemcpcdelta(annotation, (((char *) mcpc)), refDelta); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } /* Cogit>>#relocateCallsInClosedPIC: */ static void NoDbgRegParms relocateCallsInClosedPIC(CogMethod *cPIC) { sqInt callDelta; sqInt entryPoint; sqInt i; sqInt pc; sqLong refDelta; CogMethod *targetMethod; refDelta = (cPIC->objectHeader); callDelta = refDelta; assert((callTargetFromReturnAddress(backEnd, (((sqInt)cPIC)) + missOffset)) == (picAbortTrampolineFor((cPIC->cmNumArgs)))); relocateCallBeforeReturnPCby(backEnd, (((sqInt)cPIC)) + missOffset, -callDelta); pc = (((sqInt)cPIC)) + firstCPICCaseOffset; for (i = 1; i <= ((cPIC->cPICNumCases)); i += 1) { pc = addressOfEndOfCaseinCPIC(i, cPIC); if (i == 1) { entryPoint = jumpLongTargetBeforeFollowingAddress(backEnd, pc); } else { /* begin jumpLongConditionalTargetBeforeFollowingAddress: */ entryPoint = jumpLongTargetBeforeFollowingAddress(((AbstractInstruction *) backEnd), pc); } if (((((usqInt)cPIC)) <= (((usqInt)entryPoint))) && (((((usqInt)cPIC)) + ((cPIC->blockSize))) >= (((usqInt)entryPoint)))) { /* Interpret/MNU */ } else { targetMethod = ((CogMethod *) (entryPoint - cmNoCheckEntryOffset)); assert(((targetMethod->cmType)) == CMMethod); if (i == 1) { relocateJumpLongBeforeFollowingAddressby(backEnd, pc, -(callDelta - ((targetMethod->objectHeader)))); } else { relocateJumpLongConditionalBeforeFollowingAddressby(backEnd, pc, -(callDelta - ((targetMethod->objectHeader)))); } } } assert(((cPIC->cPICNumCases)) > 0); relocateMethodReferenceBeforeAddressby(backEnd, (addressOfEndOfCaseinCPIC(2, cPIC)) + 4 /* loadPICLiteralByteSize */, refDelta); relocateJumpLongBeforeFollowingAddressby(backEnd, (((sqInt)cPIC)) + cPICEndOfCodeOffset, -callDelta); } /* Cogit>>#relocateIfCallOrMethodReference:mcpc:delta: */ static sqInt NoDbgRegParms relocateIfCallOrMethodReferencemcpcdelta(sqInt annotation, char *mcpc, sqInt refDelta) { sqInt callDelta; sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod; sqInt unlinkedRoutine; callDelta = refDelta; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint <= methodZoneBase) { /* send is not linked; just relocate */ relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -callDelta); return 0; } /* begin offsetAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod->cmType)) != CMFree) { /* send target not freed; just relocate. */ relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -(callDelta - ((targetMethod->objectHeader)))); return 0; } unlinkedRoutine = sendTable1[((((targetMethod->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod->cmNumArgs)) : (NumSendTrampolines - 1))]; unlinkedRoutine -= callDelta; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod->selector), unlinkedRoutine); return 0; } if (annotation == IsRelativeCall) { relocateCallBeforeReturnPCby(backEnd, ((sqInt)mcpc), -callDelta); return 0; } if (annotation == IsAbsPCReference) { relocateMethodReferenceBeforeAddressby(backEnd, ((sqInt)mcpc), refDelta); } return 0; } /* Cogit>>#remapIfObjectRef:pc:hasYoung: */ static sqInt NoDbgRegParms remapIfObjectRefpchasYoung(sqInt annotation, char *mcpc, sqInt hasYoungPtr) { sqInt cacheTag1; sqInt callSiteReturnAddress; sqInt entryPoint1; sqInt literal; sqInt mappedCacheTag; sqInt mappedLiteral; sqInt offset1; sqInt *sendTable1; sqInt tagCouldBeObj1; CogMethod *targetMethod1; if (annotation == IsObjectReference) { literal = longAt(((usqInt)mcpc)); if (couldBeObject(literal)) { mappedLiteral = remapObject(literal); if (literal != mappedLiteral) { /* begin storeLiteral:atAnnotatedAddress:using: */ longAtput(((usqInt)mcpc), mappedLiteral); codeModified = 1; } if ((hasYoungPtr != 0) && (isYoung(mappedLiteral))) { (((sqInt *) hasYoungPtr))[0] = 1; } } } if (annotation >= IsSendCall) { /* begin entryCacheTagAndCouldBeObjectAt:annotation:into: */ cacheTag1 = longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8)))); /* in-line cache tags are the selectors of sends if sends are unlinked, the selectors of super sends (entry offset = cmNoCheckEntryOffset), the selectors of open PIC sends (entry offset = cmEntryOffset, target is an Open PIC) or in-line cache tags (classes, class indices, immediate bit patterns, etc). Note that selectors can be immediate so there is no guarantee that they are markable/remappable objects. */ entryPoint1 = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); tagCouldBeObj1 = entryPointTagIsSelector(entryPoint1); if (tagCouldBeObj1 && (couldBeObject(cacheTag1))) { mappedCacheTag = remapObject(cacheTag1); if (cacheTag1 != mappedCacheTag) { /* begin rewriteInlineCacheTag:at: */ callSiteReturnAddress = ((usqInt)mcpc); longAtput(pcRelativeAddressAt(((AbstractInstruction *) backEnd), callSiteReturnAddress - 8), mappedCacheTag); ((AbstractInstruction *) backEnd); codeModified = 1; } if ((hasYoungPtr != 0) && (isYoung(mappedCacheTag))) { (((sqInt *) hasYoungPtr))[0] = 1; } } if (hasYoungPtr != 0) { /* Since the unlinking routines may rewrite the cacheTag to the send's selector, and since they don't have the cogMethod to hand and can't add it to youngReferrers, the method must remain in youngReferrers if the targetMethod's selector is young. */ if (entryPoint1 > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint1 - offset1)); if (isYoung((targetMethod1->selector))) { (((sqInt *) hasYoungPtr))[0] = 1; } } } } return 0; } /* Remap a potential object reference from a closed PIC. This may be an object reference, an inline cache tag or null. Answer if the updated literal is young. mcpc is the address of the next instruction following either the load of the method literal or the compare of the class tag. */ /* Cogit>>#remapMaybeObjRefInClosedPICAt: */ static sqInt NoDbgRegParms remapMaybeObjRefInClosedPICAt(sqInt mcpc) { sqInt object; sqInt subject; object = literalBeforeFollowingAddress(backEnd, mcpc); if (!(couldBeObject(object))) { return 0; } subject = remapOop(object); if (object != subject) { storeLiteralbeforeFollowingAddress(backEnd, subject, mcpc); codeModified = 1; } return isYoungObject(subject); } /* Rewrite the three values involved in a CPIC case. Used by the initialize & extend CPICs. c.f. expectedClosedPICPrototype: */ /* write the obj ref/operand via the second ldr */ /* Cogit>>#rewriteCPICCaseAt:tag:objRef:target: */ static void NoDbgRegParms rewriteCPICCaseAttagobjReftarget(sqInt followingAddress, sqInt newTag, sqInt newObjRef, sqInt newTarget) { sqInt classTagPC; sqInt methodObjPC; methodObjPC = (followingAddress - (jumpLongConditionalByteSize(backEnd))) - 8 /* cmpC32RTempByteSize */; storeLiteralbeforeFollowingAddress(backEnd, newObjRef, methodObjPC); /* rewite the tag via the first ldr */ classTagPC = followingAddress - (jumpLongConditionalByteSize(backEnd)); /* begin storeLiteral32:beforeFollowingAddress: */ storeLiteralbeforeFollowingAddress(((AbstractInstruction *) backEnd), newTag, classTagPC); ((AbstractInstruction *) backEnd); rewriteConditionalJumpLongAttarget(backEnd, followingAddress, newTarget); } /* Cogit>>#SubCw:R: */ static AbstractInstruction * NoDbgRegParms gSubCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(SubCwR, wordConstant, reg)); } /* Answer the number of clean blocks found in the literal frame */ /* Cogit>>#scanForCleanBlocks */ static sqInt scanForCleanBlocks(void) { sqInt i; sqInt iLimiT; sqInt lit; sqInt numCleanBlocks; sqInt startPCOrNil; numCleanBlocks = 0; for (i = 1, iLimiT = (literalCountOf(methodObj)); i <= iLimiT; i += 1) { lit = fetchPointerofObject(i, methodObj); startPCOrNil = startPCOrNilOfLiteralin(lit, methodObj); if (!(startPCOrNil == null)) { numCleanBlocks += 1; } } return numCleanBlocks; } /* Cogit>>#setBreakMethod: */ void setBreakMethod(sqInt anObj) { breakMethod = anObj; } /* Cogit>>#setPostCompileHook: */ void setPostCompileHook(void (*aFunction)(CogMethod *)) { postCompileHook = aFunction; } /* If a method is compiled to machine code via a block entry it won't have a selector. A subsequent send can find the method and hence fill in the selector. */ /* self disassembleMethod: cogMethod */ /* Cogit>>#setSelectorOf:to: */ void setSelectorOfto(CogMethod *cogMethod, sqInt aSelectorOop) { compilationBreakpointisMNUCase(aSelectorOop, numBytesOf(aSelectorOop), 0); assert(((cogMethod->cmType)) == CMMethod); (cogMethod->selector = aSelectorOop); if (isYoung(aSelectorOop)) { ensureInYoungReferrers(cogMethod); } } /* Cogit>>#spanForCleanBlockStartingAt: */ static sqInt NoDbgRegParms spanForCleanBlockStartingAt(sqInt startPC) { BytecodeDescriptor *descriptor; sqInt end; sqInt pc; pc = startPC; end = numBytesOf(methodObj); while (pc <= end) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); pc += (descriptor->numBytes); if ((descriptor->isReturn)) { return pc - startPC; } } error("couldn't locate end of clean block"); return 0; } /* Answer a fake value for the method oop in other than the first case in the PIC prototype. Since we use MoveUniqueCw:R: it must not be confused with a method-relative address. */ /* Cogit>>#subsequentPrototypeMethodOop */ static sqInt subsequentPrototypeMethodOop(void) { return (((((usqInt)195929424)) >= ((methodLabel->address))) && ((((usqInt)195929424)) < (youngReferrers())) ? 233496237 : 195929424); } /* Cogit>>#traceLinkedSendOffset */ sqInt traceLinkedSendOffset(void) { return (cmNoCheckEntryOffset + 4 /* callInstructionByteSize */) + (/* begin pushLinkRegisterByteSize */ 4); } /* Encode true and false and 0 to N such that they can't be confused for register numbers (including NoReg) and can be tested for by isTrampolineArgConstant: and decoded by trampolineArgValue: */ /* Cogit>>#trampolineArgConstant: */ static sqInt NoDbgRegParms trampolineArgConstant(sqInt booleanOrInteger) { assert(booleanOrInteger >= 0); return -2 - booleanOrInteger; } /* Cogit>>#trampolineName:numArgs: */ static char * NoDbgRegParms trampolineNamenumArgs(char *routinePrefix, sqInt numArgs) { char *theString; /* begin trampolineName:numArgs:limit: */ theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= (NumSendTrampolines - 2) ? '0' + numArgs : 'N')); return theString; } /* Malloc a string with the contents for the trampoline table */ /* Cogit>>#trampolineName:numArgs:limit: */ static char * NoDbgRegParms trampolineNamenumArgslimit(char *routinePrefix, int numArgs, sqInt argsLimit) { char *theString; theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= argsLimit ? '0' + numArgs : 'N')); return theString; } /* Cogit>>#trampolineName:numRegArgs: */ static char * NoDbgRegParms trampolineNamenumRegArgs(char *routinePrefix, sqInt numArgs) { sqInt argsLimit; char *theString; /* begin trampolineName:numArgs:limit: */ argsLimit = 2 /* numRegArgs */; theString = malloc((strlen(routinePrefix)) + 6); sprintf(theString, "%s%cArgs", routinePrefix, (numArgs <= argsLimit ? '0' + numArgs : 'N')); return theString; } /* Cogit>>#unknownBytecode */ static sqInt unknownBytecode(void) { return EncounteredUnknownBytecode; } /* Unlink all sends in cog methods. */ /* Cogit>>#unlinkAllSends */ void unlinkAllSends(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); voidOpenPICList(); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if (((cogMethod->cmType)) != CMFree) { freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } /* Cogit>>#unlinkIfFreeOrLinkedSend:pc:of: */ static sqInt NoDbgRegParms unlinkIfFreeOrLinkedSendpcof(sqInt annotation, char *mcpc, sqInt theSelector) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if ((((targetMethod1->cmType)) == CMFree) || (((targetMethod1->selector)) == theSelector)) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), (targetMethod1->selector), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Cogit>>#unlinkIfInvalidClassSend:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfInvalidClassSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send, but maybe a super send or linked to an OpenPIC, in which case the cache tag will be a selector.... */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (!(((annotation == IsSuperSend) || (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend)))) || (((targetMethod1->cmType)) == CMOpenPIC))) { if (!(isValidClassTag(longAt(pcRelativeAddressAt(backEnd, ((usqInt)((((sqInt)mcpc)) - 8))))))) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } } return 0; } /* Cogit>>#unlinkIfLinkedSendToFree:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfLinkedSendToFreepcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if (((targetMethod1->cmType)) == CMFree) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Cogit>>#unlinkIfLinkedSend:pc:ignored: */ static sqInt NoDbgRegParms unlinkIfLinkedSendpcignored(sqInt annotation, char *mcpc, sqInt superfluity) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } return 0; } /* Cogit>>#unlinkIfLinkedSend:pc:to: */ static sqInt NoDbgRegParms unlinkIfLinkedSendpcto(sqInt annotation, char *mcpc, sqInt theCogMethod) { sqInt entryPoint; sqInt offset1; sqInt *sendTable1; CogMethod *targetMethod1; sqInt unlinkedRoutine; if (annotation >= IsSendCall) { entryPoint = callTargetFromReturnAddress(backEnd, ((sqInt)mcpc)); if (entryPoint > methodZoneBase) { /* It's a linked send. */ /* begin targetMethodAndSendTableFor:annotation:into: */ if (annotation == IsSendCall) { offset1 = cmEntryOffset; sendTable1 = ordinarySendTrampolines; } else { if (annotation == IsDirectedSuperSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperSendTrampolines; } else { if (annotation == IsDirectedSuperBindingSend) { offset1 = cmNoCheckEntryOffset; sendTable1 = directedSuperBindingSendTrampolines; } else { assert(annotation == IsSuperSend); offset1 = cmNoCheckEntryOffset; sendTable1 = superSendTrampolines; } } } targetMethod1 = ((CogMethod *) (entryPoint - offset1)); if ((((sqInt)targetMethod1)) == theCogMethod) { /* begin unlinkSendAt:targetMethod:sendTable: */ unlinkedRoutine = sendTable1[((((targetMethod1->cmNumArgs)) < (NumSendTrampolines - 1)) ? ((targetMethod1->cmNumArgs)) : (NumSendTrampolines - 1))]; rewriteInlineCacheAttagtarget(backEnd, ((sqInt)mcpc), inlineCacheValueForSelectorinat((targetMethod1->selector), enumeratingCogMethod, mcpc), unlinkedRoutine); codeModified = 1; } } } return 0; } /* Unlink all sends in cog methods whose class tag is that of a forwarded class. */ /* Cogit>>#unlinkSendsLinkedForInvalidClasses */ void unlinkSendsLinkedForInvalidClasses(void) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); codeModified = (freedPIC = 0); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfInvalidClassSendpcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICHasForwardedClass(cogMethod))) { freeMethod(cogMethod); freedPIC = 1; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freedPIC) { unlinkSendsToFree(); } else { if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } } /* Unlink all sends in cog methods. Free all Closed PICs with the selector, or with an MNU case if isMNUSelector. First check if any method actually has the selector; if not there can't be any linked send to it. This routine (including descendents) is performance critical. It contributes perhaps 30% of entire execution time in Compiler recompileAll. */ /* Cogit>>#unlinkSendsOf:isMNUSelector: */ void unlinkSendsOfisMNUSelector(sqInt selector, sqInt isMNUSelector) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt mustScanAndUnlink; sqInt result; if (!(methodZoneBase)) { return; } cogMethod = ((CogMethod *) methodZoneBase); mustScanAndUnlink = 0; if (isMNUSelector) { while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) != CMFree) { if (((cogMethod->cpicHasMNUCaseOrCMIsFullBlock)) && (((cogMethod->cmType)) == CMClosedPIC)) { assert(((cogMethod->cmType)) == CMClosedPIC); freeMethod(cogMethod); mustScanAndUnlink = 1; } else { if (((cogMethod->selector)) == selector) { mustScanAndUnlink = 1; if (((cogMethod->cmType)) == CMClosedPIC) { freeMethod(cogMethod); } } } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } else { while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->selector)) == selector)) { mustScanAndUnlink = 1; if (((cogMethod->cmType)) == CMClosedPIC) { freeMethod(cogMethod); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } if (!mustScanAndUnlink) { return; } codeModified = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfFreeOrLinkedSendpcof(annotation, (((char *) mcpc)), selector); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Unlink all sends in cog methods to free methods and/or pics. */ /* Cogit>>#unlinkSendsToFree */ void unlinkSendsToFree(void) { sqInt annotation; CogMethod *cogMethod; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; if (!(methodZoneBase)) { return; } codeModified = 0; cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendToFreepcignored(annotation, (((char *) mcpc)), 0); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if (((cogMethod->cmType)) == CMClosedPIC) { assert(noTargetsFreeInClosedPIC(cogMethod)); } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } /* Unlink all sends in cog methods to a particular target method. If targetMethodObject isn't actually a method (perhaps being used via invokeAsMethod) then there's nothing to do. */ /* Cogit>>#unlinkSendsTo:andFreeIf: */ void unlinkSendsToandFreeIf(sqInt targetMethodObject, sqInt freeIfTrue) { sqInt annotation; CogMethod *cogMethod; sqInt freedPIC; usqInt map; sqInt mapByte; sqInt mcpc; sqInt result; CogMethod *targetMethod; if (!((isOopCompiledMethod(targetMethodObject)) && (methodHasCogMethod(targetMethodObject)))) { return; } targetMethod = cogMethodOf(targetMethodObject); if (!(methodZoneBase)) { return; } codeModified = (freedPIC = 0); cogMethod = ((CogMethod *) methodZoneBase); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { /* begin mapFor:performUntil:arg: */ mcpc = ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock) ? (((usqInt)cogMethod)) + cbNoSwitchEntryOffset : (((usqInt)cogMethod)) + cmNoCheckEntryOffset); map = ((((usqInt)cogMethod)) + ((cogMethod->blockSize))) - 1; while (((mapByte = byteAt(map))) != MapEnd) { if (mapByte >= FirstAnnotation) { /* If this is an IsSendCall annotation, peek ahead for an IsAnnotationExtension, and consume it. */ mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if ((((annotation = ((usqInt) mapByte) >> AnnotationShift)) == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } result = unlinkIfLinkedSendpcto(annotation, (((char *) mcpc)), (((sqInt)targetMethod))); if (result != 0) { goto l2; } } else { if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } l2: /* end mapFor:performUntil:arg: */; } else { if ((((cogMethod->cmType)) == CMClosedPIC) && (cPICHasTarget(cogMethod, targetMethod))) { freeMethod(cogMethod); freedPIC = 1; } } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } if (freeIfTrue) { freeMethod(targetMethod); } if (freedPIC) { unlinkSendsToFree(); } else { if (codeModified) { /* After possibly updating inline caches we need to flush the icache. */ flushICacheFromto(processor, ((usqInt)methodZoneBase), ((usqInt)(limitZony()))); } } } /* Cogit>>#XorCw:R: */ static AbstractInstruction * NoDbgRegParms gXorCwR(sqInt wordConstant, sqInt reg) { /* begin gen:literal:operand: */ return checkLiteralforInstruction(wordConstant, genoperandoperand(XorCwR, wordConstant, reg)); } /* Access for the object representations when they need to prepend code to trampolines. */ /* Eliminate stale dependent info. */ /* Cogit>>#zeroOpcodeIndex */ static void zeroOpcodeIndex(void) { sqInt i; for (i = 0; i < opcodeIndex; i += 1) { ((abstractOpcodes[i]).dependent = null); } zeroOpcodeIndexForNewOpcodes(); } /* Access for the object representations when they need to prepend code to trampolines. */ /* Cogit>>#zeroOpcodeIndexForNewOpcodes */ static void zeroOpcodeIndexForNewOpcodes(void) { opcodeIndex = 0; /* begin resetLiterals */ /* an impossibly high value */ firstOpcodeIndex = 1U << 16; nextLiteralIndex = (lastDumpedLiteralIndex = 0); } /* CogMethod>>#counters */ static sqInt NoDbgRegParms counters(CogMethod * self_in_counters) { return 0; } /* CogMethodZone>>#addAllToYoungReferrers */ void addAllToYoungReferrers(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) || (((cogMethod->cmType)) == CMOpenPIC)) { ensureInYoungReferrers(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#addToOpenPICList: */ static void NoDbgRegParms addToOpenPICList(CogMethod *anOpenPIC) { assert(((anOpenPIC->cmType)) == CMOpenPIC); assert((openPICList == null) || (((openPICList->cmType)) == CMOpenPIC)); (anOpenPIC->nextOpenPIC = ((usqInt)openPICList)); openPICList = anOpenPIC; } /* CogMethodZone>>#addToYoungReferrers: */ static void NoDbgRegParms addToYoungReferrers(CogMethod *cogMethod) { assert(youngReferrers <= limitAddress); assert((occurrencesInYoungReferrers(cogMethod)) == 0); assert((cogMethod->cmRefersToYoung)); assert((youngReferrers <= limitAddress) && (youngReferrers >= (limitAddress - (methodCount * BytesPerWord)))); if (!(asserta((limitAddress - (methodCount * BytesPerWord)) >= mzFreeStart))) { error("no room on youngReferrers list"); } youngReferrers -= BytesPerWord; longAtput(youngReferrers, ((usqInt)cogMethod)); } /* CogMethodZone>>#allocate: */ static usqInt NoDbgRegParms allocate(sqInt numBytes) { usqInt allocation; sqInt roundedBytes; roundedBytes = (numBytes + 7) & -8; if ((mzFreeStart + roundedBytes) >= (limitAddress - (methodCount * BytesPerWord))) { return 0; } allocation = mzFreeStart; mzFreeStart += roundedBytes; methodCount += 1; return allocation; } /* Free all methods */ /* CogMethodZone>>#clearCogCompiledCode */ static void clearCogCompiledCode(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) == CMMethod) { freeMethod(cogMethod); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } manageFromto(baseAddress, limitAddress); } /* CogMethodZone>>#compactCompiledCode */ static void compactCompiledCode(void) { unsigned short bytes; CogMethod *dest; sqLong objectHeaderValue; CogMethod *source; compactionInProgress = 1; objectHeaderValue = nullHeaderForMachineCodeMethod(); source = ((CogMethod *) baseAddress); voidOpenPICList(); methodCount = 0; while ((source < (limitZony())) && (((source->cmType)) != CMFree)) { assert((cogMethodDoesntLookKosher(source)) == 0); (source->objectHeader = objectHeaderValue); if (((source->cmUsageCount)) > 0) { (source->cmUsageCount = ((source->cmUsageCount)) / 2); } if (((source->cmType)) == CMOpenPIC) { addToOpenPICList(source); } methodCount += 1; source = ((CogMethod *) (roundUpLength((((sqInt)source)) + ((source->blockSize))))); } if (source >= (limitZony())) { haltmsg("no free methods; cannot compact."); return; } dest = source; while (source < (limitZony())) { assert((maybeFreeCogMethodDoesntLookKosher(source)) == 0); bytes = (source->blockSize); if (((source->cmType)) != CMFree) { methodCount += 1; memmove(dest, source, bytes); (dest->objectHeader = objectHeaderValue); if (((dest->cmType)) == CMMethod) { /* For non-Newspeak there should be a one-to-one mapping between bytecoded and cog methods. For Newspeak not necessarily, but only for anonymous accessors. */ /* Only update the original method's header if it is referring to this CogMethod. */ if ((((sqInt)(rawHeaderOf((dest->methodObject))))) == (((sqInt)source))) { rawHeaderOfput((dest->methodObject), ((sqInt)dest)); } else { assert((noAssertMethodClassAssociationOf((dest->methodObject))) == (nilObject())); } } else { if (((dest->cmType)) == CMOpenPIC) { addToOpenPICList(dest); } } if (((dest->cmUsageCount)) > 0) { (dest->cmUsageCount = ((dest->cmUsageCount)) / 2); } dest = ((CogMethod *) ((((usqInt)dest)) + bytes)); } source = ((CogMethod *) ((((usqInt)source)) + bytes)); } mzFreeStart = ((usqInt)dest); methodBytesFreedSinceLastCompaction = 0; compactionInProgress = 0; } /* CogMethodZone>>#ensureInYoungReferrers: */ static void NoDbgRegParms ensureInYoungReferrers(CogMethod *cogMethod) { if (!((cogMethod->cmRefersToYoung))) { assert((occurrencesInYoungReferrers(cogMethod)) == 0); (cogMethod->cmRefersToYoung = 1); addToYoungReferrers(cogMethod); } } /* CogMethodZone>>#followForwardedLiteralsInOpenPICList */ static void followForwardedLiteralsInOpenPICList(void) { CogMethod *openPIC; openPIC = openPICList; while (openPIC != null) { followForwardedLiteralsIn(openPIC); openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } } /* CogMethodZone>>#freeMethod: */ void freeMethod(CogMethod *cogMethod) { assert(((cogMethod->cmType)) != CMFree); assert((cogMethodDoesntLookKosher(cogMethod)) == 0); if (((cogMethod->cmType)) == CMMethod) { /* For non-Newspeak there should ne a one-to-one mapping between bytecoded and cog methods. For Newspeak not necessarily, but only for anonymous accessors. */ /* Only reset the original method's header if it is referring to this CogMethod. */ if ((((sqInt)(rawHeaderOf((cogMethod->methodObject))))) == (((sqInt)cogMethod))) { rawHeaderOfput((cogMethod->methodObject), (cogMethod->methodHeader)); } else { assert((noAssertMethodClassAssociationOf((cogMethod->methodObject))) == (nilObject())); } } if (((cogMethod->cmType)) == CMOpenPIC) { removeFromOpenPICList(cogMethod); } (cogMethod->cmRefersToYoung = 0); (cogMethod->cmType = CMFree); methodBytesFreedSinceLastCompaction += (cogMethod->blockSize); } /* Free methods, preferring older methods for compaction, up to some fraction, currently a quarter. */ /* CogMethodZone>>#freeOlderMethodsForCompaction */ static void freeOlderMethodsForCompaction(void) { sqInt amountToFree; CogMethod *cogMethod; sqInt freeableUsage; sqInt freedSoFar; sqInt initialFreeSpace; sqInt zoneSize; zoneSize = limitAddress - baseAddress; initialFreeSpace = (limitAddress - mzFreeStart) + methodBytesFreedSinceLastCompaction; freedSoFar = initialFreeSpace; /* 4 needs to be e.g. a start-up parameter */ amountToFree = zoneSize / 4; freeableUsage = 0; do { cogMethod = ((CogMethod *) baseAddress); while (((((usqInt)cogMethod)) < mzFreeStart) && (freedSoFar < amountToFree)) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->cmUsageCount)) <= freeableUsage)) { freeMethod(cogMethod); freedSoFar += (cogMethod->blockSize); } cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } while((freedSoFar < amountToFree) && (((freeableUsage += 1)) < CMMaxUsageCount)); } /* Answer that all entries in youngReferrers are in-use and have the cmRefersToYoung flag set. Used to check that the youngreferrers pruning routines work correctly. */ /* CogMethodZone>>#kosherYoungReferrers */ static sqInt kosherYoungReferrers(void) { CogMethod *cogMethod; usqInt pointer; if ((youngReferrers > limitAddress) || (youngReferrers < mzFreeStart)) { return 0; } pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (!((((cogMethod->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung)))) { return 0; } pointer += BytesPerWord; } return 1; } /* CogMethodZone>>#manageFrom:to: */ static void NoDbgRegParms manageFromto(sqInt theStartAddress, sqInt theLimitAddress) { mzFreeStart = (baseAddress = theStartAddress); youngReferrers = (limitAddress = theLimitAddress); openPICList = null; methodBytesFreedSinceLastCompaction = 0; methodCount = 0; } /* CogMethodZone>>#methodFor: */ CogMethod * methodFor(void *address) { CogMethod *cogMethod; CogMethod *nextMethod; cogMethod = ((CogMethod *) baseAddress); while ((cogMethod < (limitZony())) && ((((usqInt)cogMethod)) <= (((usqInt)address)))) { /* begin methodAfter: */ nextMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); if (nextMethod == cogMethod) { return 0; } if (((((usqInt)address)) >= (((usqInt)cogMethod))) && ((((usqInt)address)) < (((usqInt)nextMethod)))) { return cogMethod; } cogMethod = nextMethod; } return 0; } /* CogMethodZone>>#methodsCompiledToMachineCodeInto: */ sqInt methodsCompiledToMachineCodeInto(sqInt arrayObj) { CogMethod *cogMethod; sqInt methodIndex; methodIndex = 0; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == CMMethod) { storePointerUncheckedofObjectwithValue(methodIndex, arrayObj, (cogMethod->methodObject)); methodIndex += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return methodIndex; } /* CogMethodZone>>#numMethods */ sqInt numMethods(void) { return methodCount; } /* CogMethodZone>>#numMethodsOfType: */ sqInt numMethodsOfType(sqInt cogMethodType) { CogMethod *cogMethod; sqInt n; n = 0; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == cogMethodType) { n += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } return n; } /* CogMethodZone>>#occurrencesInYoungReferrers: */ static sqInt NoDbgRegParms occurrencesInYoungReferrers(CogMethod *cogMethod) { sqInt count; usqInt pointer; assert(youngReferrers <= limitAddress); count = 0; pointer = youngReferrers; while (pointer < limitAddress) { if ((((sqInt)cogMethod)) == (longAt(pointer))) { count += 1; } pointer += BytesPerWord; } return count; } /* CogMethodZone>>#openPICWithSelector: */ static CogMethod * NoDbgRegParms openPICWithSelector(sqInt aSelector) { CogMethod *openPIC; openPIC = openPICList; do { if ((openPIC == null) || (((openPIC->selector)) == aSelector)) { return openPIC; } openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } while(1); return 0; } /* Some methods have been freed. Compute how much each survivor needs to move during the ensuing compaction and record it in the objectHeader field. For Sista, where we want PICs to last so they can be observed, we need to keep PICs unless they are definitely unused. So we need to identify unused PICs. So in planCompact, zero the usage counts of all PICs, saving the actual usage count in blockEntryOffset. Then in relocateMethodsPreCompaction (actually in relocateIfCallOrMethodReference:mcpc:delta:) restore the usage counts of used PICs. Finally in compactCompiledCode, clear the blockEntryOffset of the unused PICs; they will then have a zero count and be reclaimed in the next code compaction. */ /* CogMethodZone>>#planCompaction */ static void planCompaction(void) { CogMethod *cogMethod; sqInt delta; delta = 0; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) == CMFree) { delta -= (cogMethod->blockSize); } else { assert((cogMethodDoesntLookKosher(cogMethod)) == 0); (cogMethod->objectHeader = delta); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethods */ void printCogMethods(void) { CogMethod *cogMethod; sqInt nc; sqInt nf; sqInt nm; sqInt no; sqInt nu; nm = (nc = (no = (nf = (nu = 0)))); cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { printCogMethod(cogMethod); switch ((cogMethod->cmType)) { case CMFree: nf += 1; break; case CMMethod: nm += 1; break; case CMClosedPIC: nc += 1; break; case CMOpenPIC: no += 1; break; default: nu += 1; } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } print("CMMethod "); printNum(nm); print(" CMClosedPIC "); printNum(nc); print(" CMOpenPIC "); printNum(no); print(" CMFree "); printNum(nf); if (nu > 0) { print(" UNKNOWN "); printNum(nu); } print(" total "); printNum((((nm + nc) + no) + nf) + nu); cr(); } /* CogMethodZone>>#printCogMethodsOfType: */ void printCogMethodsOfType(sqInt cmType) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if (((cogMethod->cmType)) == cmType) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithMethod: */ void printCogMethodsWithMethod(sqInt methodOop) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->methodObject)) == methodOop)) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithPrimitive: */ void printCogMethodsWithPrimitive(sqInt primIdx) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) == CMMethod) && (primIdx == (primitiveIndexOfMethodheader((cogMethod->methodObject), (cogMethod->methodHeader))))) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogMethodsWithSelector: */ void printCogMethodsWithSelector(sqInt selectorOop) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while (cogMethod < (limitZony())) { if ((((cogMethod->cmType)) != CMFree) && (((cogMethod->selector)) == selectorOop)) { printCogMethod(cogMethod); } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } } /* CogMethodZone>>#printCogYoungReferrers */ void printCogYoungReferrers(void) { CogMethod *cogMethod; usqInt pointer; pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (!((cogMethod->cmRefersToYoung))) { print("*"); } if (((cogMethod->cmType)) == CMFree) { print("!"); } if (!(((cogMethod->cmRefersToYoung)) && (((cogMethod->cmType)) != CMFree))) { print(" "); } printCogMethod(cogMethod); pointer += BytesPerWord; } } /* CogMethodZone>>#printOpenPICList */ sqInt printOpenPICList(void) { sqInt n; CogMethod *openPIC; n = 0; openPIC = openPICList; while (!(openPIC == null)) { n += 1; printCogMethod(openPIC); openPIC = ((CogMethod *) ((openPIC->nextOpenPIC))); } return n; } /* CogMethodZone>>#pruneYoungReferrers */ static sqInt pruneYoungReferrers(void) { usqInt dest; usqInt next; usqInt source; assert(youngReferrers <= limitAddress); if (youngReferrers == limitAddress) { return null; } dest = limitAddress; while (1) { next = dest - BytesPerWord; if (!((next >= youngReferrers) && (((((CogMethod *) (longAt(next))))->cmRefersToYoung)))) break; dest = next; } assert(dest >= youngReferrers); source = dest - BytesPerWord; while (source >= youngReferrers) { if (((((CogMethod *) (longAt(source))))->cmRefersToYoung)) { assert(source < (dest - BytesPerWord)); longAtput((dest -= BytesPerWord), longAt(source)); } source -= BytesPerWord; } youngReferrers = dest; assert(kosherYoungReferrers()); return 0; } /* CogMethodZone>>#relocateAndPruneYoungReferrers */ static sqInt relocateAndPruneYoungReferrers(void) { CogMethod *cogMethod; usqInt dest; usqInt next; usqInt source; assert(youngReferrers <= limitAddress); if (youngReferrers == limitAddress) { return null; } dest = limitAddress; while (1) { next = dest - BytesPerWord; if (!((next >= youngReferrers) && (((((cogMethod = ((CogMethod *) (longAt(next))))->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung))))) break; if (((cogMethod->objectHeader)) != 0) { longAtput(next, (((sqInt)cogMethod)) + ((cogMethod->objectHeader))); } dest = next; } assert(dest >= youngReferrers); source = dest - BytesPerWord; while (source >= youngReferrers) { cogMethod = ((CogMethod *) (longAt(source))); if ((((cogMethod->cmType)) != CMFree) && ((cogMethod->cmRefersToYoung))) { assert(source < (dest - BytesPerWord)); if (((cogMethod->objectHeader)) != 0) { cogMethod = ((CogMethod *) ((((sqInt)cogMethod)) + (((sqInt)((cogMethod->objectHeader)))))); } longAtput((dest -= BytesPerWord), ((sqInt)cogMethod)); } source -= BytesPerWord; } youngReferrers = dest; return 0; } /* All surviving methods have had the amount they are going to relocate by stored in their objectHeader fields. Relocate all relative calls so that after the compaction of both the method containing each call and the call target the calls invoke the same target. */ /* CogMethodZone>>#relocateMethodsPreCompaction */ static sqInt relocateMethodsPreCompaction(void) { CogMethod *cogMethod; cogMethod = ((CogMethod *) baseAddress); while ((((usqInt)cogMethod)) < mzFreeStart) { if (((cogMethod->cmType)) != CMFree) { if (((cogMethod->cmType)) == CMClosedPIC) { relocateCallsInClosedPIC(cogMethod); } else { relocateCallsAndSelfReferencesInMethod(cogMethod); } } /* begin methodAfter: */ cogMethod = ((CogMethod *) (roundUpLength((((sqInt)cogMethod)) + ((cogMethod->blockSize))))); } relocateAndPruneYoungReferrers(); return 1; } /* CogMethodZone>>#removeFromOpenPICList: */ static sqInt NoDbgRegParms removeFromOpenPICList(CogMethod *anOpenPIC) { CogMethod *prevPIC; assert(((anOpenPIC->cmType)) == CMOpenPIC); if (!(openPICList)) { return null; } assert((((openPICList->cmType)) == CMOpenPIC) && ((((openPICList->nextOpenPIC)) == null) || ((((((CogMethod *) ((openPICList->nextOpenPIC))))->cmType)) == CMOpenPIC))); if (anOpenPIC == openPICList) { /* N.B. Use self rather than coInterpreter to avoid attempting to cast nil. Conversion to CogMethod done in the nextOpenPIC accessor. */ openPICList = ((CogMethod *) ((anOpenPIC->nextOpenPIC))); return null; } prevPIC = openPICList; do { assert((prevPIC != null) && (((prevPIC->cmType)) == CMOpenPIC)); if (((prevPIC->nextOpenPIC)) == (((usqInt)anOpenPIC))) { (prevPIC->nextOpenPIC = (anOpenPIC->nextOpenPIC)); return null; } prevPIC = ((CogMethod *) ((prevPIC->nextOpenPIC))); } while(1); return 0; } /* CogMethodZone>>#voidOpenPICList */ static void voidOpenPICList(void) { openPICList = null; } /* CogMethodZone>>#voidYoungReferrersPostTenureAll */ static void voidYoungReferrersPostTenureAll(void) { CogMethod *cogMethod; usqInt pointer; assert(youngReferrers <= limitAddress); pointer = youngReferrers; while (pointer < limitAddress) { cogMethod = ((CogMethod *) (longAt(pointer))); if (((cogMethod->cmType)) != CMFree) { (cogMethod->cmRefersToYoung = 0); } pointer += BytesPerWord; } youngReferrers = limitAddress; } /* CogMethodZone>>#whereIsMaybeCodeThing: */ char * whereIsMaybeCodeThing(sqInt anOop) { if (oopisGreaterThanOrEqualToandLessThan(anOop, codeBase, limitAddress)) { if (oopisLessThan(anOop, methodZoneBase)) { return " is in generated runtime"; } if (oopisLessThan(anOop, mzFreeStart)) { return " is in generated methods"; } if (oopisLessThan(anOop, youngReferrers)) { return " is in code zone"; } return " is in young referrers"; } return null; } /* CogObjectRepresentation>>#checkValidObjectReference: */ static sqInt NoDbgRegParms checkValidObjectReference(sqInt anOop) { return (!(isImmediate(anOop))) && ((heapMapAtWord(pointerForOop(anOop))) != 0); } /* CogObjectRepresentation>>#genCmpClassFloatCompactIndexR: */ static AbstractInstruction * NoDbgRegParms genCmpClassFloatCompactIndexR(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ClassFloatCompactIndex, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ClassFloatCompactIndex)); } return anInstruction; } /* CogObjectRepresentation>>#genCmpClassMethodContextCompactIndexR: */ static AbstractInstruction * NoDbgRegParms genCmpClassMethodContextCompactIndexR(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ClassMethodContextCompactIndex)); } return anInstruction; } /* CogObjectRepresentation>>#genDoubleArithmetic:preOpCheck: */ static sqInt NoDbgRegParms genDoubleArithmeticpreOpCheck(sqInt arithmeticOperator, AbstractInstruction *(*preOpCheckOrNil)(int rcvrReg, int argReg)) { AbstractInstruction *doOp; AbstractInstruction *jumpFailAlloc; AbstractInstruction *jumpFailCheck; AbstractInstruction *jumpFailClass; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpNonInt; jumpFailCheck = ((AbstractInstruction *) 0); jumpNonInt = ((AbstractInstruction *) 0); /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); jumpImmediate = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFailClass = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); /* begin Label */ doOp = genoperandoperand(Label, (labelCounter += 1), bytecodePC); if (!(preOpCheckOrNil == null)) { jumpFailCheck = preOpCheckOrNil(DPFPReg0, DPFPReg1); } genoperandoperand(arithmeticOperator, DPFPReg1, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* maybeGenConvertIfSmallFloatIn:scratchReg:into:andJumpTo: */ /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonInt = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(ClassReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, ClassReg, DPFPReg1); /* begin Jump: */ genoperand(Jump, ((sqInt)doOp)); jmpTarget(jumpFailAlloc, jmpTarget(jumpFailClass, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jmpTarget(jumpNonInt, ((AbstractInstruction *) (((jumpFailClass->operands))[0]))); if (!(preOpCheckOrNil == null)) { jmpTarget(jumpFailCheck, ((AbstractInstruction *) (((jumpFailClass->operands))[0]))); } return 0; } /* CogObjectRepresentation>>#genDoubleComparison:invert: */ static sqInt NoDbgRegParms genDoubleComparisoninvert(AbstractInstruction * NoDbgRegParms (*jumpOpcodeGenerator)(void *), sqInt invertComparison) { AbstractInstruction *anInstruction; AbstractInstruction *compare; sqInt constant; AbstractInstruction *jumpCond; AbstractInstruction *jumpFail; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpNonInt; jumpNonInt = ((AbstractInstruction *) 0); /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); jumpImmediate = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); if (invertComparison) { /* May need to invert for NaNs */ /* begin CmpRd:Rd: */ compare = genoperandoperand(CmpRdRd, DPFPReg0, DPFPReg1); } else { /* begin CmpRd:Rd: */ compare = genoperandoperand(CmpRdRd, DPFPReg1, DPFPReg0); } /* FP jumps are a little weird */ jumpCond = jumpOpcodeGenerator(0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCond, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* maybeGenConvertIfSmallFloatIn:scratchReg:into:andJumpTo: */ /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonInt = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, Arg0Reg, DPFPReg1); /* begin Jump: */ genoperand(Jump, ((sqInt)compare)); jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jmpTarget(jumpNonInt, ((AbstractInstruction *) (((jumpFail->operands))[0]))); return CompletePrimitive; } /* Get the method header (first word) of a CompiledMethod into headerReg. Deal with the method possibly being cogged. */ /* CogObjectRepresentation>>#genGetMethodHeaderOf:into:scratch: */ static sqInt NoDbgRegParms genGetMethodHeaderOfintoscratch(sqInt methodReg, sqInt headerReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpNotCogged; sqInt offset; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, BaseHeaderSize, methodReg, headerReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BaseHeaderSize)); } jumpNotCogged = genJumpSmallInteger(headerReg); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodHeader); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, headerReg, headerReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } jmpTarget(jumpNotCogged, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genLoadSlot:sourceReg:destReg: */ static sqInt NoDbgRegParms genLoadSlotsourceRegdestReg(sqInt index, sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, (index * BytesPerWord) + BaseHeaderSize, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } return 0; } /* CogObjectRepresentation>>#genPrimitiveAdd */ static sqInt genPrimitiveAdd(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); /* begin AddR:R: */ genoperandoperand(AddRR, ReceiverResultReg, ClassReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveAsFloat */ static sqInt genPrimitiveAsFloat(void) { AbstractInstruction *jumpFailAlloc; /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, TempReg, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFailAlloc, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genPrimitiveBitAnd */ static sqInt genPrimitiveBitAnd(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveBitOr */ static sqInt genPrimitiveBitOr(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin OrR:R: */ genoperandoperand(OrRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* rTemp := rArg0 rClass := tTemp rTemp := rTemp & 1 jz nonInt rClass >>= 1 cmp 0,rClass jge neg cmp 31,rClass // numSmallIntegerBits, jge for sign jge tooBig rTemp := rReceiver rTemp <<= rClass rTemp >>= rClass (arithmetic) cmp rTemp,rReceiver jnz ovfl rReceiver := rReceiver - 1 rReceiver := rReceiver <<= rClass rReceiver := rReceiver + 1 ret neg: rClass := 0 - rClass cmp 31,rClass // numSmallIntegerBits jge inRange rClass := 31 inRange rReceiver := rReceiver >>= rClass. rReceiver := rReceiver | smallIntegerTags. ret ovfl tooBig nonInt: fail */ /* CogObjectRepresentation>>#genPrimitiveBitShift */ static sqInt genPrimitiveBitShift(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *jumpInRange; AbstractInstruction *jumpNegative; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; AbstractInstruction *jumpTooBig; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpNegative))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpNegative: */ jumpNegative = genConditionalBranchoperand(JumpNegative, ((sqInt)0)); /* begin CmpCq:R: */ anInstruction1 = genoperandoperand(CmpCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } /* begin JumpGreaterOrEqual: */ jumpTooBig = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin LogicalShiftLeftR:R: */ genoperandoperand(LogicalShiftLeftRR, ClassReg, TempReg); /* begin ArithmeticShiftRightR:R: */ genoperandoperand(ArithmeticShiftRightRR, ClassReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, ReceiverResultReg); /* begin JumpNonZero: */ jumpOvfl = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); /* begin LogicalShiftLeftR:R: */ genoperandoperand(LogicalShiftLeftRR, ClassReg, ReceiverResultReg); genAddSmallIntegerTagsTo(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNegative, genoperand(NegateR, ClassReg)); /* begin CmpCq:R: */ anInstruction2 = genoperandoperand(CmpCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } /* begin JumpLessOrEqual: */ jumpInRange = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin MoveCq:R: */ anInstruction3 = genoperandoperand(MoveCqR, 0x1F /* numSmallIntegerBits */, ClassReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0x1F /* numSmallIntegerBits */)); } jmpTarget(jumpInRange, genoperandoperand(ArithmeticShiftRightRR, ClassReg, ReceiverResultReg)); genClearAndSetSmallIntegerTagsIn(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, jmpTarget(jumpTooBig, jmpTarget(jumpOvfl, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveBitXor */ static sqInt genPrimitiveBitXor(void) { AbstractInstruction *jumpNotSI; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); /* begin XorR:R: */ genoperandoperand(XorRR, Arg0Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveClass */ static sqInt genPrimitiveClass(void) { sqInt reg; sqInt reg1; reg = ReceiverResultReg; if (methodOrBlockNumArgs > 0) { if (methodOrBlockNumArgs > 1) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ reg1 = (reg = Arg0Reg); assert(0 < (numRegArgs())); } if ((genGetClassObjectOfintoscratchReginstRegIsReceiver(reg, ReceiverResultReg, TempReg, reg == ReceiverResultReg)) == BadRegisterSet) { genGetClassObjectOfintoscratchReginstRegIsReceiver(reg, ClassReg, TempReg, reg == ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* CogObjectRepresentation>>#genPrimitiveDiv */ static sqInt genPrimitiveDiv(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *convert; AbstractInstruction *jumpExact; AbstractInstruction *jumpIsSI; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } } /* begin JumpGreaterOrEqual: */ jumpSameSign = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } jmpTarget(jumpSameSign, (convert = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpIsSI = genJumpIsSmallIntegerValuescratch(TempReg, Arg1Reg); jmpTarget(jumpIsSI, convert); jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveDivide */ static sqInt genPrimitiveDivide(void) { AbstractInstruction *anInstruction; AbstractInstruction *jumpInexact; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOverflow; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpInexact = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); jumpOverflow = genJumpNotSmallIntegerValuescratch(TempReg, Arg1Reg); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOverflow, jmpTarget(jumpInexact, jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveEqual */ static sqInt genPrimitiveEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpZero, gJumpFPEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatAdd */ static sqInt genPrimitiveFloatAdd(void) { return genDoubleArithmeticpreOpCheck(AddRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveFloatDivide */ static sqInt genPrimitiveFloatDivide(void) { return genDoubleArithmeticpreOpCheck(DivRdRd, genDoubleFailIfZeroArgRcvrarg); } /* CogObjectRepresentation>>#genPrimitiveFloatEqual */ static sqInt genPrimitiveFloatEqual(void) { return genDoubleComparisoninvert(gJumpFPEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatGreaterOrEqual */ static sqInt genPrimitiveFloatGreaterOrEqual(void) { return genDoubleComparisoninvert(gJumpFPGreaterOrEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatGreaterThan */ static sqInt genPrimitiveFloatGreaterThan(void) { return genDoubleComparisoninvert(gJumpFPGreater, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatLessOrEqual */ static sqInt genPrimitiveFloatLessOrEqual(void) { return genDoubleComparisoninvert(gJumpFPGreaterOrEqual, 1); } /* CogObjectRepresentation>>#genPrimitiveFloatLessThan */ static sqInt genPrimitiveFloatLessThan(void) { return genDoubleComparisoninvert(gJumpFPGreater, 1); } /* CogObjectRepresentation>>#genPrimitiveFloatMultiply */ static sqInt genPrimitiveFloatMultiply(void) { return genDoubleArithmeticpreOpCheck(MulRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveFloatNotEqual */ static sqInt genPrimitiveFloatNotEqual(void) { return genDoubleComparisoninvert(gJumpFPNotEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveFloatSquareRoot */ static sqInt genPrimitiveFloatSquareRoot(void) { AbstractInstruction *jumpFailAlloc; /* inline processorHasDoublePrecisionFloatingPointSupport */ /* begin hasDoublePrecisionFloatingPointSupport */ ; genGetDoubleValueOfinto(ReceiverResultReg, DPFPReg0); /* begin SqrtRd: */ genoperand(SqrtRd, DPFPReg0); jumpFailAlloc = genAllocFloatValueintoscratchRegscratchReg(DPFPReg0, SendNumArgsReg, ClassReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFailAlloc, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentation>>#genPrimitiveFloatSubtract */ static sqInt genPrimitiveFloatSubtract(void) { return genDoubleArithmeticpreOpCheck(SubRdRd, null); } /* CogObjectRepresentation>>#genPrimitiveGreaterOrEqual */ static sqInt genPrimitiveGreaterOrEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpGreaterOrEqual, gJumpFPGreaterOrEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveGreaterThan */ static sqInt genPrimitiveGreaterThan(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpGreater, gJumpFPGreater, 0); } /* CogObjectRepresentation>>#genPrimitiveIdentical */ static sqInt genPrimitiveIdentical(void) { return genPrimitiveIdenticalOrNotIf(0); } /* CogObjectRepresentation>>#genPrimitiveLessOrEqual */ static sqInt genPrimitiveLessOrEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpLessOrEqual, gJumpFPGreaterOrEqual, 1); } /* CogObjectRepresentation>>#genPrimitiveLessThan */ static sqInt genPrimitiveLessThan(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpLess, gJumpFPGreater, 1); } /* CogObjectRepresentation>>#genPrimitiveMod */ static sqInt genPrimitiveMod(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpExact; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpSameSign; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genRemoveSmallIntegerTagsInScratchReg(ClassReg); /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, Arg1Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genRemoveSmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpGreaterOrEqual: */ jumpSameSign = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin XorR:R: */ genoperandoperand(XorRR, ClassReg, Arg1Reg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ClassReg); jmpTarget(jumpSameSign, jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genSetSmallIntegerTagsIn(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveMultiply */ static sqInt genPrimitiveMultiply(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(processorHasMultiplyAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); genRemoveSmallIntegerTagsInScratchReg(Arg1Reg); /* begin MulR:R: */ genMulRR(backEnd, Arg1Reg, ClassReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); genSetSmallIntegerTagsIn(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* subclasses override if they can */ /* CogObjectRepresentation>>#genPrimitiveNewMethod */ static sqInt genPrimitiveNewMethod(void) { return UnimplementedPrimitive; } /* CogObjectRepresentation>>#genPrimitiveNotEqual */ static sqInt genPrimitiveNotEqual(void) { return genSmallIntegerComparisonorDoubleComparisoninvert(JumpNonZero, gJumpFPNotEqual, 0); } /* CogObjectRepresentation>>#genPrimitiveNotIdentical */ static sqInt genPrimitiveNotIdentical(void) { return genPrimitiveIdenticalOrNotIf(1); } /* CogObjectRepresentation>>#genPrimitiveQuo */ static sqInt genPrimitiveQuo(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *convert; AbstractInstruction *jumpExact; AbstractInstruction *jumpIsSI; AbstractInstruction *jumpNotSI; AbstractInstruction *jumpZero; if (!(processorHasDivQuoRemAndMClassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ClassReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); genShiftAwaySmallIntegerTagsInScratchReg(ClassReg); if (!(setsConditionCodesFor(lastOpcode(), JumpZero))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpZero: */ jumpZero = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); genShiftAwaySmallIntegerTagsInScratchReg(TempReg); gDivRRQuoRem(ClassReg, TempReg, TempReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpExact = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin Label */ convert = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpExact, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpIsSI = genJumpIsSmallIntegerValuescratch(TempReg, Arg1Reg); jmpTarget(jumpIsSI, convert); jmpTarget(jumpZero, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genPrimitiveSubtract */ static sqInt genPrimitiveSubtract(void) { AbstractInstruction *jumpNotSI; AbstractInstruction *jumpOvfl; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSI = genJumpNotSmallInteger(Arg0Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, TempReg); /* begin JumpOverflow: */ jumpOvfl = genConditionalBranchoperand(JumpOverflow, ((sqInt)0)); genAddSmallIntegerTagsTo(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOvfl, jmpTarget(jumpNotSI, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentation>>#genSmallIntegerComparison: */ static sqInt NoDbgRegParms genSmallIntegerComparison(sqInt jumpOpcode) { AbstractInstruction *anInstruction; sqInt constant; AbstractInstruction *jumpFail; AbstractInstruction *jumpTrue; if (!(mclassIsSmallInteger())) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpFail = genJumpNotSmallInteger(Arg0Reg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); jumpTrue = genConditionalBranchoperand(jumpOpcode, 0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpTrue, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* Stack looks like return address */ /* CogObjectRepresentation>>#genSmallIntegerComparison:orDoubleComparison:invert: */ static sqInt NoDbgRegParms genSmallIntegerComparisonorDoubleComparisoninvert(sqInt jumpOpcode, AbstractInstruction * NoDbgRegParms (*jumpFPOpcodeGenerator)(void *), sqInt invertComparison) { AbstractInstruction *anInstruction; sqInt constant; AbstractInstruction *jumpCond; AbstractInstruction *jumpFail; AbstractInstruction *jumpNonInt; sqInt r; jumpNonInt = ((AbstractInstruction *) 0); r = genSmallIntegerComparison(jumpOpcode); if (r < 0) { return r; } # if defined(DPFPReg0) /* Fall through on non-SmallInteger argument. Argument may be a Float : let us check or fail */ jumpNonInt = genJumpImmediate(Arg0Reg); genGetCompactClassIndexNonImmOfinto(Arg0Reg, SendNumArgsReg); genCmpClassFloatCompactIndexR(SendNumArgsReg); /* begin JumpNonZero: */ jumpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genConvertSmallIntegerToIntegerInReg(ReceiverResultReg); /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, ReceiverResultReg, DPFPReg0); genGetDoubleValueOfinto(Arg0Reg, DPFPReg1); if (invertComparison) { /* May need to invert for NaNs */ /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg0, DPFPReg1); } else { /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg1, DPFPReg0); } /* FP jumps are a little weird */ jumpCond = jumpFPOpcodeGenerator(0); /* begin genMoveConstant:R: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCond, genMoveConstantR(trueObject(), ReceiverResultReg)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNonInt, jmpTarget(jumpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); # endif /* defined(DPFPReg0) */ return CompletePrimitive; } /* CogObjectRepresentation>>#isUnannotatableConstant: */ static sqInt NoDbgRegParms isUnannotatableConstant(CogSimStackEntry *simStackEntry) { return (((simStackEntry->type)) == SSConstant) && ((isImmediate((simStackEntry->constant))) || (!(shouldAnnotateObjectReference((simStackEntry->constant))))); } /* Character gets mapped to zero. See inlineCacheTagForInstance:. */ /* CogObjectRepresentationFor32BitSpur>>#classForInlineCacheTag: */ static sqInt NoDbgRegParms classForInlineCacheTag(sqInt inlineCacheTag) { return classOrNilAtIndex((inlineCacheTag == 0 ? characterTag() : inlineCacheTag)); } /* CogObjectRepresentationFor32BitSpur>>#genAddSmallIntegerTagsTo: */ static sqInt NoDbgRegParms genAddSmallIntegerTagsTo(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Set the SmallInteger tag bits when the tag bits may be filled with garbage. */ /* CogObjectRepresentationFor32BitSpur>>#genClearAndSetSmallIntegerTagsIn: */ static sqInt NoDbgRegParms genClearAndSetSmallIntegerTagsIn(sqInt scratchReg) { return genSetSmallIntegerTagsIn(scratchReg); } /* Convert the Character in reg to a SmallInteger, assuming the Character's value is a valid character. */ /* self assume: objectMemory smallIntegerTag = 1 */ /* CogObjectRepresentationFor32BitSpur>>#genConvertCharacterToSmallIntegerInReg: */ static void NoDbgRegParms genConvertCharacterToSmallIntegerInReg(sqInt reg) { assert(((numCharacterBits()) + 1) == (numSmallIntegerBits())); /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, 1, reg); } /* CogObjectRepresentationFor32BitSpur>>#genConvertIntegerToSmallIntegerInReg: */ static sqInt NoDbgRegParms genConvertIntegerToSmallIntegerInReg(sqInt reg) { AbstractInstruction *anInstruction; /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, 1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Convert the SmallInteger in reg to a Character, assuming the SmallInteger's value is a valid character. */ /* self assume: objectMemory smallIntegerTag = 1 */ /* CogObjectRepresentationFor32BitSpur>>#genConvertSmallIntegerToCharacterInReg: */ static void NoDbgRegParms genConvertSmallIntegerToCharacterInReg(sqInt reg) { assert(((numCharacterBits()) + 1) == (numSmallIntegerBits())); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, reg); } /* CogObjectRepresentationFor32BitSpur>>#genConvertSmallIntegerToIntegerInReg: */ static sqInt NoDbgRegParms genConvertSmallIntegerToIntegerInReg(sqInt reg) { /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, reg); return 0; } /* Fetch the instance's identity hash into destReg, encoded as a SmallInteger. */ /* Get header word in scratchReg */ /* CogObjectRepresentationFor32BitSpur>>#genGetHashFieldNonImmOf:asSmallIntegerInto: */ static sqInt NoDbgRegParms genGetHashFieldNonImmOfasSmallIntegerInto(sqInt instReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 4, instReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(4)); } /* begin AndCq:R: */ quickConstant = identityHashHalfWordMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } genConvertIntegerToSmallIntegerInReg(destReg); return 0; } /* Fetch the instance's identity hash into destReg, unencoded. */ /* CogObjectRepresentationFor32BitSpur>>#genGetHashFieldNonImmOf:into: */ static sqInt NoDbgRegParms genGetHashFieldNonImmOfinto(sqInt instReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 4, instReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(4)); } /* begin AndCq:R: */ quickConstant = identityHashHalfWordMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return 0; } /* Extract the inline cache tag for the object in sourceReg into destReg. The inline cache tag for a given object is the value loaded in inline caches to distinguish objects of different classes. In Spur this is either the tags for immediates, (with 1 & 3 collapsed to 1 for SmallIntegers, and 2 collapsed to 0 for Characters), or the receiver's classIndex. If forEntry is true answer the entry label at which control is to enter (cmEntryOffset). If forEntry is false, control enters at the start. If forEntry is true, generate something like this: Limm: andl $0x1, rDest j Lcmp Lentry: movl rSource, rDest andl $0x3, rDest jnz Limm movl 0(%edx), rDest andl $0x3fffff, rDest Lcmp: If forEntry is false, generate something like the following. At least on a 2.2GHz Intel Core i7 the following is slightly faster than the above, 136m sends/sec vs 130m sends/sec for nfib in tinyBenchmarks Lentry: movl rSource, rDest andl $0x3, rDest jz LnotImm andl $1, rDest j Lcmp LnotImm: movl 0(%edx), rDest andl $0x3fffff, rDest Lcmp: But we expect most SmallInteger arithmetic to be performed in-line and so prefer the version that is faster for non-immediates (because it branches for immediates only). */ /* CogObjectRepresentationFor32BitSpur>>#genGetInlineCacheClassTagFrom:into:forEntry: */ static AbstractInstruction * NoDbgRegParms genGetInlineCacheClassTagFromintoforEntry(sqInt sourceReg, sqInt destReg, sqInt forEntry) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *entryLabel; AbstractInstruction *immLabel; AbstractInstruction *jumpCompare; AbstractInstruction *jumpNotImm; sqInt quickConstant; if (forEntry) { /* begin AlignmentNops: */ genoperand(AlignmentNops, BytesPerWord); /* begin Label */ immLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, 1, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin Jump: */ jumpCompare = genoperand(Jump, ((sqInt)0)); /* begin AlignmentNops: */ genoperand(AlignmentNops, BytesPerWord); /* begin Label */ entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); gAndCqRR(tagMask(), sourceReg, destReg); /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)immLabel)); flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } jmpTarget(jumpCompare, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } else { /* begin Label */ entryLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); gAndCqRR(tagMask(), sourceReg, destReg); /* begin JumpZero: */ jumpNotImm = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AndCqR, 1, destReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } /* begin Jump: */ jumpCompare = genoperand(Jump, ((sqInt)0)); flag("endianness"); jmpTarget(jumpNotImm, checkQuickConstantforInstruction(0, genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg))); jmpTarget(jumpCompare, gAndCqR(classIndexMask(), destReg)); } return entryLabel; } /* Get the size in byte-sized slots of the object in srcReg into destReg. srcReg may equal destReg. destReg <- numSlots << self shiftForWord - (fmt bitAnd: 3). Assumes the object in srcReg has a byte format, i.e. 16 to 23 or 24 to 31 */ /* CogObjectRepresentationFor32BitSpur>>#genGetNumBytesOf:into: */ static sqInt NoDbgRegParms genGetNumBytesOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *jmp; sqInt quickConstant; genGetRawSlotSizeOfNonImminto(srcReg, destReg); /* begin CmpCq:R: */ quickConstant = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jmp = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genGetOverflowSlotsOfinto(srcReg, destReg); jmpTarget(jmp, gLogicalShiftLeftCqR(shiftForWord(), destReg)); genGetBitsofFormatByteOfinto(3, srcReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, destReg); return 0; } /* CogObjectRepresentationFor32BitSpur>>#genGetOverflowSlotsOf:into: */ static sqInt NoDbgRegParms genGetOverflowSlotsOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, -BaseHeaderSize, srcReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(-BaseHeaderSize)); } return 0; } /* Generate a test for aRegister containing an integer value in the SmallInteger range, and a jump if so, answering the jump. c.f. Spur32BitMemoryManager>>isIntegerValue: */ /* CogObjectRepresentationFor32BitSpur>>#genJumpIsSmallIntegerValue:scratch: */ static AbstractInstruction * NoDbgRegParms genJumpIsSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg) { return (/* begin MoveR:R: */ genoperandoperand(MoveRR, aRegister, scratchReg), /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, scratchReg), /* begin XorR:R: */ genoperandoperand(XorRR, aRegister, scratchReg), /* begin JumpGreaterOrEqual: */ genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0))); } /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallIntegerInScratchReg: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerInScratchReg(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } /* Generate a test for aRegister containing an integer value outside the SmallInteger range, and a jump if so, answering the jump. c.f. Spur32BitMemoryManager>>isIntegerValue: */ /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallIntegerValue:scratch: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallIntegerValuescratch(sqInt aRegister, sqInt scratchReg) { return (/* begin MoveR:R: */ genoperandoperand(MoveRR, aRegister, scratchReg), /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, scratchReg), /* begin XorR:R: */ genoperandoperand(XorRR, aRegister, scratchReg), /* begin JumpLess: */ genConditionalBranchoperand(JumpLess, ((sqInt)0))); } /* CogObjectRepresentationFor32BitSpur>>#genJumpNotSmallInteger: */ static AbstractInstruction * NoDbgRegParms genJumpNotSmallInteger(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } /* CogObjectRepresentationFor32BitSpur>>#genJumpSmallInteger: */ static AbstractInstruction * NoDbgRegParms genJumpSmallInteger(sqInt aRegister) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, 1, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtPut */ static sqInt genPrimitiveAtPut(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction *jumpArrayOutOfBounds; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpBytesOutOfRange; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction *jumpHasFixedFields; AbstractInstruction *jumpImmediate; AbstractInstruction * jumpImmutable; AbstractInstruction *jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction *jumpIsContext; AbstractInstruction *jumpIsShorts; AbstractInstruction * jumpNonSmallIntegerValue; AbstractInstruction *jumpNotIndexableBits; AbstractInstruction *jumpNotIndexablePointers; AbstractInstruction * jumpNotPointers; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpShortsOutOfRange; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordsOutOfRange; AbstractInstruction *methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant10; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; jumpImmutable = ((AbstractInstruction *) 0); nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant10 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperand(TstCqR, quickConstant10, TempReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(quickConstant10)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpAbove: */ jumpNotPointers = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg1Reg, TempReg, 0); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ jumpNotIndexablePointers = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin JumpNonZero: */ jumpHasFixedFields = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant2 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, quickConstant2, Arg0Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpHasFixedFields, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, formatReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant3)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AddCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant4)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg0Reg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotPointers, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonSmallIntegerValue = genJumpNotSmallInteger(Arg1Reg); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, quickConstant5, formatReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant7 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(CmpCqR, quickConstant7, formatReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant7)); } /* begin JumpBelow: */ jumpNotIndexableBits = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); if (!(setsConditionCodesFor(lastOpcode(), JumpLess))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin AddCq:R: */ quickConstant8 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant8, Arg0Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant8)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, checkQuickConstantforInstruction((((usqInt)0xFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFF << 1) | 1), Arg1Reg))); /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), nSlotsOrBytesReg); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant9 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, quickConstant9, formatReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant9)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ methodInBounds = genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, checkQuickConstantforInstruction((((usqInt)0xFFFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFFFF << 1) | 1), Arg1Reg))); /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, nSlotsOrBytesReg); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsCompiledMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpIsContext, jmpTarget(jumpNotIndexableBits, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpWordsOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexablePointers, jmpTarget(jumpNonSmallIntegerValue, jmpTarget(jumpFixedFieldsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))))))))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the code for primitives 61 & 165, at:put:/basicAt:put: & integerAt:put:. If signedVersion is true then generate signed accesses to the bits classes (a la 164 & 165). If signedVersion is false, generate unsigned accesses (a la 60, 61, 63 & 64). */ /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtPutSigned: */ static sqInt NoDbgRegParms genPrimitiveAtPutSigned(sqInt signedVersion) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction * jumpArrayOutOfBounds; AbstractInstruction * jumpBadIndex; AbstractInstruction * jumpBytesOutOfBounds; AbstractInstruction * jumpBytesOutOfRange; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction * jumpHasFixedFields; AbstractInstruction * jumpImmediate; AbstractInstruction * jumpImmutable; AbstractInstruction * jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction * jumpIsContext; AbstractInstruction * jumpIsShorts; AbstractInstruction * jumpNonSmallIntegerValue; AbstractInstruction * jumpNotIndexableBits; AbstractInstruction * jumpNotIndexablePointers; AbstractInstruction * jumpNotPointers; AbstractInstruction * jumpShortsOutOfBounds; AbstractInstruction * jumpShortsOutOfRange; AbstractInstruction * jumpWordsOutOfBounds; AbstractInstruction * jumpWordsOutOfRange; AbstractInstruction * methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant10; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; jumpImmutable = ((AbstractInstruction *) 0); jumpWordsOutOfRange = ((AbstractInstruction *) 0); nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant10 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperand(TstCqR, quickConstant10, TempReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(quickConstant10)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant)); } /* begin JumpAbove: */ jumpNotPointers = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg1Reg, TempReg, 0); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ jumpNotIndexablePointers = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin JumpNonZero: */ jumpHasFixedFields = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant2 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, quickConstant2, Arg0Reg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant2)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpHasFixedFields, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(AndCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant3)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant4)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg0Reg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, Arg1Reg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotPointers, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNonSmallIntegerValue = genJumpNotSmallInteger(Arg1Reg); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, quickConstant5, formatReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant7 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(CmpCqR, quickConstant7, formatReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant7)); } /* begin JumpBelow: */ jumpNotIndexableBits = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); if (!signedVersion) { if (!(setsConditionCodesFor(lastOpcode(), JumpLess))) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); } /* begin AddCq:R: */ quickConstant8 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, quickConstant8, Arg0Reg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(quickConstant8)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } if (signedVersion) { jmpTarget(jumpIsBytes, genoperandoperand(MoveRR, SendNumArgsReg, TempReg)); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 7, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(1)); } } else { jmpTarget(jumpIsBytes, checkQuickConstantforInstruction((((usqInt)0xFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFF << 1) | 1), Arg1Reg))); } /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), nSlotsOrBytesReg); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant9 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperand(CmpCqR, quickConstant9, formatReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(quickConstant9)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ methodInBounds = genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } if (signedVersion) { jmpTarget(jumpIsShorts, genoperandoperand(MoveRR, SendNumArgsReg, TempReg)); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 15, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } } else { jmpTarget(jumpIsShorts, checkQuickConstantforInstruction((((usqInt)0xFFFF << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)0xFFFF << 1) | 1), Arg1Reg))); } /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, nSlotsOrBytesReg); /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsCompiledMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpIsContext, jmpTarget(jumpNotIndexableBits, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexablePointers, jmpTarget(jumpNonSmallIntegerValue, jmpTarget(jumpFixedFieldsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))))))); if (!signedVersion) { jmpTarget(jumpWordsOutOfRange, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); } # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpIsContext->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the code for primitives 60 & 164, at:/basicAt: & integerAt:. If signedVersion is true then generate signed accesses to the bits classes (a la 164 & 165). If signedVersion is false, generate unsigned accesses (a la 60, 61, 63 & 64). */ /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveAtSigned: */ static sqInt NoDbgRegParms genPrimitiveAtSigned(sqInt signedVersion) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction * convertToIntAndReturn; AbstractInstruction * first; AbstractInstruction * first1; sqInt formatReg; AbstractInstruction * jumpArrayOutOfBounds; AbstractInstruction * jumpBadIndex; AbstractInstruction * jumpBytesOutOfBounds; AbstractInstruction * jumpFixedFieldsOutOfBounds; AbstractInstruction * jumpHasFixedFields; AbstractInstruction * jumpImmediate; AbstractInstruction * jumpIsArray; AbstractInstruction * jumpIsBytes; AbstractInstruction * jumpIsContext; AbstractInstruction * jumpIsMethod; AbstractInstruction * jumpIsShorts; AbstractInstruction * jumpIsWords; AbstractInstruction * jumpNotIndexable; AbstractInstruction * jumpShortsOutOfBounds; AbstractInstruction * jumpWordsOutOfBounds; AbstractInstruction * jumpWordTooBig; AbstractInstruction * methodInBounds; sqInt nSlotsOrBytesReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; sqInt quickConstant8; sqInt quickConstant9; nSlotsOrBytesReg = ClassReg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpImmediate = genJumpImmediate(ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg1Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); genGetNumSlotsOfinto(ReceiverResultReg, nSlotsOrBytesReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpIsArray = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin JumpBelow: */ jumpNotIndexable = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin JumpBelowOrEqual: */ jumpHasFixedFields = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant4, formatReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant4)); } /* begin JumpAboveOrEqual: */ jumpIsWords = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); jmpTarget(jumpNotIndexable, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin Jump: */ jumpNotIndexable = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsArray, genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg)); /* begin JumpBelowOrEqual: */ jumpArrayOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant5 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, quickConstant5, Arg1Reg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant5)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), nSlotsOrBytesReg)); gAndCqRR(BytesPerWord - 1, formatReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant6, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpIsMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BaseHeaderSize, Arg1Reg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize)); } methodInBounds = anInstruction8; /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (signedVersion) { /* begin SignExtend8R:R: */ /* begin LogicalShiftLeftCq:R: */ first = genoperandoperand(LogicalShiftLeftCqR, (BytesPerWord * 8) - 8, ReceiverResultReg); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, (BytesPerWord * 8) - 8, ReceiverResultReg); goto l8; l8: /* end SignExtend8R:R: */; } /* begin Label */ convertToIntAndReturn = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, nSlotsOrBytesReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, 1, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveM16rR, BaseHeaderSize, ReceiverResultReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(BaseHeaderSize)); } if (signedVersion) { /* begin SignExtend16R:R: */ /* begin LogicalShiftLeftCq:R: */ first1 = genoperandoperand(LogicalShiftLeftCqR, (BytesPerWord * 8) - 16, ReceiverResultReg); /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, (BytesPerWord * 8) - 16, ReceiverResultReg); goto l13; l13: /* end SignExtend16R:R: */; } /* begin Jump: */ genoperand(Jump, ((sqInt)convertToIntAndReturn)); jmpTarget(jumpIsWords, genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg)); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant7 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, quickConstant7, Arg1Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant7)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, TempReg); jumpWordTooBig = jumpNotSmallIntegerUnsignedValueInRegister(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)convertToIntAndReturn)); jmpTarget(jumpHasFixedFields, gAndCqR(classIndexMask(), TempReg)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, formatReg); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, nSlotsOrBytesReg); genGetClassObjectOfClassIndexintoscratchReg(formatReg, nSlotsOrBytesReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, nSlotsOrBytesReg, formatReg); /* begin PopR: */ genoperand(PopR, nSlotsOrBytesReg); genConvertSmallIntegerToIntegerInReg(formatReg); /* begin AndCq:R: */ quickConstant8 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AndCqR, quickConstant8, formatReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant8)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, nSlotsOrBytesReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelowOrEqual: */ jumpFixedFieldsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, formatReg, Arg1Reg); /* begin AddCq:R: */ quickConstant9 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, quickConstant9, Arg1Reg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant9)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsMethod, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); getLiteralCountOfplusOneinBytesintoscratch(ReceiverResultReg, 1, 1, nSlotsOrBytesReg, TempReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, nSlotsOrBytesReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)methodInBounds)); jmpTarget(jumpWordTooBig, jmpTarget(jumpFixedFieldsOutOfBounds, jmpTarget(jumpArrayOutOfBounds, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexable, jmpTarget(jumpIsContext, jmpTarget(jumpBadIndex, jmpTarget(jumpImmediate, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))))); return 0; } /* Arguably we should fail for immediates, but so far no one has complained, so... */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveIdentityHash */ static sqInt genPrimitiveIdentityHash(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction * inst; AbstractInstruction *jumpImm; AbstractInstruction *jumpNotSet; AbstractInstruction *jumpSI; AbstractInstruction * ret; jumpImm = genJumpImmediate(ReceiverResultReg); genGetHashFieldNonImmOfasSmallIntegerInto(ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, ConstZero, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(ConstZero)); } /* begin JumpZero: */ jumpNotSet = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ ret = genoperand(RetN, 0); } else { /* begin RetN: */ ret = genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImm, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSI = genJumpSmallInteger(ReceiverResultReg); jmpTarget(jumpSI, ret); genConvertCharacterToSmallIntegerInReg(ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)ret)); jmpTarget(jumpNotSet, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!(primitiveIndex == 75)) { return 0; } /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceNewHashTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* :Assume the receiuver is never a SmallInteger. One would use ^self for that. */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveImmediateAsInteger */ static sqInt genPrimitiveImmediateAsInteger(void) { genConvertCharacterToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* Implement primitiveNew for convenient cases: - the receiver has a hash - the receiver is fixed size (excluding ephemerons to save instructions & miniscule time) - single word header/num slots < numSlotsMask - the result fits in eden (actually below scavengeThreshold) */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveNew */ static sqInt genPrimitiveNew(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt byteSizeReg; AbstractInstruction *fillLoop; sqInt fillReg; sqInt halfHeaderReg; sqInt instSpecReg; AbstractInstruction *jumpHasSlots; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpTooBig; AbstractInstruction *jumpUnhashed; AbstractInstruction *jumpVariableOrEphemeron; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; AbstractInstruction *skip; if (methodOrBlockNumArgs != 0) { return UnimplementedPrimitive; } /* inst spec will hold class's instance specification, then byte size and finally end of new object. */ halfHeaderReg = (fillReg = SendNumArgsReg); /* get freeStart as early as possible so as not to wait later... */ instSpecReg = (byteSizeReg = ClassReg); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, Arg1Reg)); genGetHashFieldNonImmOfinto(ReceiverResultReg, halfHeaderReg); /* begin JumpZero: */ jumpUnhashed = genConditionalBranchoperand(JumpZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ReceiverResultReg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin LogicalShiftRightCq:R: */ quickConstant = fixedFieldsFieldWidth(); genoperandoperand(LogicalShiftRightCqR, quickConstant, TempReg); /* begin AndCq:R: */ quickConstant2 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant2)); } /* begin AndCq:R: */ quickConstant3 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant3, instSpecReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant3)); } /* begin CmpCq:R: */ quickConstant4 = nonIndexablePointerFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant4)); } /* begin JumpAbove: */ jumpVariableOrEphemeron = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant5, instSpecReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant5)); } /* begin JumpAboveOrEqual: */ jumpTooBig = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ quickConstant1 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant1, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, 0, byteSizeReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpHasSlots = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, BaseHeaderSize * 2, byteSizeReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BaseHeaderSize * 2)); } /* begin Jump: */ skip = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasSlots, genoperandoperand(MoveRR, byteSizeReg, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, byteSizeReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, byteSizeReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), byteSizeReg); jmpTarget(skip, gLogicalShiftLeftCqR(numSlotsHalfShift(), halfHeaderReg)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, byteSizeReg); /* begin CmpCq:R: */ quickConstant6 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant6, byteSizeReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, byteSizeReg, address1)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(LoadEffectiveAddressMwrR, BaseHeaderSize, ReceiverResultReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveCq:R: */ quickConstant7 = nilObject(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(MoveCqR, quickConstant7, fillReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant7)); } /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperandoperand(MoveRMwr, fillReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(0)); } fillLoop = anInstruction13; /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperandoperand(MoveRMwr, fillReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, 8, Arg1Reg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(8)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, byteSizeReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)fillLoop)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpUnhashed, jmpTarget(jumpVariableOrEphemeron, jmpTarget(jumpTooBig, jmpTarget(jumpNoSpace, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return 0; } /* Implement primitiveNewWithArg for convenient cases: - the receiver has a hash - the receiver is variable and not compiled method - single word header/num slots < numSlotsMask - the result fits in eden See superclass method for dynamic frequencies of formats. For the moment we implement only arrayFormat, firstByteFormat & firstLongFormat */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveNewWithArg */ static sqInt genPrimitiveNewWithArg(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt byteSizeReg; AbstractInstruction *fillLoop; sqInt fillReg; sqInt halfHeaderReg; sqInt instSpecReg; AbstractInstruction *jumpArrayFormat; AbstractInstruction *jumpArrayTooBig; AbstractInstruction *jumpByteFormat; AbstractInstruction *jumpBytePrepDone; AbstractInstruction *jumpByteTooBig; AbstractInstruction *jumpFailCuzFixed; AbstractInstruction *jumpHasSlots; AbstractInstruction *jumpLongPrepDone; AbstractInstruction *jumpLongTooBig; AbstractInstruction *jumpNElementsNonInt; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpUnhashed; sqInt literal; sqInt maxSlots; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; sqInt quickConstant7; AbstractInstruction *skip; sqInt wordConstant; if (methodOrBlockNumArgs != 1) { return UnimplementedPrimitive; } /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* inst spec will hold class's instance specification and then byte size and finally numSlots half of header */ halfHeaderReg = (fillReg = SendNumArgsReg); /* The max slots we'll allocate here are those for a single header */ instSpecReg = (byteSizeReg = ClassReg); /* get freeStart as early as possible so as not to wait later... */ maxSlots = (numSlotsMask()) - 1; /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, Arg1Reg)); genGetHashFieldNonImmOfinto(ReceiverResultReg, halfHeaderReg); /* begin JumpZero: */ jumpUnhashed = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* get class's format inst var for inst spec (format field) */ jumpNElementsNonInt = genJumpNotSmallInteger(Arg0Reg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ReceiverResultReg, instSpecReg); /* begin LogicalShiftRightCq:R: */ quickConstant = (fixedFieldsFieldWidth()) + 1 /* numSmallIntegerTagBits */; genoperandoperand(LogicalShiftRightCqR, quickConstant, instSpecReg); /* begin AndCq:R: */ quickConstant3 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant3, instSpecReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant3)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, TempReg); /* begin LogicalShiftLeftCq:R: */ quickConstant1 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant1, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); /* begin CmpCq:R: */ quickConstant4 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant4, instSpecReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant4)); } /* begin JumpZero: */ jumpArrayFormat = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant5, instSpecReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant5)); } /* begin JumpZero: */ jumpByteFormat = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant6 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant6, instSpecReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant6)); } /* begin JumpNonZero: */ jumpFailCuzFixed = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)maxSlots << 1) | 1); anInstruction4 = genoperandoperand(CmpCqR, (((usqInt)maxSlots << 1) | 1), Arg0Reg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(literal)); } /* begin JumpAbove: */ jumpLongTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperand(PushCq, 0); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin Jump: */ jumpLongPrepDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpByteFormat, checkQuickConstantforInstruction((((usqInt)(maxSlots * BytesPerWord) << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)(maxSlots * BytesPerWord) << 1) | 1), Arg0Reg))); /* begin JumpAbove: */ jumpByteTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, BytesPerWord, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord)); } /* begin SubR:R: */ genoperandoperand(SubRR, instSpecReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, BytesPerWord - 1, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BytesPerWord - 1)); } /* begin LogicalShiftLeftCq:R: */ quickConstant2 = formatShift(); genoperandoperand(LogicalShiftLeftCqR, quickConstant2, TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AddCqR, BytesPerWord - 1, instSpecReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BytesPerWord - 1)); } /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, shiftForWord(), instSpecReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperand(PushCq, 0); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(0)); } /* begin Jump: */ jumpBytePrepDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpArrayFormat, checkQuickConstantforInstruction((((usqInt)maxSlots << 1) | 1), genoperandoperand(CmpCqR, (((usqInt)maxSlots << 1) | 1), Arg0Reg))); /* begin JumpAbove: */ jumpArrayTooBig = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, instSpecReg); /* begin PushCw: */ wordConstant = nilObject(); /* begin gen:literal: */ checkLiteralforInstruction(wordConstant, genoperand(PushCw, wordConstant)); jmpTarget(jumpBytePrepDone, jmpTarget(jumpLongPrepDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instSpecReg, halfHeaderReg); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(CmpCqR, 0, byteSizeReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpHasSlots = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(MoveCqR, BaseHeaderSize * 2, byteSizeReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(BaseHeaderSize * 2)); } /* begin Jump: */ skip = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasSlots, genoperandoperand(MoveRR, byteSizeReg, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, byteSizeReg); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, byteSizeReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), byteSizeReg); jmpTarget(skip, gLogicalShiftLeftCqR(numSlotsHalfShift(), halfHeaderReg)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, byteSizeReg); /* begin CmpCq:R: */ quickConstant7 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(CmpCqR, quickConstant7, byteSizeReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(quickConstant7)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, byteSizeReg, address1)); /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveRMwr, halfHeaderReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(4)); } /* begin PopR: */ genoperand(PopR, fillReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(LoadEffectiveAddressMwrR, BaseHeaderSize, ReceiverResultReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveRMwr, fillReg, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(0)); } fillLoop = anInstruction18; /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, fillReg, 4, Arg1Reg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(AddCqR, 8, Arg1Reg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(8)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, byteSizeReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)fillLoop)); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNoSpace, genoperand(PopR, TempReg)); jmpTarget(jumpUnhashed, jmpTarget(jumpFailCuzFixed, jmpTarget(jumpArrayTooBig, jmpTarget(jumpByteTooBig, jmpTarget(jumpLongTooBig, jmpTarget(jumpNElementsNonInt, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))); return 0; } /* Implement primitiveShallowCopy/primitiveClone for convenient cases: - the receiver is not a context - the receiver is not a compiled method - the result fits in eden (actually below scavengeThreshold) */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveShallowCopy */ static sqInt genPrimitiveShallowCopy(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction *continuance; AbstractInstruction *copyLoop; sqInt formatReg; AbstractInstruction * jumpEmpty; AbstractInstruction *jumpImmediate; AbstractInstruction *jumpIsMethod; AbstractInstruction *jumpNoSpace; AbstractInstruction *jumpTooBig; AbstractInstruction *jumpVariable; sqInt ptrReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt resultReg; sqInt slotsReg; jumpImmediate = genJumpImmediate(ReceiverResultReg); resultReg = Arg0Reg; /* get freeStart as early as possible so as not to wait later... */ slotsReg = Arg1Reg; /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, resultReg)); genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (ptrReg = (formatReg = SendNumArgsReg)), NoReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpIsMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = indexablePointersFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpVariable = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin Label */ continuance = genoperandoperand(Label, (labelCounter += 1), bytecodePC); genGetRawSlotSizeOfNonImminto(ReceiverResultReg, slotsReg); /* begin CmpCq:R: */ quickConstant2 = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, slotsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpZero: */ jumpTooBig = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, 0, slotsReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0)); } /* begin JumpZero: */ jumpEmpty = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, slotsReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AndCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } /* begin AddR:R: */ genoperandoperand(AddRR, TempReg, slotsReg); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, BaseHeaderSize / BytesPerWord, slotsReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize / BytesPerWord)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), slotsReg); /* begin AddR:R: */ genoperandoperand(AddRR, resultReg, slotsReg); /* begin CmpCq:R: */ quickConstant3 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant3, slotsReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpNoSpace = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, resultReg, ptrReg); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, slotsReg, address1)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(SubCqR, BytesPerWord * 2, slotsReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveMwrR, 0, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant4 = (((sqInt)((usqInt)((formatMask())) << (formatShift())))) + (classIndexMask()); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, 0, resultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveMwrR, BytesPerWord, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(BytesPerWord)); } /* begin AndCq:R: */ quickConstant5 = ((sqInt)((usqInt)((numSlotsMask())) << (numSlotsHalfShift()))); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(AndCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperandoperand(MoveRMwr, TempReg, BytesPerWord, resultReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(BytesPerWord)); } /* begin Label */ copyLoop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(AddCqR, BytesPerWord * 2, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperand(AddCqR, BytesPerWord * 2, ptrReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BytesPerWord * 2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, 0, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ptrReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, BytesPerWord, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, TempReg, BytesPerWord, ptrReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BytesPerWord)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, ptrReg, slotsReg); /* begin JumpAbove: */ genConditionalBranchoperand(JumpAbove, ((sqInt)copyLoop)); /* begin MoveR:R: */ genoperandoperand(MoveRR, resultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpVariable, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genGetClassIndexOfNonImminto(ReceiverResultReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, ClassReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)continuance)); jmpTarget(jumpImmediate, jmpTarget(jumpNoSpace, jmpTarget(jumpIsMethod, jmpTarget(jumpTooBig, jmpTarget(jumpEmpty, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); return 0; } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveStringAt */ static sqInt genPrimitiveStringAt(void) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction *done; sqInt formatReg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpIsBytes; AbstractInstruction *jumpIsShorts; AbstractInstruction *jumpNotIndexable; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpWordsDone; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordTooBig; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, Arg1Reg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genConvertSmallIntegerToIntegerInReg(Arg1Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 1, Arg1Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpGreaterOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpGreaterOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpNotIndexable = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddCq:R: */ quickConstant3 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, quickConstant3, Arg1Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant3)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg1Reg, ReceiverResultReg, TempReg); jumpWordTooBig = jumpNotCharacterUnsignedValueInRegister(TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, ReceiverResultReg); /* begin Jump: */ jumpWordsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, BytesPerWord - 1, formatReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AddCqR, BaseHeaderSize, Arg1Reg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, Arg1Reg, ReceiverResultReg, ReceiverResultReg); jmpTarget(jumpWordsDone, (done = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genConvertIntegerToCharacterInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(AndCqR, (BytesPerWord / 1) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((BytesPerWord / 1) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg1Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg1Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperandoperand(MoveM16rR, BaseHeaderSize, ReceiverResultReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(BaseHeaderSize)); } /* begin Jump: */ genoperand(Jump, ((sqInt)done)); jmpTarget(jumpWordTooBig, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, jmpTarget(jumpNotIndexable, jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))); return CompletePrimitive; } /* c.f. StackInterpreter>>stSizeOf: SpurMemoryManager>>lengthOf:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationFor32BitSpur>>#genPrimitiveStringAtPut */ static sqInt genPrimitiveStringAtPut(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt formatReg; AbstractInstruction *jumpBadArg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBytesOutOfBounds; AbstractInstruction *jumpBytesOutOfRange; AbstractInstruction * jumpImmutable; AbstractInstruction *jumpIsBytes; AbstractInstruction * jumpIsCompiledMethod; AbstractInstruction *jumpIsShorts; AbstractInstruction * jumpNotString; AbstractInstruction *jumpShortsOutOfBounds; AbstractInstruction *jumpShortsOutOfRange; AbstractInstruction *jumpWordsOutOfBounds; AbstractInstruction *jumpWordsOutOfRange; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; jumpImmutable = ((AbstractInstruction *) 0); /* begin genLoadArgAtDepth:into: */ assert(1 < (numRegArgs())); /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); jumpBadArg = genJumpNotCharacterInScratchReg(TempReg); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } # if IMMUTABILITY genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), TempReg); /* begin genJumpBaseHeaderImmutable: */ quickConstant5 = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(TstCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(quickConstant5)); } /* begin JumpNonZero: */ jumpImmutable = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); # else /* IMMUTABILITY */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, (formatReg = SendNumArgsReg), NoReg); # endif /* IMMUTABILITY */ genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, formatReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpBelow: */ jumpNotString = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant1, formatReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpAboveOrEqual: */ jumpIsCompiledMethod = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant2, formatReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin JumpAboveOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant3, formatReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, 0, Arg1Reg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin JumpLess: */ jumpWordsOutOfRange = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpWordsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin AddCq:R: */ quickConstant4 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, quickConstant4, Arg0Reg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant4)); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsShorts, gCmpCqR(characterObjectOf(0xFFFF), Arg1Reg)); /* begin JumpAbove: */ jumpShortsOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - 1, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, (BytesPerWord / 2) - 1, formatReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral((BytesPerWord / 2) - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpShortsOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRM16r, TempReg, BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIsBytes, gCmpCqR(characterObjectOf(0xFF), Arg1Reg)); /* begin JumpAbove: */ jumpBytesOutOfRange = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, BytesPerWord - 1, formatReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, formatReg, ClassReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ClassReg); /* begin JumpBelowOrEqual: */ jumpBytesOutOfBounds = genConditionalBranchoperand(JumpBelowOrEqual, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, TempReg); genConvertCharacterToCodeInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(AddCqR, BaseHeaderSize, Arg0Reg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, Arg0Reg, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotString, jmpTarget(jumpBytesOutOfRange, jmpTarget(jumpShortsOutOfRange, jmpTarget(jumpWordsOutOfRange, jmpTarget(jumpIsCompiledMethod, jmpTarget(jumpBytesOutOfBounds, jmpTarget(jumpShortsOutOfBounds, jmpTarget(jumpWordsOutOfBounds, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpNotString->operands))[0]))); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, 1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(1)); } genConvertIntegerToSmallIntegerInReg(Arg0Reg); jmpTarget(jumpBadArg, jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return CompletePrimitive; } /* CogObjectRepresentationFor32BitSpur>>#genRemoveSmallIntegerTagsInScratchReg: */ static sqInt NoDbgRegParms genRemoveSmallIntegerTagsInScratchReg(sqInt scratchReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 1, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* CogObjectRepresentationFor32BitSpur>>#genShiftAwaySmallIntegerTagsInScratchReg: */ static sqInt NoDbgRegParms genShiftAwaySmallIntegerTagsInScratchReg(sqInt scratchReg) { /* begin ArithmeticShiftRightCq:R: */ genoperandoperand(ArithmeticShiftRightCqR, 1, scratchReg); return 0; } /* Get the literal count of a CompiledMethod into headerReg, plus one if requested. If inBytes is true, scale the count by the word size. Deal with the possibility of the method being cogged. */ /* CogObjectRepresentationFor32BitSpur>>#getLiteralCountOf:plusOne:inBytes:into:scratch: */ static sqInt NoDbgRegParms getLiteralCountOfplusOneinBytesintoscratch(sqInt methodReg, sqInt plusOne, sqInt inBytes, sqInt litCountReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; genGetMethodHeaderOfintoscratch(methodReg, litCountReg, scratchReg); if (inBytes) { /* begin AndCq:R: */ quickConstant = ((sqInt)((usqInt)((alternateHeaderNumLiteralsMask())) << 1)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, litCountReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 1, litCountReg); } else { /* begin LogicalShiftRightCq:R: */ genoperandoperand(LogicalShiftRightCqR, 1, litCountReg); /* begin AndCq:R: */ quickConstant1 = alternateHeaderNumLiteralsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant1, litCountReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } } if (plusOne) { /* begin AddCq:R: */ quickConstant2 = (inBytes ? BytesPerWord : 1); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant2, litCountReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } } return 0; } /* Answer the relevant inline cache tag for an instance. c.f. getInlineCacheClassTagFrom:into: & inlineCacheTagForClass: */ /* CogObjectRepresentationFor32BitSpur>>#inlineCacheTagForInstance: */ static sqInt NoDbgRegParms inlineCacheTagForInstance(sqInt oop) { return (isImmediate(oop) ? oop & 1 : classIndexOf(oop)); } /* CogObjectRepresentationFor32BitSpur>>#jumpNotSmallIntegerUnsignedValueInRegister: */ static AbstractInstruction * NoDbgRegParms jumpNotSmallIntegerUnsignedValueInRegister(sqInt reg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0x3FFFFFFF, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0x3FFFFFFF)); } /* begin JumpAbove: */ return genConditionalBranchoperand(JumpAbove, ((sqInt)0)); } /* Mark and trace a literal in an inline cache preceding address in cogMethodOrNil. Answer if code was modified. */ /* CogObjectRepresentationFor32BitSpur>>#markAndTraceCacheTagLiteral:in:atpc: */ static sqInt NoDbgRegParms markAndTraceCacheTagLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address) { sqInt objOop; AbstractInstruction * self_in_rewriteInlineCacheTagat; if (!(couldBeObject(literal))) { return 0; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return 0; } objOop = followForwarded(literal); /* begin rewriteInlineCacheTag:at: */ self_in_rewriteInlineCacheTagat = ((AbstractInstruction *) (backEnd())); longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheTagat, address - 8), objOop); markAndTraceUpdatedLiteralin(objOop, cogMethodOrNil); return 1; } /* CogObjectRepresentationFor32BitSpur>>#numSmallIntegerBits */ static sqInt numSmallIntegerBits(void) { return 0x1F; } /* The two valid tag patterns are 0 (Character) and 1 (SmallInteger) */ /* CogObjectRepresentationFor32BitSpur>>#validInlineCacheTag: */ static sqInt NoDbgRegParms validInlineCacheTag(usqInt classIndexOrTagPattern) { return (classIndexOrTagPattern <= 1) || ((classAtIndex(classIndexOrTagPattern)) != null); } /* Answer if the cacheTag is not unmarked, i.e. answer true for compact class indices and immediates; only answer false for unmarked objects. In Spur linked send cache tags are class indices so effectively they're always marked. */ /* CogObjectRepresentationForSpur>>#cacheTagIsMarked: */ static sqInt NoDbgRegParms cacheTagIsMarked(sqInt cacheTag) { return 1; } /* CogObjectRepresentationForSpur>>#callStoreCheckTrampoline */ static void callStoreCheckTrampoline(void) { AbstractInstruction *abstractInstruction; /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* CogObjectRepresentationForSpur>>#checkValidDerivedObjectReference: */ static sqInt NoDbgRegParms checkValidDerivedObjectReference(sqInt bodyAddress) { return (heapMapAtWord(pointerForOop(bodyAddress - BaseHeaderSize))) != 0; } /* CogObjectRepresentationForSpur>>#checkValidOopReference: */ static sqInt NoDbgRegParms checkValidOopReference(sqInt anOop) { return (isImmediate(anOop)) || ((heapMapAtWord(pointerForOop(anOop))) != 0); } /* CogObjectRepresentationForSpur>>#couldBeDerivedObject: */ static sqInt NoDbgRegParms couldBeDerivedObject(sqInt bodyAddress) { return oopisGreaterThanOrEqualTo(bodyAddress - BaseHeaderSize, startOfMemory()); } /* CogObjectRepresentationForSpur>>#couldBeObject: */ static sqInt NoDbgRegParms couldBeObject(sqInt literal) { return (isNonImmediate(literal)) && (oopisGreaterThanOrEqualTo(literal, startOfMemory())); } /* Create a trampoline to answer the active context that will answer it if a frame is already married, and create it otherwise. Assume numArgs is in SendNumArgsReg and ClassReg is free. */ /* CogObjectRepresentationForSpur>>#genActiveContextTrampolineLarge:inBlock:called: */ static sqInt NoDbgRegParms genActiveContextTrampolineLargeinBlockcalled(sqInt isLarge, sqInt isInBlock, char *aString) { sqInt startAddress; startAddress = methodZoneBase(); zeroOpcodeIndex(); genGetActiveContextLargeinBlock(isLarge, isInBlock); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress(aString, startAddress); recordRunTimeObjectReferences(); return startAddress; } /* CogObjectRepresentationForSpur>>#genAllocFloatValue:into:scratchReg:scratchReg: */ static AbstractInstruction * NoDbgRegParms genAllocFloatValueintoscratchRegscratchReg(sqInt dpreg, sqInt resultReg, sqInt scratch1, sqInt scratch2) { sqInt address; sqInt address1; usqIntptr_t allocSize; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *jumpFail; usqLong newFloatHeader; sqInt quickConstant; sqInt quickConstant1; allocSize = BaseHeaderSize + (sizeof(double)); newFloatHeader = headerForSlotsformatclassIndex((sizeof(double)) / BytesPerWord, firstLongFormat(), ClassFloatCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, resultReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(LoadEffectiveAddressMwrR, allocSize, resultReg, scratch1); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(allocSize)); } /* begin CmpCq:R: */ quickConstant = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, scratch1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpFail = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, scratch1, address1)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant1 = ((usqInt) newFloatHeader); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant1, scratch1); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveRMwr, scratch1, 0, resultReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, newFloatHeader >> 32, scratch1); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(newFloatHeader >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, scratch1, 4, resultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveRdM64r, dpreg, BaseHeaderSize, resultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize)); } return jumpFail; } /* Check the remembered bit of the object in objReg; answer the jump taken if the bit is already set. Only need to fetch the byte containing it, which reduces the size of the mask constant. */ /* CogObjectRepresentationForSpur>>#genCheckRememberedBitOf:scratch: */ static AbstractInstruction * NoDbgRegParms genCheckRememberedBitOfscratch(sqInt objReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; int mask; sqInt rememberedBitByteOffset; rememberedBitByteOffset = (rememberedBitShift()) / 8; mask = 1U << ((rememberedBitShift()) % 8); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, rememberedBitByteOffset, objReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(rememberedBitByteOffset)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, mask, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(mask)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* CogObjectRepresentationForSpur>>#genConvertCharacterToCodeInReg: */ static sqInt NoDbgRegParms genConvertCharacterToCodeInReg(sqInt reg) { sqInt quickConstant; /* begin LogicalShiftRightCq:R: */ quickConstant = numTagBits(); genoperandoperand(LogicalShiftRightCqR, quickConstant, reg); return 0; } /* CogObjectRepresentationForSpur>>#genConvertIntegerToCharacterInReg: */ static sqInt NoDbgRegParms genConvertIntegerToCharacterInReg(sqInt reg) { AbstractInstruction *anInstruction; sqInt quickConstant; sqInt quickConstant1; /* begin LogicalShiftLeftCq:R: */ quickConstant = numTagBits(); genoperandoperand(LogicalShiftLeftCqR, quickConstant, reg); /* begin AddCq:R: */ quickConstant1 = characterTag(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, quickConstant1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant1)); } return 0; } /* Create a closure with the given startpc, numArgs and numCopied within a context with ctxtNumArgs, large if isLargeCtxt that is in a block if isInBlock. If numCopied > 0 pop those values off the stack. */ /* CogObjectRepresentationForSpur>>#genCreateClosureAt:numArgs:numCopied:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock) { AbstractInstruction *anInstruction; sqInt i; genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(bcpc, numArgs, numCopied, ctxtNumArgs, isLargeCtxt, isInBlock); for (i = 1; i <= numCopied; i += 1) { /* begin PopR: */ genoperand(PopR, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, TempReg, (((numCopied - i) + ClosureFirstCopiedValueIndex) * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((((numCopied - i) + ClosureFirstCopiedValueIndex) * BytesPerOop) + BaseHeaderSize)); } } return 0; } /* Create a full closure with the given values. */ /* CogObjectRepresentationForSpur>>#genCreateFullClosure:numArgs:numCopied:ignoreContext:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(sqInt compiledBlock, sqInt numArgs, sqInt numCopied, sqInt ignoreContext, sqInt contextNumArgs, sqInt contextIsLarge, sqInt contextIsBlock) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; usqInt byteSize; sqInt constant; usqLong header; sqInt literal; sqInt numSlots; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; /* First get thisContext into ReceiverResultReg and thence in ClassReg. */ if (ignoreContext) { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ClassReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(MoveCqR, constant, ClassReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(constant)); } } } else { genGetActiveContextNumArgslargeinBlock(contextNumArgs, contextIsLarge, contextIsBlock); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); } numSlots = FullClosureFirstCopiedValueIndex + numCopied; byteSize = smallObjectBytesForSlots(numSlots); assert(ClassFullBlockClosureCompactIndex != 0); header = headerForSlotsformatclassIndex(numSlots, indexablePointersFormat(), ClassFullBlockClosureCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(LoadEffectiveAddressMwrR, byteSize, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(byteSize)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveRMwr, ClassReg, (ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral((ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize)); } if (shouldAnnotateObjectReference(compiledBlock)) { annotateobjRef(gMoveCwR(compiledBlock, TempReg), compiledBlock); } else { /* begin MoveCq:R: */ anInstruction = genoperandoperand(MoveCqR, compiledBlock, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(compiledBlock)); } } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)numArgs << 1) | 1); anInstruction9 = genoperandoperand(MoveCqR, (((usqInt)numArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(literal)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral((ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize)); } return 0; } /* Make sure that the object in reg is not forwarded. This routine assumes the object will never be forwarded to an immediate, as it is used to unforward literal variables (associations). Use the fact that isForwardedObjectClassIndexPun is a power of two to save an instruction. */ /* CogObjectRepresentationForSpur>>#genEnsureObjInRegNotForwarded:scratchReg: */ static sqInt NoDbgRegParms genEnsureObjInRegNotForwardedscratchReg(sqInt reg, sqInt scratch) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *loop; AbstractInstruction *ok; sqInt quickConstant; assert(reg != scratch); /* begin Label */ loop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(ok, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchReg(sqInt reg, sqInt scratch) { AbstractInstruction *instruction; /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ instruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); return genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(reg, scratch, instruction, 0); } /* Make sure that the oop in reg is not forwarded. Use the fact that isForwardedObjectClassIndexPun is a power of two to save an instruction. */ /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg:ifForwarder:ifNotForwarder: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(sqInt reg, sqInt scratch, sqInt fwdJumpTarget, sqInt nonFwdJumpTargetOrZero) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction * finished; AbstractInstruction * imm; AbstractInstruction * ok; sqInt quickConstant; assert(reg != scratch); /* notionally self genGetClassIndexOfNonImm: reg into: scratch. cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: TempReg. but the following is an instruction shorter: */ imm = genJumpImmediate(reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin Jump: */ genoperand(Jump, ((sqInt)(((void *) fwdJumpTarget)))); if ((((usqInt)nonFwdJumpTargetOrZero)) == 0) { /* begin Label */ finished = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { finished = nonFwdJumpTargetOrZero; } jmpTarget(imm, jmpTarget(ok, finished)); return 0; } /* Make sure that the oop in reg is not forwarded, updating the slot in objReg with the value. */ /* CogObjectRepresentationForSpur>>#genEnsureOopInRegNotForwarded:scratchReg:updatingSlot:in: */ static sqInt NoDbgRegParms genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(sqInt reg, sqInt scratch, sqInt index, sqInt objReg) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *imm; AbstractInstruction *loop; AbstractInstruction *ok; sqInt quickConstant; /* Open-code self genEnsureOopInRegNotForwarded: reg scratchReg: scratch updatingMw: index * objectMemory wordSize + objectMemory baseHeaderSize r: objReg. to avoid calling the store check unless the receiver is forwarded. */ assert((reg != scratch) && (objReg != scratch)); /* begin Label */ loop = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* notionally self genGetClassIndexOfNonImm: reg into: scratch. cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: TempReg. but the following is an instruction shorter: */ imm = genJumpImmediate(reg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, reg, scratch); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = (classIndexMask()) - (isForwardedObjectClassIndexPun()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, scratch); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ ok = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, reg, reg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveRMwr, reg, (index * BytesPerWord) + BaseHeaderSize, objReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } assert((reg == Arg0Reg) && ((scratch == TempReg) && (objReg == ReceiverResultReg))); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckContextReceiverTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(ok, jmpTarget(imm, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Do the store check. Answer the argument for the benefit of the code generator; ReceiverResultReg may be caller-saved and hence smashed by this call. Answering it allows the code generator to reload ReceiverResultReg cheaply. In Spur the only thing we leave to the run-time is adding the receiver to the remembered set and setting its isRemembered bit. */ /* CogObjectRepresentationForSpur>>#generateObjectRepresentationTrampolines */ static void generateObjectRepresentationTrampolines(void) { sqInt instVarIndex; AbstractInstruction *jumpSC; # if IMMUTABILITY for (instVarIndex = 0; instVarIndex < NumStoreTrampolines; instVarIndex += 1) { ceStoreTrampolines[instVarIndex] = (genStoreTrampolineCalledinstVarIndex(trampolineNamenumArgslimit("ceStoreTrampoline", instVarIndex, NumStoreTrampolines - 2), instVarIndex)); } # endif /* IMMUTABILITY */ ceNewHashTrampoline = genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceNewHashOf, "ceNewHash", 1, ReceiverResultReg, null, null, null, /* begin emptyRegisterMask */ 0, 1, ReceiverResultReg, 0); /* begin genStoreCheckTrampoline */ if (CheckRememberedInTrampoline) { zeroOpcodeIndex(); jumpSC = genCheckRememberedBitOfscratch(ReceiverResultReg, R0); assert(((jumpSC->opcode)) == JumpNonZero); (jumpSC->opcode = JumpZero); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpSC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } ceStoreCheckTrampoline = genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(remember, "ceStoreCheckTrampoline", 1, ReceiverResultReg, null, null, null, ((CallerSavedRegisterMask | (1U << ReceiverResultReg)) - (1U << ReceiverResultReg)), 1, (CallerSavedRegisterMask & (1U << ReceiverResultReg) ? ReceiverResultReg : /* begin cResultRegister */ R0), CheckRememberedInTrampoline); ceStoreCheckContextReceiverTrampoline = genStoreCheckContextReceiverTrampoline(); ceScheduleScavengeTrampoline = genTrampolineForcalledregsToSave(ceScheduleScavenge, "ceScheduleScavengeTrampoline", CallerSavedRegisterMask); ceSmallActiveContextInMethodTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, 0, "ceSmallMethodContext"); ceSmallActiveContextInBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, InVanillaBlock, "ceSmallBlockContext"); ceSmallActiveContextInFullBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(0, InFullBlock, "ceSmallFullBlockContext"); ceLargeActiveContextInMethodTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, 0, "ceLargeMethodContext"); ceLargeActiveContextInBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, InVanillaBlock, "ceLargeBlockContext"); ceLargeActiveContextInFullBlockTrampoline = genActiveContextTrampolineLargeinBlockcalled(1, InFullBlock, "ceLargeFullBlockContext"); } /* Create a trampoline to answer the active context that will answer it if a frame is already married, and create it otherwise. Assume numArgs is in SendNumArgsReg and ClassReg is free. */ /* CogObjectRepresentationForSpur>>#genGetActiveContextLarge:inBlock: */ static sqInt NoDbgRegParms genGetActiveContextLargeinBlock(sqInt isLarge, sqInt isInBlock) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction22; AbstractInstruction *anInstruction23; AbstractInstruction *anInstruction24; AbstractInstruction *anInstruction25; AbstractInstruction *anInstruction26; AbstractInstruction *anInstruction27; AbstractInstruction *anInstruction28; AbstractInstruction *anInstruction29; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction30; AbstractInstruction *anInstruction31; AbstractInstruction *anInstruction32; AbstractInstruction *anInstruction33; AbstractInstruction *anInstruction34; AbstractInstruction *anInstruction35; AbstractInstruction *anInstruction36; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt constant; AbstractInstruction *continuation; AbstractInstruction *exit; usqLong header; AbstractInstruction * inst; AbstractInstruction *jumpNeedScavenge; AbstractInstruction *jumpSingle; AbstractInstruction *loopHead; sqInt offset; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt slotSize; /* load the flag; stash it in both TempReg & ClassReg; do the compare (a prime candidated for use of AndCq:R:R:) */ /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveMwrR, FoxMethod, FPReg, ClassReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(FoxMethod)); } gAndCqRR(MFMethodFlagHasContextFlag, ClassReg, TempReg); /* begin JumpZero: */ jumpSingle = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveMwrR, FoxThisContext, FPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(FoxThisContext)); } /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpSingle, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(OrCqR, MFMethodFlagHasContextFlag, ClassReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(MFMethodFlagHasContextFlag)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, ClassReg, FoxMethod, FPReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(FoxMethod)); } switch (isInBlock) { case InFullBlock: /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, 3, ClassReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } break; case InVanillaBlock: /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, 3, ClassReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(3)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveM16rR, 0, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, ClassReg); break; case 0: /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, 1, ClassReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(1)); } break; default: error("Case not found and no otherwise clause"); } slotSize = (isLarge ? LargeContextSlots : SmallContextSlots); header = headerForSlotsformatclassIndex(slotSize, indexablePointersFormat(), ClassMethodContextCompactIndex); flag("endianness"); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant2 = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(MoveCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(quickConstant2)); } /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction31 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction31)) { (anInstruction31->dependent = locateLiteral(4)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg); /* begin AddCq:R: */ quickConstant3 = smallObjectBytesForSlots(slotSize); /* begin checkQuickConstant:forInstruction: */ anInstruction13 = genoperandoperand(AddCqR, quickConstant3, TempReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(quickConstant3)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant4 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(quickConstant4)); } /* begin JumpAboveOrEqual: */ jumpNeedScavenge = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin MoveR:R: */ continuation = genoperandoperand(MoveRR, FPReg, TempReg); genSetSmallIntegerTagsIn(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (SenderIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(BaseHeaderSize + (SenderIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, FoxSavedFP, FPReg, TempReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(FoxSavedFP)); } genSetSmallIntegerTagsIn(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (InstructionPointerIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(BaseHeaderSize + (InstructionPointerIndex * BytesPerOop))); } /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodObject); /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(offset)); } /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (MethodIndex * BytesPerWord), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(BaseHeaderSize + (MethodIndex * BytesPerWord))); } /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperandoperand(MoveRMwr, ReceiverResultReg, FoxThisContext, FPReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(FoxThisContext)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, SPReg, TempReg); /* begin LogicalShiftRightCq:R: */ quickConstant = 2 /* log2BytesPerWord */; genoperandoperand(LogicalShiftRightCqR, quickConstant, TempReg); /* begin SubCq:R: */ quickConstant5 = 3; /* begin checkQuickConstant:forInstruction: */ anInstruction22 = genoperandoperand(SubCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction22)) { (anInstruction22->dependent = locateLiteral(quickConstant5)); } /* begin AddR:R: */ genoperandoperand(AddRR, SendNumArgsReg, TempReg); genConvertIntegerToSmallIntegerInReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction23 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (StackPointerIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction23)) { (anInstruction23->dependent = locateLiteral(BaseHeaderSize + (StackPointerIndex * BytesPerOop))); } if (isInBlock > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, 2, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(2)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, TempReg, FPReg, TempReg); } else { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction36 = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction36)) { (anInstruction36->dependent = locateLiteral(constant)); } } } /* begin checkQuickConstant:forInstruction: */ anInstruction24 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (ClosureIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction24)) { (anInstruction24->dependent = locateLiteral(BaseHeaderSize + (ClosureIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction25 = genoperandoperandoperand(MoveMwrR, FoxMFReceiver, FPReg, TempReg); if (usesOutOfLineLiteral(anInstruction25)) { (anInstruction25->dependent = locateLiteral(FoxMFReceiver)); } /* begin checkQuickConstant:forInstruction: */ anInstruction26 = genoperandoperandoperand(MoveRMwr, TempReg, BaseHeaderSize + (ReceiverIndex * BytesPerOop), ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction26)) { (anInstruction26->dependent = locateLiteral(BaseHeaderSize + (ReceiverIndex * BytesPerOop))); } /* begin checkQuickConstant:forInstruction: */ anInstruction27 = genoperandoperand(MoveCqR, 1, ClassReg); if (usesOutOfLineLiteral(anInstruction27)) { (anInstruction27->dependent = locateLiteral(1)); } /* begin CmpR:R: */ loopHead = genoperandoperand(CmpRR, SendNumArgsReg, ClassReg); /* begin JumpGreater: */ exit = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, ClassReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction28 = genoperandoperand(AddCqR, 2, TempReg); if (usesOutOfLineLiteral(anInstruction28)) { (anInstruction28->dependent = locateLiteral(2)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, TempReg, FPReg, TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction29 = genoperandoperand(AddCqR, ReceiverIndex + (BaseHeaderSize / BytesPerWord), ClassReg); if (usesOutOfLineLiteral(anInstruction29)) { (anInstruction29->dependent = locateLiteral(ReceiverIndex + (BaseHeaderSize / BytesPerWord))); } /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, ClassReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction30 = genoperandoperand(SubCqR, (ReceiverIndex + (BaseHeaderSize / BytesPerWord)) - 1, ClassReg); if (usesOutOfLineLiteral(anInstruction30)) { (anInstruction30->dependent = locateLiteral((ReceiverIndex + (BaseHeaderSize / BytesPerWord)) - 1)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loopHead)); jmpTarget(exit, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin MoveCq:R: */ quickConstant1 = nilObject(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(MoveCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant1)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction32 = genoperandoperand(AddCqR, FoxMFReceiver, ClassReg); if (usesOutOfLineLiteral(anInstruction32)) { (anInstruction32->dependent = locateLiteral(FoxMFReceiver)); } /* begin checkQuickConstant:forInstruction: */ anInstruction33 = genoperandoperand(AddCqR, (ReceiverIndex + 1) + (BaseHeaderSize / BytesPerWord), SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction33)) { (anInstruction33->dependent = locateLiteral((ReceiverIndex + 1) + (BaseHeaderSize / BytesPerWord))); } /* begin checkQuickConstant:forInstruction: */ anInstruction34 = genoperandoperand(SubCqR, BytesPerWord, ClassReg); if (usesOutOfLineLiteral(anInstruction34)) { (anInstruction34->dependent = locateLiteral(BytesPerWord)); } loopHead = anInstruction34; /* begin CmpR:R: */ genoperandoperand(CmpRR, SPReg, ClassReg); /* begin JumpBelow: */ exit = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, SendNumArgsReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction35 = genoperandoperand(AddCqR, 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction35)) { (anInstruction35->dependent = locateLiteral(1)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loopHead)); jmpTarget(exit, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpNeedScavenge, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); CallRTregistersToBeSavedMask(ceScheduleScavengeTrampoline, ((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)); genoperand(PopR, LinkReg); /* begin Jump: */ genoperand(Jump, ((sqInt)continuation)); return 0; } /* Get the active context into ReceiverResultReg, creating it if necessary. */ /* CogObjectRepresentationForSpur>>#genGetActiveContextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genGetActiveContextNumArgslargeinBlock(sqInt numArgs, sqInt isLargeContext, sqInt isInBlock) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; sqInt routine; if (isLargeContext) { switch (isInBlock) { case 0: routine = ceLargeActiveContextInMethodTrampoline; break; case InVanillaBlock: routine = ceLargeActiveContextInBlockTrampoline; break; case InFullBlock: routine = ceLargeActiveContextInFullBlockTrampoline; break; default: error("Case not found and no otherwise clause"); routine = -1; } } else { switch (isInBlock) { case 0: routine = ceSmallActiveContextInMethodTrampoline; break; case InVanillaBlock: routine = ceSmallActiveContextInBlockTrampoline; break; case InFullBlock: routine = ceSmallActiveContextInFullBlockTrampoline; break; default: error("Case not found and no otherwise clause"); routine = -1; } } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, numArgs, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(numArgs)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, routine); (abstractInstruction->annotation = IsRelativeCall); return 0; } /* CogObjectRepresentationForSpur>>#genGetBits:ofFormatByteOf:into: */ static sqInt NoDbgRegParms genGetBitsofFormatByteOfinto(sqInt mask, sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, 3, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, mask, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(mask)); } return 0; } /* Fetch the instance's class index into destReg. */ /* CogObjectRepresentationForSpur>>#genGetClassIndexOfNonImm:into: */ static sqInt NoDbgRegParms genGetClassIndexOfNonImminto(sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } return 0; } /* Fetch the class object whose index is in instReg into destReg. It is non-obvious, but the Cogit assumes loading a class does not involve a runtime call, so do not call classAtIndex: */ /* CogObjectRepresentationForSpur>>#genGetClassObjectOfClassIndex:into:scratchReg: */ static sqInt NoDbgRegParms genGetClassObjectOfClassIndexintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; sqInt offset; sqInt quickConstant; sqInt quickConstant2; sqInt quickConstant3; assert(instReg != destReg); assert(instReg != scratchReg); assert(destReg != scratchReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, scratchReg); /* begin LogicalShiftRightCq:R: */ quickConstant = classTableMajorIndexShift(); genoperandoperand(LogicalShiftRightCqR, quickConstant, scratchReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), scratchReg); assert(!(shouldAnnotateObjectReference(classTableRootObj()))); /* begin MoveMw:r:R: */ offset = (classTableRootObj()) + BaseHeaderSize; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, scratchReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, scratchReg); /* begin AndCq:R: */ quickConstant2 = classTableMinorIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AndCqR, quickConstant2, scratchReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant2)); } /* begin AddCq:R: */ quickConstant3 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, quickConstant3, scratchReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant3)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, scratchReg, destReg, destReg); return 0; } /* Fetch the instance's class into destReg. If the instance is not the receiver and is forwarded, follow forwarding. */ /* CogObjectRepresentationForSpur>>#genGetClassObjectOf:into:scratchReg:instRegIsReceiver: */ static sqInt NoDbgRegParms genGetClassObjectOfintoscratchReginstRegIsReceiver(sqInt instReg, sqInt destReg, sqInt scratchReg, sqInt instRegIsReceiver) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpIsImm; AbstractInstruction *jumpNotForwarded; AbstractInstruction *loop; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; if ((instReg == destReg) || ((instReg == scratchReg) || (destReg == scratchReg))) { return BadRegisterSet; } /* begin MoveR:R: */ loop = genoperandoperand(MoveRR, instReg, scratchReg); /* begin AndCq:R: */ quickConstant1 = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant1, scratchReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ jumpIsImm = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, 0, instReg, scratchReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(0)); } /* begin AndCq:R: */ quickConstant2 = classIndexMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AndCqR, quickConstant2, scratchReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant2)); } if (!instRegIsReceiver) { /* if it is forwarded... */ /* begin CmpCq:R: */ quickConstant = isForwardedObjectClassIndexPun(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ jumpNotForwarded = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, BaseHeaderSize, instReg, instReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(BaseHeaderSize)); } /* begin Jump: */ genoperand(Jump, ((sqInt)loop)); jmpTarget(jumpNotForwarded, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } jmpTarget(jumpIsImm, genoperandoperand(MoveRR, scratchReg, destReg)); if (scratchReg == TempReg) { /* begin PushR: */ genoperand(PushR, instReg); genGetClassObjectOfClassIndexintoscratchReg(destReg, instReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, instReg, destReg); /* begin PopR: */ genoperand(PopR, instReg); } else { genGetClassObjectOfClassIndexintoscratchReg(destReg, scratchReg, TempReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, scratchReg, destReg); } return 0; } /* CogObjectRepresentationForSpur>>#genGetClassTagOf:into:scratchReg: */ static AbstractInstruction * NoDbgRegParms genGetClassTagOfintoscratchReg(sqInt instReg, sqInt destReg, sqInt scratchReg) { return genGetInlineCacheClassTagFromintoforEntry(instReg, destReg, 1); } /* Fetch the instance's class index into destReg. */ /* CogObjectRepresentationForSpur>>#genGetCompactClassIndexNonImmOf:into: */ static sqInt NoDbgRegParms genGetCompactClassIndexNonImmOfinto(sqInt instReg, sqInt destReg) { return genGetClassIndexOfNonImminto(instReg, destReg); } /* CogObjectRepresentationForSpur>>#genGetDoubleValueOf:into: */ static sqInt NoDbgRegParms genGetDoubleValueOfinto(sqInt srcReg, sqInt destFPReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveM64rRd, BaseHeaderSize, srcReg, destFPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BaseHeaderSize)); } return 0; } /* Get the format field of the object in srcReg into destReg. srcReg may equal destReg. */ /* CogObjectRepresentationForSpur>>#genGetFormatOf:into: */ static sqInt NoDbgRegParms genGetFormatOfinto(sqInt srcReg, sqInt destReg) { return genGetBitsofFormatByteOfinto(formatMask(), srcReg, destReg); } /* Get the format of the object in sourceReg into destReg. If scratchRegOrNone is not NoReg, load at least the least significant 32-bits (64-bits in 64-bits) of the header word, which contains the format, into scratchRegOrNone. */ /* CogObjectRepresentationForSpur>>#genGetFormatOf:into:leastSignificantHalfOfBaseHeaderIntoScratch: */ static sqInt NoDbgRegParms genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(sqInt sourceReg, sqInt destReg, sqInt scratchRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt quickConstant; sqInt quickConstant1; if (scratchRegOrNone == NoReg) { flag("endianness"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMbrR, 3, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(3)); } } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, 0, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin MoveR:R: */ genoperandoperand(MoveRR, destReg, scratchRegOrNone); /* begin LogicalShiftRightCq:R: */ quickConstant = formatShift(); genoperandoperand(LogicalShiftRightCqR, quickConstant, destReg); } /* begin AndCq:R: */ quickConstant1 = formatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AndCqR, quickConstant1, destReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } return 0; } /* Get the size in word-sized slots of the object in srcReg into destReg. srcReg may equal destReg. */ /* CogObjectRepresentationForSpur>>#genGetNumSlotsOf:into: */ static sqInt NoDbgRegParms genGetNumSlotsOfinto(sqInt srcReg, sqInt destReg) { AbstractInstruction *anInstruction; AbstractInstruction *jmp; sqInt quickConstant; assert(srcReg != destReg); genGetRawSlotSizeOfNonImminto(srcReg, destReg); /* begin CmpCq:R: */ quickConstant = numSlotsMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jmp = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genGetOverflowSlotsOfinto(srcReg, destReg); jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* The raw numSlots field is the most significant byte of the 64-bit header word. MoveMbrR zero-extends. */ /* CogObjectRepresentationForSpur>>#genGetRawSlotSizeOfNonImm:into: */ static sqInt NoDbgRegParms genGetRawSlotSizeOfNonImminto(sqInt sourceReg, sqInt destReg) { AbstractInstruction *anInstruction1; /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMbrR, 7, sourceReg, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(7)); } return 0; } /* CogObjectRepresentationForSpur>>#genJumpImmediate: */ static AbstractInstruction * NoDbgRegParms genJumpImmediate(sqInt aRegister) { AbstractInstruction *anInstruction; sqInt quickConstant; /* begin TstCq:R: */ quickConstant = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(TstCqR, quickConstant, aRegister); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* CogObjectRepresentationForSpur>>#genJumpImmutable:scratchReg: */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpImmutablescratchReg(sqInt sourceReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin genJumpBaseHeaderImmutable: */ quickConstant = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } #endif /* IMMUTABILITY */ /* CogObjectRepresentationForSpur>>#genJumpMutable:scratchReg: */ #if IMMUTABILITY static AbstractInstruction * NoDbgRegParms genJumpMutablescratchReg(sqInt sourceReg, sqInt scratchReg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, sourceReg, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin genJumpBaseHeaderMutable: */ quickConstant = immutableBitMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(TstCqR, quickConstant, scratchReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpZero: */ return genConditionalBranchoperand(JumpZero, ((sqInt)0)); } #endif /* IMMUTABILITY */ /* CogObjectRepresentationForSpur>>#genJumpNotCharacterInScratchReg: */ static AbstractInstruction * NoDbgRegParms genJumpNotCharacterInScratchReg(sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt quickConstant; sqInt quickConstant1; /* begin AndCq:R: */ quickConstant = tagMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AndCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin CmpCq:R: */ quickConstant1 = characterTag(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ return genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* Generate a call to code that allocates a new Array of size. The Array should be initialized with nils iff initialized is true. The size arg is passed in SendNumArgsReg, the result must come back in ReceiverResultReg. */ /* CogObjectRepresentationForSpur>>#genNewArrayOfSize:initialized: */ static sqInt NoDbgRegParms genNewArrayOfSizeinitialized(sqInt size, sqInt initialized) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; sqInt constant; usqLong header; sqInt i; sqInt offset; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; assert(size < (numSlotsMask())); header = headerForSlotsformatclassIndex(size, arrayFormat(), ClassArrayCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } if (initialized && (size > 0)) { /* begin genMoveConstant:R: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(constant)); } } for (i = 0; i < size; i += 1) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, TempReg, (i * BytesPerWord) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((i * BytesPerWord) + BaseHeaderSize)); } } } /* begin LoadEffectiveAddressMw:r:R: */ offset = smallObjectBytesForSlots(size); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(LoadEffectiveAddressMwrR, offset, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(offset)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Create a closure with the given startpc, numArgs and numCopied within a context with ctxtNumArgs, large if isLargeCtxt that is in a block if isInBlock. Do /not/ initialize the copied values. */ /* CogObjectRepresentationForSpur>>#genNoPopCreateClosureAt:numArgs:numCopied:contextNumArgs:large:inBlock: */ static sqInt NoDbgRegParms genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(sqInt bcpc, sqInt numArgs, sqInt numCopied, sqInt ctxtNumArgs, sqInt isLargeCtxt, sqInt isInBlock) { AbstractInstruction *abstractInstruction; sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; usqInt byteSize; usqLong header; sqInt literal; sqInt literal1; sqInt numSlots; sqInt quickConstant; sqInt quickConstant1; AbstractInstruction *skip; /* First get thisContext into ReceiverResultRega and thence in ClassReg. */ genGetActiveContextNumArgslargeinBlock(ctxtNumArgs, isLargeCtxt, isInBlock); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); numSlots = ClosureFirstCopiedValueIndex + numCopied; byteSize = smallObjectBytesForSlots(numSlots); header = headerForSlotsformatclassIndex(numSlots, indexablePointersFormat(), ClassBlockClosureCompactIndex); /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ReceiverResultReg)); /* begin genStoreHeader:intoNewInstance:using: */ quickConstant = ((usqInt) header); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, TempReg, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, header >> 32, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(header >> 32)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveRMwr, TempReg, 4, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(4)); } /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperandoperand(LoadEffectiveAddressMwrR, byteSize, ReceiverResultReg, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(byteSize)); } /* begin MoveR:Aw: */ address1 = freeStartAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); /* begin CmpCq:R: */ quickConstant1 = getScavengeThreshold(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant1)); } /* begin JumpBelow: */ skip = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceScheduleScavengeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(skip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperandoperand(MoveRMwr, ClassReg, (ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral((ClosureOuterContextIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)bcpc << 1) | 1); anInstruction7 = genoperandoperand(MoveCqR, (((usqInt)bcpc << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(literal)); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral((ClosureStartPCIndex * BytesPerOop) + BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ literal1 = (((usqInt)numArgs << 1) | 1); anInstruction9 = genoperandoperand(MoveCqR, (((usqInt)numArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(literal1)); } /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveRMwr, TempReg, (ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral((ClosureNumArgsIndex * BytesPerOop) + BaseHeaderSize)); } return 0; } /* CogObjectRepresentationForSpur>>#genPrimitiveAsCharacter */ static sqInt genPrimitiveAsCharacter(void) { AbstractInstruction *jumpNotInt; AbstractInstruction *jumpOutOfRange; sqInt reg; jumpNotInt = ((AbstractInstruction *) 0); if (methodOrBlockNumArgs == 0) { reg = ReceiverResultReg; } else { if (methodOrBlockNumArgs > 1) { return UnimplementedPrimitive; } reg = Arg0Reg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotInt = genJumpNotSmallInteger(reg); } /* begin MoveR:R: */ genoperandoperand(MoveRR, reg, TempReg); genConvertSmallIntegerToIntegerInReg(TempReg); jumpOutOfRange = jumpNotCharacterUnsignedValueInRegister(TempReg); genConvertSmallIntegerToCharacterInReg(reg); if (reg != ReceiverResultReg) { /* begin MoveR:R: */ genoperandoperand(MoveRR, reg, ReceiverResultReg); } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpOutOfRange, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (reg != ReceiverResultReg) { jmpTarget(jumpNotInt, ((AbstractInstruction *) (((jumpOutOfRange->operands))[0]))); } return CompletePrimitive; } /* Generate primitive 60, at: with unsigned access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveAt */ static sqInt genPrimitiveAt(void) { return genPrimitiveAtSigned(0); } /* CogObjectRepresentationForSpur>>#genPrimitiveIdenticalOrNotIf: */ static sqInt NoDbgRegParms genPrimitiveIdenticalOrNotIf(sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *comp; sqInt constant; sqInt constant1; AbstractInstruction *jumpCmp; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin CmpR:R: */ comp = genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); if (orNot) { /* begin JumpZero: */ jumpCmp = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(Arg0Reg, TempReg, comp, 0); } else { /* begin JumpNonZero: */ jumpCmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } /* begin genMoveConstant:R: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpCmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!orNot) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(Arg0Reg, TempReg, comp, 0); } /* begin genMoveConstant:R: */ constant1 = falseObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gMoveCwR(constant1, ReceiverResultReg), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, constant1, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } return UnfailingPrimitive; } /* Generate primitive 164, at: with signed access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveIntegerAt */ static sqInt genPrimitiveIntegerAt(void) { return genPrimitiveAtSigned(1); } /* Generate primitive 165, at:put: with signed access for pure bits classes. */ /* CogObjectRepresentationForSpur>>#genPrimitiveIntegerAtPut */ static sqInt genPrimitiveIntegerAtPut(void) { return genPrimitiveAtPutSigned(1); } /* CogObjectRepresentationForSpur>>#genPrimitiveObjectAt */ static sqInt genPrimitiveObjectAt(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt headerReg; AbstractInstruction *jumpBadIndex; AbstractInstruction *jumpBounds; AbstractInstruction *jumpNotHeaderIndex; sqInt literal; sqInt quickConstant; sqInt quickConstant1; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); /* begin genJumpNotSmallInteger:scratchReg: */ jumpBadIndex = genJumpNotSmallInteger(Arg0Reg); genGetMethodHeaderOfintoscratch(ReceiverResultReg, (headerReg = Arg1Reg), TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)1 << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)1 << 1) | 1), Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpNotHeaderIndex = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, headerReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpNotHeaderIndex, gAndCqR((((usqInt)(alternateHeaderNumLiteralsMask()) << 1) | 1), headerReg)); /* begin SubCq:R: */ quickConstant = ((((usqInt)1 << 1) | 1)) - (smallIntegerTag()); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, quickConstant, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, headerReg, Arg0Reg); /* begin JumpAbove: */ jumpBounds = genConditionalBranchoperand(JumpAbove, ((sqInt)0)); genConvertSmallIntegerToIntegerInReg(Arg0Reg); /* begin AddCq:R: */ quickConstant1 = ((usqInt) BaseHeaderSize) >> (shiftForWord()); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant1, Arg0Reg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin MoveXwr:R:R: */ genoperandoperandoperand(MoveXwrRR, Arg0Reg, ReceiverResultReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpBounds, gAddCqR(((((usqInt)1 << 1) | 1)) - (smallIntegerTag()), Arg0Reg)); jmpTarget(jumpBadIndex, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* c.f. StackInterpreter>>stSizeOf: lengthOf:baseHeader:format: fixedFieldsOf:format:length: */ /* CogObjectRepresentationForSpur>>#genPrimitiveSize */ static sqInt genPrimitiveSize(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; AbstractInstruction * jump32BitLongsDone; AbstractInstruction * jump64BitLongsDone; AbstractInstruction * jumpArrayDone; AbstractInstruction * jumpBytesDone; AbstractInstruction * jumpHasFixedFields; AbstractInstruction *jumpImm; AbstractInstruction * jumpIs64BitLongs; AbstractInstruction * jumpIsBytes; AbstractInstruction *jumpIsContext; AbstractInstruction * jumpIsContext1; AbstractInstruction * jumpIsShorts; AbstractInstruction *jumpNotIndexable; AbstractInstruction * jumpNotIndexable1; AbstractInstruction * jumpShortsDone; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt quickConstant6; jumpImm = genJumpImmediate(ReceiverResultReg); /* begin genGetSizeOf:into:formatReg:scratchReg:abortJumpsInto: */ genGetFormatOfintoleastSignificantHalfOfBaseHeaderIntoScratch(ReceiverResultReg, SendNumArgsReg, TempReg); genGetNumSlotsOfinto(ReceiverResultReg, ClassReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpGreaterOrEqual: */ jumpIsBytes = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpZero: */ jumpArrayDone = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin JumpLess: */ jumpNotIndexable1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant2 = weakArrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpLessOrEqual: */ jumpHasFixedFields = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstShortFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant3, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant3)); } /* begin JumpGreaterOrEqual: */ jumpIsShorts = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstLongFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, quickConstant4, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(quickConstant4)); } /* begin JumpGreaterOrEqual: */ jump32BitLongsDone = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = sixtyFourBitIndexableFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(CmpCqR, quickConstant5, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(quickConstant5)); } /* begin JumpZero: */ jumpIs64BitLongs = genConditionalBranchoperand(JumpZero, ((sqInt)0)); jmpTarget(jumpNotIndexable1, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin Jump: */ jumpNotIndexable1 = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsBytes, gLogicalShiftLeftCqR(shiftForWord(), ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AndCqR, BytesPerWord - 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(BytesPerWord - 1)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); /* begin Jump: */ jumpBytesDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIsShorts, gLogicalShiftLeftCqR((shiftForWord()) - 1, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(AndCqR, 1, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(1)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); /* begin Jump: */ jumpShortsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpIs64BitLongs, genoperandoperand(LogicalShiftRightCqR, 1, ClassReg)); /* begin Jump: */ jump64BitLongsDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpHasFixedFields, gAndCqR(classIndexMask(), TempReg)); /* begin MoveR:R: */ genoperandoperand(MoveRR, TempReg, SendNumArgsReg); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, ClassMethodContextCompactIndex, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(ClassMethodContextCompactIndex)); } /* begin JumpZero: */ jumpIsContext1 = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin PushR: */ genoperand(PushR, ClassReg); genGetClassObjectOfClassIndexintoscratchReg(SendNumArgsReg, ClassReg, TempReg); genLoadSlotsourceRegdestReg(InstanceSpecificationIndex, ClassReg, SendNumArgsReg); genConvertSmallIntegerToIntegerInReg(SendNumArgsReg); /* begin PopR: */ genoperand(PopR, ClassReg); /* begin AndCq:R: */ quickConstant6 = fixedFieldsOfClassFormatMask(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(AndCqR, quickConstant6, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant6)); } /* begin SubR:R: */ genoperandoperand(SubRR, SendNumArgsReg, ClassReg); jmpTarget(jumpArrayDone, jmpTarget(jump64BitLongsDone, jmpTarget(jump32BitLongsDone, jmpTarget(jumpShortsDone, jmpTarget(jumpBytesDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); jumpNotIndexable = jumpNotIndexable1; jumpIsContext = jumpIsContext1; genConvertIntegerToSmallIntegerInReg(ClassReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpImm, jmpTarget(jumpNotIndexable, jmpTarget(jumpIsContext, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); return CompletePrimitive; } /* primitiveCompareWith: */ /* CogObjectRepresentationForSpur>>#genPrimitiveStringCompareWith */ static sqInt genPrimitiveStringCompareWith(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction * instr; AbstractInstruction *jump; AbstractInstruction *jumpAbove; AbstractInstruction *jumpIncorrectFormat1; AbstractInstruction *jumpIncorrectFormat2; AbstractInstruction *jumpIncorrectFormat3; AbstractInstruction *jumpIncorrectFormat4; AbstractInstruction *jumpMidFailure; AbstractInstruction *jumpSuccess; sqInt minSizeReg; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt string1CharOrByteSizeReg; sqInt string1Reg; sqInt string2CharOrByteSizeReg; sqInt string2Reg; /* I redefine those name to ease program comprehension */ string1Reg = ReceiverResultReg; string2Reg = Arg0Reg; string1CharOrByteSizeReg = Arg1Reg; string2CharOrByteSizeReg = ClassReg; /* Load arguments in reg */ minSizeReg = SendNumArgsReg; /* begin genLoadArgAtDepth:into: */ assert(0 < (numRegArgs())); genGetFormatOfinto(string1Reg, TempReg); /* begin CmpCq:R: */ quickConstant = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant1)); } /* begin JumpAboveOrEqual: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(string1Reg, string1CharOrByteSizeReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), string1CharOrByteSizeReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, string1CharOrByteSizeReg); genGetFormatOfinto(string2Reg, TempReg); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant2, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpIncorrectFormat3 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant3, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant3)); } /* begin JumpAboveOrEqual: */ jumpIncorrectFormat4 = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(string2Reg, string2CharOrByteSizeReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), string2CharOrByteSizeReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, string2CharOrByteSizeReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, string1CharOrByteSizeReg, string2CharOrByteSizeReg); /* begin JumpBelow: */ jumpAbove = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, string1CharOrByteSizeReg, minSizeReg); /* begin Jump: */ jump = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpAbove, genoperandoperand(MoveRR, string2CharOrByteSizeReg, minSizeReg)); jmpTarget(jump, checkQuickConstantforInstruction(0, genoperandoperand(CmpCqR, 0, minSizeReg))); /* begin JumpZero: */ jumpSuccess = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(MoveCqR, BaseHeaderSize, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(BaseHeaderSize)); } /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, BaseHeaderSize, minSizeReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(BaseHeaderSize)); } /* begin MoveXbr:R:R: */ instr = genoperandoperandoperand(MoveXbrRR, TempReg, string1Reg, string1CharOrByteSizeReg); /* begin MoveXbr:R:R: */ genoperandoperandoperand(MoveXbrRR, TempReg, string2Reg, string2CharOrByteSizeReg); /* begin SubR:R: */ genoperandoperand(SubRR, string2CharOrByteSizeReg, string1CharOrByteSizeReg); /* begin JumpNonZero: */ jumpMidFailure = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, 1, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, minSizeReg); /* begin JumpNonZero: */ genConditionalBranchoperand(JumpNonZero, ((sqInt)instr)); genGetNumBytesOfinto(string1Reg, string1CharOrByteSizeReg); genGetNumBytesOfinto(string2Reg, string2CharOrByteSizeReg); jmpTarget(jumpSuccess, genoperandoperand(SubRR, string2CharOrByteSizeReg, string1CharOrByteSizeReg)); jmpTarget(jumpMidFailure, genoperandoperand(MoveRR, string1CharOrByteSizeReg, ReceiverResultReg)); genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); if (methodOrBlockNumArgs <= 2 /* numRegArgs */) { /* begin RetN: */ genoperand(RetN, 0); } else { /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } jmpTarget(jumpIncorrectFormat4, jmpTarget(jumpIncorrectFormat3, jmpTarget(jumpIncorrectFormat2, jmpTarget(jumpIncorrectFormat1, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); return CompletePrimitive; } /* replaceFrom: start to: stop with: replacement startingAt: repStart. The primitive in the JIT tries to deal with two pathological cases, copy of arrays and byteStrings, which often copies only a dozen of fields and where switching to the C runtime cost a lot. Based on heuristics on the method class, I generate a quick array path (typically for Array), a quick byteString path (typically for ByteString, ByteArray and LargeInteger) or no quick path at all (Typically for Bitmap). The many tests to ensure that the primitive won't fail are not super optimised (multiple reloading or stack arguments in registers) but this is still good enough and worth it since we're avoiding the Smalltalk to C stack switch. The tight copying loops are optimised. It is possible to build a bigger version with the 2 different paths but I (Clement) believe this is too big machine code wise to be worth it. */ /* CogObjectRepresentationForSpur>>#genPrimitiveStringReplace */ static sqInt genPrimitiveStringReplace(void) { sqInt adjust; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction13; AbstractInstruction *anInstruction14; AbstractInstruction *anInstruction15; AbstractInstruction *anInstruction16; AbstractInstruction *anInstruction17; AbstractInstruction *anInstruction18; AbstractInstruction *anInstruction19; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction20; AbstractInstruction *anInstruction21; AbstractInstruction *anInstruction22; AbstractInstruction *anInstruction23; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *anInstruction9; sqInt arrayReg; AbstractInstruction * inst; AbstractInstruction * instr; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jumpEmpty; AbstractInstruction *jumpImm; AbstractInstruction *jumpImmutable; AbstractInstruction *jumpIncorrectFormat1; AbstractInstruction *jumpIncorrectFormat2; AbstractInstruction *jumpIncorrectFormat3; AbstractInstruction *jumpIncorrectFormat4; AbstractInstruction *jumpNotSmi1; AbstractInstruction *jumpNotSmi2; AbstractInstruction *jumpNotSmi3; AbstractInstruction *jumpOutOfBounds1; AbstractInstruction *jumpOutOfBounds2; AbstractInstruction *jumpOutOfBounds3; AbstractInstruction *jumpOutOfBounds4; sqInt literal; sqInt literal1; sqInt offset; sqInt offset1; sqInt offset2; sqInt offset3; sqInt offset4; sqInt offset5; sqInt offset6; sqInt offset7; sqInt offset8; sqInt offset9; sqInt quickConstant; sqInt quickConstant1; sqInt quickConstant2; sqInt quickConstant3; sqInt quickConstant4; sqInt quickConstant5; sqInt replReg; sqInt repStartReg; sqInt result; sqInt startReg; sqInt stopReg; sqInt wordConstant; /* Can I generate a quick path for this method ? */ jmpAlreadyRemembered = ((AbstractInstruction *) 0); jumpImmutable = ((AbstractInstruction *) 0); jumpOutOfBounds3 = ((AbstractInstruction *) 0); jumpOutOfBounds4 = ((AbstractInstruction *) 0); if (!((seemsToBeInstantiating(arrayFormat())) || (seemsToBeInstantiating(firstByteFormat())))) { return UnimplementedPrimitive; } arrayReg = ReceiverResultReg; startReg = Arg0Reg; stopReg = Arg1Reg; replReg = ClassReg; /* Load arguments in reg */ repStartReg = SendNumArgsReg; /* begin genStackArgAt:into: */ offset6 = (0) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction20 = genoperandoperandoperand(MoveMwrR, offset6, SPReg, repStartReg); if (usesOutOfLineLiteral(anInstruction20)) { (anInstruction20->dependent = locateLiteral(offset6)); } /* begin genStackArgAt:into: */ offset7 = (1) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction21 = genoperandoperandoperand(MoveMwrR, offset7, SPReg, replReg); if (usesOutOfLineLiteral(anInstruction21)) { (anInstruction21->dependent = locateLiteral(offset7)); } /* begin genStackArgAt:into: */ offset8 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction22 = genoperandoperandoperand(MoveMwrR, offset8, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction22)) { (anInstruction22->dependent = locateLiteral(offset8)); } /* begin genStackArgAt:into: */ offset9 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction23 = genoperandoperandoperand(MoveMwrR, offset9, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction23)) { (anInstruction23->dependent = locateLiteral(offset9)); } /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi1 = genJumpNotSmallInteger(repStartReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi2 = genJumpNotSmallInteger(stopReg); /* begin genJumpNotSmallInteger:scratchReg: */ jumpNotSmi3 = genJumpNotSmallInteger(startReg); /* if start>stop primitive success */ jumpImm = genJumpImmediate(replReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpLess: */ jumpEmpty = genConditionalBranchoperand(JumpLess, ((sqInt)0)); # if IMMUTABILITY jumpImmutable = genJumpImmutablescratchReg(ReceiverResultReg, TempReg); # endif /* IMMUTABILITY */ /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)0 << 1) | 1); anInstruction12 = genoperandoperand(CmpCqR, (((usqInt)0 << 1) | 1), startReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(literal)); } /* begin JumpLessOrEqual: */ jumpOutOfBounds1 = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ literal1 = (((usqInt)0 << 1) | 1); anInstruction13 = genoperandoperand(CmpCqR, (((usqInt)0 << 1) | 1), repStartReg); if (usesOutOfLineLiteral(anInstruction13)) { (anInstruction13->dependent = locateLiteral(literal1)); } /* begin JumpLessOrEqual: */ jumpOutOfBounds2 = genConditionalBranchoperand(JumpLessOrEqual, ((sqInt)0)); if (seemsToBeInstantiating(arrayFormat())) { /* Are they both array format ? */ genGetFormatOfinto(arrayReg, TempReg); genGetFormatOfinto(replReg, startReg); /* begin CmpCq:R: */ quickConstant = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, startReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpNonZero: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant1 = arrayFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(CmpCqR, quickConstant1, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(quickConstant1)); } /* begin JumpNonZero: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genGetNumSlotsOfinto(arrayReg, TempReg); genConvertSmallIntegerToIntegerInReg(stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds3 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); genGetNumSlotsOfinto(replReg, TempReg); /* begin genStackArgAt:into: */ offset = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction14 = genoperandoperandoperand(MoveMwrR, offset, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction14)) { (anInstruction14->dependent = locateLiteral(offset)); } genConvertSmallIntegerToIntegerInReg(startReg); genConvertSmallIntegerToIntegerInReg(repStartReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, stopReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds4 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, arrayReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(arrayReg, TempReg); } /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); callStoreCheckTrampoline(); genoperand(PopR, LinkReg); jmpTarget(jmpDestYoung, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin genStackArgAt:into: */ offset1 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction15 = genoperandoperandoperand(MoveMwrR, offset1, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction15)) { (anInstruction15->dependent = locateLiteral(offset1)); } genConvertSmallIntegerToIntegerInReg(stopReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, repStartReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), repStartReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, replReg); adjust = (((usqInt) BaseHeaderSize) >> (shiftForWord())) - 1; if (adjust != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, adjust, startReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(adjust)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, adjust, stopReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(adjust)); } } /* begin MoveXwr:R:R: */ instr = genoperandoperandoperand(MoveXwrRR, startReg, replReg, TempReg); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, startReg, arrayReg); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, 1, startReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpAboveOrEqual: */ genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)instr)); jmpTarget(jumpEmpty, (methodOrBlockNumArgs <= 2 /* numRegArgs */ ? (/* begin RetN: */ genoperand(RetN, 0)) : (/* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord)))); jmpTarget(jumpIncorrectFormat1, jmpTarget(jumpIncorrectFormat2, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } if (seemsToBeInstantiating(firstByteFormat())) { /* Are they both byte array format ? CompiledMethod excluded */ genGetFormatOfinto(arrayReg, TempReg); genGetFormatOfinto(replReg, repStartReg); /* begin CmpCq:R: */ quickConstant2 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, quickConstant2, repStartReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(quickConstant2)); } /* begin JumpLess: */ jumpIncorrectFormat1 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant3 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(CmpCqR, quickConstant3, repStartReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(quickConstant3)); } /* begin JumpGreaterOrEqual: */ jumpIncorrectFormat2 = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant4 = firstByteFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction9 = genoperandoperand(CmpCqR, quickConstant4, TempReg); if (usesOutOfLineLiteral(anInstruction9)) { (anInstruction9->dependent = locateLiteral(quickConstant4)); } /* begin JumpLess: */ jumpIncorrectFormat3 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); /* begin CmpCq:R: */ quickConstant5 = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperand(CmpCqR, quickConstant5, TempReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(quickConstant5)); } /* begin JumpGreaterOrEqual: */ jumpIncorrectFormat4 = genConditionalBranchoperand(JumpGreaterOrEqual, ((sqInt)0)); genGetNumSlotsOfinto(arrayReg, startReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), startReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, startReg); genConvertSmallIntegerToIntegerInReg(stopReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds3 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin MoveR:R: */ genoperandoperand(MoveRR, repStartReg, TempReg); /* begin genStackArgAt:into: */ offset2 = (0) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction16 = genoperandoperandoperand(MoveMwrR, offset2, SPReg, repStartReg); if (usesOutOfLineLiteral(anInstruction16)) { (anInstruction16->dependent = locateLiteral(offset2)); } /* begin genStackArgAt:into: */ offset3 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction17 = genoperandoperandoperand(MoveMwrR, offset3, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction17)) { (anInstruction17->dependent = locateLiteral(offset3)); } genConvertSmallIntegerToIntegerInReg(startReg); genConvertSmallIntegerToIntegerInReg(repStartReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, stopReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, stopReg); genGetNumSlotsOfinto(replReg, startReg); /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, shiftForWord(), startReg); gAndCqRR(BytesPerWord - 1, TempReg, TempReg); /* begin SubR:R: */ genoperandoperand(SubRR, TempReg, startReg); /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpGreater: */ jumpOutOfBounds4 = genConditionalBranchoperand(JumpGreater, ((sqInt)0)); /* begin genStackArgAt:into: */ offset4 = (3) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction18 = genoperandoperandoperand(MoveMwrR, offset4, SPReg, startReg); if (usesOutOfLineLiteral(anInstruction18)) { (anInstruction18->dependent = locateLiteral(offset4)); } genConvertSmallIntegerToIntegerInReg(startReg); /* begin genStackArgAt:into: */ offset5 = (2) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction19 = genoperandoperandoperand(MoveMwrR, offset5, SPReg, stopReg); if (usesOutOfLineLiteral(anInstruction19)) { (anInstruction19->dependent = locateLiteral(offset5)); } genConvertSmallIntegerToIntegerInReg(stopReg); /* begin SubR:R: */ genoperandoperand(SubRR, startReg, repStartReg); /* begin AddR:R: */ genoperandoperand(AddRR, repStartReg, replReg); adjust = BaseHeaderSize - 1; if (adjust != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AddCqR, adjust, startReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(adjust)); } /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(AddCqR, adjust, stopReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(adjust)); } } /* begin MoveXbr:R:R: */ instr = genoperandoperandoperand(MoveXbrRR, startReg, replReg, TempReg); /* begin MoveR:Xbr:R: */ genoperandoperandoperand(MoveRXbrR, TempReg, startReg, arrayReg); /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperand(AddCqR, 1, startReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral(1)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, startReg, stopReg); /* begin JumpAboveOrEqual: */ genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)instr)); jmpTarget(jumpEmpty, (methodOrBlockNumArgs <= 2 /* numRegArgs */ ? (/* begin RetN: */ genoperand(RetN, 0)) : (/* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord)))); jmpTarget(jumpIncorrectFormat4, jmpTarget(jumpIncorrectFormat3, jmpTarget(jumpIncorrectFormat2, jmpTarget(jumpIncorrectFormat1, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); } if (((result = compileInterpreterPrimitive())) < 0) { return result; } jmpTarget(jumpImm, jmpTarget(jumpNotSmi1, jmpTarget(jumpNotSmi2, jmpTarget(jumpNotSmi3, genoperandoperand(Label, (labelCounter += 1), bytecodePC))))); jmpTarget(jumpOutOfBounds1, jmpTarget(jumpOutOfBounds2, jmpTarget(jumpOutOfBounds3, jmpTarget(jumpOutOfBounds4, ((AbstractInstruction *) (((jumpImm->operands))[0])))))); # if IMMUTABILITY jmpTarget(jumpImmutable, ((AbstractInstruction *) (((jumpImm->operands))[0]))); # endif /* IMMUTABILITY */ return CompletePrimitive; } /* CogObjectRepresentationForSpur>>#genSetSmallIntegerTagsIn: */ static sqInt NoDbgRegParms genSetSmallIntegerTagsIn(sqInt scratchReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(OrCqR, 1, scratchReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(1)); } return 0; } /* Create a trampoline to store-check the update of the receiver in a closure's outerContext in compileBlockFrameBuild:. */ /* CogObjectRepresentationForSpur>>#genStoreCheckContextReceiverTrampoline */ static sqInt genStoreCheckContextReceiverTrampoline(void) { sqInt startAddress; startAddress = methodZoneBase(); zeroOpcodeIndex(); genStoreCheckReceiverRegvalueRegscratchReginFrame(ReceiverResultReg, Arg0Reg, TempReg, 0); /* begin RetN: */ genoperand(RetN, 0); outputInstructionsForGeneratedRuntimeAt(startAddress); recordGeneratedRunTimeaddress("ceStoreCheckContextReceiver", startAddress); recordRunTimeObjectReferences(); return startAddress; } /* Generate the code for a store check of valueReg into destReg. */ /* CogObjectRepresentationForSpur>>#genStoreCheckReceiverReg:valueReg:scratchReg:inFrame: */ static sqInt NoDbgRegParms genStoreCheckReceiverRegvalueRegscratchReginFrame(sqInt destReg, sqInt valueReg, sqInt scratchReg, sqInt inFrame) { AbstractInstruction *abstractInstruction; AbstractInstruction * inst; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jmpImmediate; AbstractInstruction *jmpSourceOld; sqInt wordConstant; /* Is value stored an immediate? If so we're done */ jmpAlreadyRemembered = ((AbstractInstruction *) 0); /* Get the old/new boundary in scratchReg */ jmpImmediate = genJumpImmediate(valueReg); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, scratchReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, destReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, valueReg); /* begin JumpAboveOrEqual: */ jmpSourceOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(destReg, scratchReg); } assert(destReg == ReceiverResultReg); /* begin evaluateTrampolineCallBlock:protectLinkRegIfNot: */ if (inFrame) { /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); } else { /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreCheckTrampoline); (abstractInstruction->annotation = IsRelativeCall); genoperand(PopR, LinkReg); } jmpTarget(jmpImmediate, jmpTarget(jmpDestYoung, jmpTarget(jmpSourceOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, ((AbstractInstruction *) (((jmpSourceOld->operands))[0]))); } return 0; } /* CogObjectRepresentationForSpur>>#genStoreSourceReg:slotIndex:destReg:scratchReg:inFrame:needsStoreCheck: */ static sqInt NoDbgRegParms genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt inFrame, sqInt needsStoreCheck) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } if (needsStoreCheck) { return genStoreCheckReceiverRegvalueRegscratchReginFrame(destReg, sourceReg, scratchReg, inFrame); } return 0; } /* This method is used for unchecked stores in objects after their creation (typically, inlined creation of Array, closures and some temp vectors). Currently there is no need to do the immutability check here */ /* CogObjectRepresentationForSpur>>#genStoreSourceReg:slotIndex:intoNewObjectInDestReg: */ static sqInt NoDbgRegParms genStoreSourceRegslotIndexintoNewObjectInDestReg(sqInt sourceReg, sqInt index, sqInt destReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } return 0; } /* Convention: - RcvrResultReg holds the object mutated. If immutability failure: - TempReg holds the instance variable index mutated if instVarIndex > numDedicatedStoreTrampoline - ClassReg holds the value to store Registers are not lived across this trampoline as the immutability failure may need new stack frames. */ /* CogObjectRepresentationForSpur>>#genStoreTrampolineCalled:instVarIndex: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreTrampolineCalledinstVarIndex(char *trampolineName, sqInt instVarIndex) { AbstractInstruction *jumpRC; AbstractInstruction *jumpSC; zeroOpcodeIndex(); jumpSC = genJumpMutablescratchReg(ReceiverResultReg, SendNumArgsReg); compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceCannotAssignTowithIndexvalueToAssign, 3, ReceiverResultReg, (instVarIndex < (NumStoreTrampolines - 1) ? (/* begin trampolineArgConstant: */ assert(instVarIndex >= 0), -2 - instVarIndex) : TempReg), ClassReg, null, 0 /* emptyRegisterMask */, 1, NoReg); jmpTarget(jumpSC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (CheckRememberedInTrampoline) { jumpRC = genCheckRememberedBitOfscratch(ReceiverResultReg, SendNumArgsReg); assert(((jumpRC->opcode)) == JumpNonZero); (jumpRC->opcode = JumpZero); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jumpRC, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(remember, trampolineName, 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); } #endif /* IMMUTABILITY */ /* Store check code is duplicated to use a single trampoline */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityAndStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *immutableJump; AbstractInstruction *jmpAlreadyRemembered; AbstractInstruction *jmpDestYoung; AbstractInstruction *jmpImmediate; AbstractInstruction *jmpSourceOld; sqInt wordConstant; jmpAlreadyRemembered = ((AbstractInstruction *) 0); immutableJump = genJumpImmutablescratchReg(destReg, scratchReg); /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } /* Get the old/new boundary in scratchReg */ jmpImmediate = genJumpImmediate(sourceReg); /* begin MoveCw:R: */ wordConstant = storeCheckBoundary(); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, scratchReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, destReg); /* begin JumpBelow: */ jmpDestYoung = genConditionalBranchoperand(JumpBelow, ((sqInt)0)); /* begin CmpR:R: */ genoperandoperand(CmpRR, scratchReg, sourceReg); /* begin JumpAboveOrEqual: */ jmpSourceOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); if (!CheckRememberedInTrampoline) { jmpAlreadyRemembered = genCheckRememberedBitOfscratch(destReg, scratchReg); } jmpTarget(immutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (index >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, index, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(index)); } /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction3->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[index]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); if (needRestoreRcvr) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } jmpTarget(jmpImmediate, jmpTarget(jmpDestYoung, jmpTarget(jmpSourceOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (!CheckRememberedInTrampoline) { jmpTarget(jmpAlreadyRemembered, ((AbstractInstruction *) (((jmpSourceOld->operands))[0]))); } return 0; } #endif /* IMMUTABILITY */ /* Gen an immutability check with no store check (e.g. assigning an immediate literal) */ /* imm check has its own trampoline */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityButNoStoreCheckSourceReg:slotIndex:destReg:scratchReg:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needRestoreRcvr) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *immutabilityFailure; AbstractInstruction *mutableJump; mutableJump = genJumpMutablescratchReg(destReg, scratchReg); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (index >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, index, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(index)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[index]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); if (needRestoreRcvr) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } /* begin Jump: */ immutabilityFailure = genoperand(Jump, ((sqInt)0)); jmpTarget(mutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin genTraceStores */ if (traceStores > 0) { /* begin MoveR:R: */ genoperandoperand(MoveRR, ClassReg, TempReg); /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceTraceStoreTrampoline); (abstractInstruction3->annotation = IsRelativeCall); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveRMwr, sourceReg, (index * BytesPerWord) + BaseHeaderSize, destReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral((index * BytesPerWord) + BaseHeaderSize)); } jmpTarget(immutabilityFailure, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } #endif /* IMMUTABILITY */ /* We know there is a frame as immutability check requires a frame */ /* needRestoreRcvr has to be true to keep RcvrResultReg live with the receiver in it across the trampoline */ /* Trampoline convention... */ /* CogObjectRepresentationForSpur>>#genStoreWithImmutabilityCheckSourceReg:slotIndex:destReg:scratchReg:needsStoreCheck:needRestoreRcvr: */ #if IMMUTABILITY static sqInt NoDbgRegParms genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(sqInt sourceReg, sqInt index, sqInt destReg, sqInt scratchReg, sqInt needsStoreCheck, sqInt needRestoreRcvr) { assert(destReg == ReceiverResultReg); assert(scratchReg == TempReg); assert(sourceReg == ClassReg); if (needsStoreCheck) { genStoreWithImmutabilityAndStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sourceReg, index, destReg, scratchReg, needRestoreRcvr); } else { genStoreWithImmutabilityButNoStoreCheckSourceRegslotIndexdestRegscratchRegneedRestoreRcvr(sourceReg, index, destReg, scratchReg, needRestoreRcvr); } return 0; } #endif /* IMMUTABILITY */ /* Make sure SendNumArgsReg and ClassReg are available in addition to ReceiverResultReg and TempReg in genGetActiveContextNumArgs:large:inBlock:. */ /* CogObjectRepresentationForSpur>>#getActiveContextAllocatesInMachineCode */ static sqInt getActiveContextAllocatesInMachineCode(void) { return 1; } /* Since all cache tags in Spur are class indices none of them are young or have to be updated in a scavenge. */ /* CogObjectRepresentationForSpur>>#inlineCacheTagIsYoung: */ static sqInt NoDbgRegParms inlineCacheTagIsYoung(sqInt cacheTag) { return 0; } /* CogObjectRepresentationForSpur>>#jumpNotCharacterUnsignedValueInRegister: */ static AbstractInstruction * NoDbgRegParms jumpNotCharacterUnsignedValueInRegister(sqInt reg) { AbstractInstruction *anInstruction; /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, (1U << 30 /* numCharacterBits */) - 1, reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral((1U << 30 /* numCharacterBits */) - 1)); } /* begin JumpAbove: */ return genConditionalBranchoperand(JumpAbove, ((sqInt)0)); } /* Mark and trace a literal in a machine code instruction preceding address in cogMethodOrNil. Answer if code was modified. */ /* CogObjectRepresentationForSpur>>#markAndTraceLiteral:in:atpc: */ static sqInt NoDbgRegParms markAndTraceLiteralinatpc(sqInt literal, CogMethod *cogMethodOrNil, usqInt address) { sqInt objOop; if (!(couldBeObject(literal))) { return 0; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return 0; } objOop = followForwarded(literal); storeLiteralbeforeFollowingAddress(backEnd(), objOop, address); markAndTraceUpdatedLiteralin(objOop, cogMethodOrNil); return 1; } /* Mark and trace a literal in a sqInt variable of cogMethod. */ /* CogObjectRepresentationForSpur>>#markAndTraceLiteral:in:at: */ static void NoDbgRegParms markAndTraceLiteralinat(sqInt literal, CogMethod *cogMethod, sqInt *address) { sqInt objOop; if (!(couldBeObject(literal))) { return; } assert(addressCouldBeObj(literal)); if (!(isForwarded(literal))) { markAndTrace(literal); return; } objOop = followForwarded(literal); address[0] = objOop; markAndTraceUpdatedLiteralin(objOop, cogMethod); } /* Common code to mark a literal in cogMethod and add the cogMethod to youngReferrers if the literal is young. */ /* CogObjectRepresentationForSpur>>#markAndTraceUpdatedLiteral:in: */ static void NoDbgRegParms markAndTraceUpdatedLiteralin(sqInt objOop, CogMethod *cogMethodOrNil) { if (isNonImmediate(objOop)) { if ((cogMethodOrNil != null) && (isYoungObject(objOop))) { ensureInYoungReferrers(cogMethodOrNil); } markAndTrace(objOop); } } /* If primIndex has an accessorDepth and fails, or it is external and fails with PrimErrNoMemory, call ceCheckAndMaybeRetryPrimitive if so If ceCheck.... answers true, retry the primitive. */ /* CogObjectRepresentationForSpur>>#maybeCompileRetryOnPrimitiveFail: */ static sqInt NoDbgRegParms maybeCompileRetryOnPrimitiveFail(sqInt primIndex) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmp; if ((accessorDepthForPrimitiveIndex(primIndex)) >= 0) { /* begin MoveAw:R: */ address = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmp = genConditionalBranchoperand(JumpZero, ((sqInt)0)); } else { if ((primNumberExternalCall()) != primIndex) { return 0; } /* begin MoveAw:R: */ address1 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, TempReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, PrimErrNoMemory, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(PrimErrNoMemory)); } /* begin JumpNonZero: */ jmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); } compileCallFornumArgsargargargargresultRegregsToSave(ceCheckAndMaybeRetryPrimitive, 1, trampolineArgConstant(primIndex), null, null, null, TempReg, 0 /* emptyRegisterMask */); jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Generate a shift of the register containing the class tag in a method cache probe. c.f. SpurMemoryManager>>methodCacheHashOf:with: */ /* CogObjectRepresentationForSpur>>#maybeShiftClassTagRegisterForMethodCacheProbe: */ static sqInt NoDbgRegParms maybeShiftClassTagRegisterForMethodCacheProbe(sqInt classTagReg) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, 2, classTagReg); return 0; } /* CogObjectRepresentationForSpur>>#numCharacterBits */ static sqInt numCharacterBits(void) { return 30; } /* Define how many register arguments a StackToRegisterMappingCogit can and should use with the receiver. The value must be 0, 1 or 2. Note that a SimpleStackBasedCogit always has 0 register args (although the receiver is passed in a register). The Spur object representation is simple enough that implementing at:put: is straight-forward and hence 2 register args are worth while. The method must be inlined in CoInterpreter, and dead code eliminated so that the register-popping enilopmarts such as enterRegisterArgCogMethod:- at:receiver: do not have to be implemented in SimpleStackBasedCogit. */ /* CogObjectRepresentationForSpur>>#numRegArgs */ sqInt numRegArgs(void) { return 2; } /* CogObjectRepresentationForSpur>>#remapObject: */ static sqInt NoDbgRegParms remapObject(sqInt objOop) { assert(addressCouldBeObj(objOop)); return (shouldRemapObj(objOop) ? remapObj(objOop) : objOop); } /* CogObjectRepresentationForSpur>>#remapOop: */ static sqInt NoDbgRegParms remapOop(sqInt objOop) { return (shouldRemapOop(objOop) ? remapObj(objOop) : objOop); } /* Objects in newSpace or oldSpace except nil, true, false & classTableRootObj need to be annotated. */ /* CogObjectRepresentationForSpur>>#shouldAnnotateObjectReference: */ static sqInt NoDbgRegParms shouldAnnotateObjectReference(sqInt anOop) { return (isNonImmediate(anOop)) && ((oopisGreaterThan(anOop, classTableRootObj())) || (oopisLessThan(anOop, nilObject()))); } /* CogObjectRepresentationForSpur>>#slotOffsetOfInstVarIndex: */ static sqInt NoDbgRegParms slotOffsetOfInstVarIndex(sqInt index) { return (index * BytesPerWord) + BaseHeaderSize; } /* CogOutOfLineLiteralsARMCompiler>>#cmpC32RTempByteSize */ static sqInt NoDbgRegParms cmpC32RTempByteSize(AbstractInstruction * self_in_cmpC32RTempByteSize) { return 8; } /* Generate an out-of-line literal. Copy the value and any annotation from the stand-in in the literals manager. */ /* CogOutOfLineLiteralsARMCompiler>>#concretizeLiteral */ static AbstractInstruction * NoDbgRegParms concretizeLiteral(AbstractInstruction * self_in_concretizeLiteral) { usqInt literal; AbstractInstruction * literalAsInstruction; literalAsInstruction = ((AbstractInstruction *) (((self_in_concretizeLiteral->operands))[0])); literal = ((addressIsInInstructions(literalAsInstruction)) || (literalAsInstruction == (methodLabel())) ? (literalAsInstruction->address) : ((usqInt)literalAsInstruction)); assert((((self_in_concretizeLiteral->dependent)) != null) && (((((self_in_concretizeLiteral->dependent))->opcode)) == Literal)); if (!(((((self_in_concretizeLiteral->dependent))->annotation)) == null)) { assert(((self_in_concretizeLiteral->annotation)) == null); (self_in_concretizeLiteral->annotation) = (((self_in_concretizeLiteral->dependent))->annotation); } if (!(((((self_in_concretizeLiteral->dependent))->address)) == null)) { assert(((((self_in_concretizeLiteral->dependent))->address)) == ((self_in_concretizeLiteral->address))); } (((self_in_concretizeLiteral->dependent))->address = (self_in_concretizeLiteral->address)); /* begin machineCodeAt:put: */ ((self_in_concretizeLiteral->machineCode))[0 / 4] = literal; (self_in_concretizeLiteral->machineCodeSize) = 4; return self_in_concretizeLiteral; } /* CogOutOfLineLiteralsARMCompiler>>#inlineCacheTagAt: */ static sqInt NoDbgRegParms inlineCacheTagAt(AbstractInstruction * self_in_inlineCacheTagAt, sqInt callSiteReturnAddress) { return longAt(pcRelativeAddressAt(self_in_inlineCacheTagAt, ((usqInt)(callSiteReturnAddress - 8)))); } /* Answer if the receiver is a pc-dependent instruction. With out-of-line literals any instruction that refers to a literal depends on the address of the literal, so add them in addition to the jumps. */ /* CogOutOfLineLiteralsARMCompiler>>#isPCDependent */ static sqInt NoDbgRegParms isPCDependent(AbstractInstruction * self_in_isPCDependent) { return (isJump(self_in_isPCDependent)) || ((((self_in_isPCDependent->opcode)) == AlignmentNops) || ((((self_in_isPCDependent->opcode)) != Literal) && ((((self_in_isPCDependent->dependent)) != null) && (((((self_in_isPCDependent->dependent))->opcode)) == Literal)))); } /* Return the literal referenced by the instruction immediately preceding followingAddress. */ /* CogOutOfLineLiteralsARMCompiler>>#literalBeforeFollowingAddress: */ static sqInt NoDbgRegParms literalBeforeFollowingAddress(AbstractInstruction * self_in_literalBeforeFollowingAddress, sqInt followingAddress) { return longAt(pcRelativeAddressAt(self_in_literalBeforeFollowingAddress, (instructionIsLDR(self_in_literalBeforeFollowingAddress, longAt(followingAddress - 4)) ? (/* begin instructionAddressBefore: */ followingAddress - 4) : (/* begin instructionAddressBefore: */ (followingAddress - 4) - 4)))); } /* Answer the size of a literal load instruction (which does not include the size of the literal). With out-of-line literals this is always a single LDR instruction that refers to the literal. */ /* CogOutOfLineLiteralsARMCompiler>>#literalLoadInstructionBytes */ static sqInt NoDbgRegParms literalLoadInstructionBytes(AbstractInstruction * self_in_literalLoadInstructionBytes) { return 4; } /* Answer the byte size of a MoveCwR opcode's corresponding machine code. On ARM this is a single instruction pc-relative register load - unless we have made a mistake and not turned on the out of line literals manager */ /* CogOutOfLineLiteralsARMCompiler>>#loadLiteralByteSize */ static sqInt NoDbgRegParms loadLiteralByteSize(AbstractInstruction * self_in_loadLiteralByteSize) { return 4; } /* Answer the NSSendCache for the return address of a Newspeak self, super, outer, or implicit receiver send. */ /* CogOutOfLineLiteralsARMCompiler>>#nsSendCacheAt: */ static sqInt NoDbgRegParms nsSendCacheAt(AbstractInstruction * self_in_nsSendCacheAt, sqInt callSiteReturnAddress) { return longAt(pcRelativeAddressAt(self_in_nsSendCacheAt, ((usqInt)(callSiteReturnAddress - 8)))); } /* The maximum offset in a LDR is (1<<12)-1, or (1<<10)-1 instructions. Be conservative. The issue is that one abstract instruction can emit multiple hardware instructions so we assume a 2 to 1 worst case of hardware instructions to abstract opcodes.. */ /* CogOutOfLineLiteralsARMCompiler>>#outOfLineLiteralOpcodeLimit */ static sqInt NoDbgRegParms outOfLineLiteralOpcodeLimit(AbstractInstruction * self_in_outOfLineLiteralOpcodeLimit) { return (1U << ((12 - 2) - 1)) - 1; } /* Extract the address of the ldr rX, [pc, #NNN] instruction at address */ /* CogOutOfLineLiteralsARMCompiler>>#pcRelativeAddressAt: */ static sqInt NoDbgRegParms pcRelativeAddressAt(AbstractInstruction * self_in_pcRelativeAddressAt, sqInt instrAddress) { sqInt inst; sqInt offset; inst = longAt(instrAddress); assert((inst & 4284416000U) == (ldrrnplusimm(self_in_pcRelativeAddressAt, 0, PC, 0, 0))); offset = inst & 0xFFF; return (instrAddress + 8) + ((inst & (1U << 23) ? offset : -offset)); } /* If possible we generate the method address using pc-relative addressing. If so we don't need to relocate it in code. So check if pc-relative code was generated, and if not, adjust a load literal. There are two cases, a push or a register load. If a push, then there is a register load, but in the instruction before. */ /* CogOutOfLineLiteralsARMCompiler>>#relocateMethodReferenceBeforeAddress:by: */ static AbstractInstruction * NoDbgRegParms relocateMethodReferenceBeforeAddressby(AbstractInstruction * self_in_relocateMethodReferenceBeforeAddressby, sqInt pc, sqInt delta) { sqInt litAddr; sqInt pcPrecedingLoad; sqInt reference; /* If the load is not done via pc-relative addressing we have to relocate. */ pcPrecedingLoad = (instructionIsPush(self_in_relocateMethodReferenceBeforeAddressby, longAt(pc - 4)) ? pc - 4 : pc); if (!(isPCRelativeValueLoad(self_in_relocateMethodReferenceBeforeAddressby, longAt(pcPrecedingLoad - 4)))) { litAddr = pcRelativeAddressAt(self_in_relocateMethodReferenceBeforeAddressby, pcPrecedingLoad); reference = longAt(litAddr); longAtput(litAddr, reference + delta); } return self_in_relocateMethodReferenceBeforeAddressby; } /* Rewrite a CallFull or JumpFull instruction to transfer to a different target. This variant is used to rewrite cached primitive calls where we load the target address into ip and use the 'bx ip' or 'blx ip' instruction for the actual jump or call. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteFullTransferAt:target:expectedInstruction: */ static sqInt NoDbgRegParms rewriteFullTransferAttargetexpectedInstruction(AbstractInstruction * self_in_rewriteFullTransferAttargetexpectedInstruction, usqInt callSiteReturnAddress, usqInt callTargetAddress, sqInt expectedInstruction) { assert((instructionBeforeAddress(self_in_rewriteFullTransferAttargetexpectedInstruction, callSiteReturnAddress)) == expectedInstruction); longAtput(pcRelativeAddressAt(self_in_rewriteFullTransferAttargetexpectedInstruction, callSiteReturnAddress - 8), callTargetAddress); return 0; } /* Rewrite an inline cache to call a different target for a new tag. This variant is used to link unlinked sends in ceSend:to:numArgs: et al. Answer the extent of the code change which is used to compute the range of the icache to flush. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteInlineCacheAt:tag:target: */ static sqInt NoDbgRegParms rewriteInlineCacheAttagtarget(AbstractInstruction * self_in_rewriteInlineCacheAttagtarget, usqInt callSiteReturnAddress, sqInt cacheTag, usqInt callTargetAddress) { sqInt call; usqInt callDistance; if (!(callTargetAddress >= (minCallAddress()))) { error("linking callsite to invalid address"); } /* pc offset */ /* return offset */ callDistance = ((usqInt) (callTargetAddress - ((callSiteReturnAddress + 8) - 4))); assert(isInImmediateJumpRange(self_in_rewriteInlineCacheAttagtarget, callDistance)); call = bl(self_in_rewriteInlineCacheAttagtarget, callDistance); longAtput(callSiteReturnAddress - 4, call); longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheAttagtarget, callSiteReturnAddress - 8), cacheTag); assert((inlineCacheTagAt(self_in_rewriteInlineCacheAttagtarget, callSiteReturnAddress)) == cacheTag); return 4; } /* Rewrite an inline cache with a new tag. This variant is used by the garbage collector. */ /* CogOutOfLineLiteralsARMCompiler>>#rewriteInlineCacheTag:at: */ static AbstractInstruction * NoDbgRegParms rewriteInlineCacheTagat(AbstractInstruction * self_in_rewriteInlineCacheTagat, sqInt cacheTag, sqInt callSiteReturnAddress) { longAtput(pcRelativeAddressAt(self_in_rewriteInlineCacheTagat, callSiteReturnAddress - 8), cacheTag); return self_in_rewriteInlineCacheTagat; } /* Size a jump and set its address. The target may be another instruction or an absolute address. On entry the address inst var holds our virtual address. On exit address is set to eventualAbsoluteAddress, which is where this instruction will be output. The span of a jump to a following instruction is therefore between that instruction's address and this instruction's address ((which are both still their virtual addresses), but the span of a jump to a preceding instruction or to an absolute address is between that instruction's address (which by now is its eventual absolute address) or absolute address and eventualAbsoluteAddress. ARM is simple; the 26-bit call/jump range means no short jumps. This routine only has to determine the targets of jumps, not determine sizes. This version also deals with out-of-line literals. If this is the real literal, update the stand-in in literalsManager with the address (because instructions referring to the literal are referring to the stand-in). If this is annotated with IsObjectReference transfer the annotation to the stand-in, whence it will be transferred to the real literal, simplifying update of literals. */ /* CogOutOfLineLiteralsARMCompiler>>#sizePCDependentInstructionAt: */ static usqInt NoDbgRegParms sizePCDependentInstructionAt(AbstractInstruction * self_in_sizePCDependentInstructionAt, sqInt eventualAbsoluteAddress) { usqInt alignment; if (((self_in_sizePCDependentInstructionAt->opcode)) == AlignmentNops) { (self_in_sizePCDependentInstructionAt->address) = eventualAbsoluteAddress; alignment = ((self_in_sizePCDependentInstructionAt->operands))[0]; return ((self_in_sizePCDependentInstructionAt->machineCodeSize) = ((eventualAbsoluteAddress + (alignment - 1)) & (-alignment)) - eventualAbsoluteAddress); } assert((isJump(self_in_sizePCDependentInstructionAt)) || ((((self_in_sizePCDependentInstructionAt->opcode)) == Call) || ((((self_in_sizePCDependentInstructionAt->opcode)) == CallFull) || ((((self_in_sizePCDependentInstructionAt->dependent)) != null) && (((((self_in_sizePCDependentInstructionAt->dependent))->opcode)) == Literal))))); if (isJump(self_in_sizePCDependentInstructionAt)) { resolveJumpTarget(self_in_sizePCDependentInstructionAt); } (self_in_sizePCDependentInstructionAt->address) = eventualAbsoluteAddress; if ((((self_in_sizePCDependentInstructionAt->dependent)) != null) && (((((self_in_sizePCDependentInstructionAt->dependent))->opcode)) == Literal)) { if (((self_in_sizePCDependentInstructionAt->opcode)) == Literal) { (((self_in_sizePCDependentInstructionAt->dependent))->address = (self_in_sizePCDependentInstructionAt->address)); } if (((self_in_sizePCDependentInstructionAt->annotation)) == (getIsObjectReference())) { (((self_in_sizePCDependentInstructionAt->dependent))->annotation = (self_in_sizePCDependentInstructionAt->annotation)); (self_in_sizePCDependentInstructionAt->annotation) = null; } } return ((self_in_sizePCDependentInstructionAt->machineCodeSize) = (self_in_sizePCDependentInstructionAt->maxSize)); } /* Rewrite the literal in the instruction immediately preceding followingAddress. */ /* CogOutOfLineLiteralsARMCompiler>>#storeLiteral:beforeFollowingAddress: */ static AbstractInstruction * NoDbgRegParms storeLiteralbeforeFollowingAddress(AbstractInstruction * self_in_storeLiteralbeforeFollowingAddress, sqInt literal, sqInt followingAddress) { longAtput(pcRelativeAddressAt(self_in_storeLiteralbeforeFollowingAddress, (instructionIsLDR(self_in_storeLiteralbeforeFollowingAddress, longAt(followingAddress - 4)) ? (/* begin instructionAddressBefore: */ followingAddress - 4) : (/* begin instructionAddressBefore: */ (followingAddress - 4) - 4))), literal); return self_in_storeLiteralbeforeFollowingAddress; } /* Update an instruction that depends on a label outside of generated code (e.g. a method or block header). */ /* CogOutOfLineLiteralsARMCompiler>>#updateLabel: */ static AbstractInstruction * NoDbgRegParms updateLabel(AbstractInstruction * self_in_updateLabel, AbstractInstruction *labelInstruction) { if (((self_in_updateLabel->opcode)) != Literal) { assert((((self_in_updateLabel->opcode)) == MoveCwR) || (((self_in_updateLabel->opcode)) == PushCw)); ((self_in_updateLabel->operands))[0] = (((labelInstruction->address)) + (((labelInstruction->operands))[1])); } return self_in_updateLabel; } /* Answer if the receiver uses an out-of-line literal. Needs only to work for the opcodes created with gen:literal:operand: et al. */ /* CogOutOfLineLiteralsARMCompiler>>#usesOutOfLineLiteral */ static sqInt NoDbgRegParms usesOutOfLineLiteral(AbstractInstruction * self_in_usesOutOfLineLiteral) { sqInt constant; sqInt constant1; sqInt constant2; sqInt constant3; sqInt constant4; sqInt constant5; sqInt i1; sqInt i2; sqInt i3; sqInt i4; sqInt value; unsigned int value1; unsigned int value2; switch ((self_in_usesOutOfLineLiteral->opcode)) { case CallFull: case JumpFull: case AddCwR: case AndCwR: case CmpCwR: case OrCwR: case SubCwR: case XorCwR: return 1; case AddCqR: case CmpCqR: case SubCqR: /* begin rotateable8bitSignedImmediate:ifTrue:ifFalse: */ constant = ((self_in_usesOutOfLineLiteral->operands))[0]; value = constant; while (1) { if ((value & 0xFF) == value) { return 0; } for (i1 = 2; i1 <= 30; i1 += 2) { if ((value & (((0xFFU << i1) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i1)))) == value) { return 0; } } if (!((value == constant) && (constant != 0))) break; value = -constant; } return 1; case AndCqR: case AndCqRR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant1 = ((self_in_usesOutOfLineLiteral->operands))[0]; value1 = constant1; while (1) { if ((value1 & 0xFF) == value1) { return 0; } for (i2 = 2; i2 <= 30; i2 += 2) { if ((value1 & (((0xFFU << i2) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i2)))) == value1) { return 0; } } if (!(value1 == constant1)) break; value1 = (constant1 < 0 ? -1 - constant1 : (unsigned int)~constant1); } return (1U << (highBit(((self_in_usesOutOfLineLiteral->operands))[0]))) != ((((self_in_usesOutOfLineLiteral->operands))[0]) + 1); case OrCqR: case TstCqR: case LoadEffectiveAddressMwrR: case MoveCqR: case MoveM16rR: case PushCq: /* begin rotateable8bitImmediate:ifTrue:ifFalse: */ constant2 = ((self_in_usesOutOfLineLiteral->operands))[0]; if ((constant2 & 0xFF) == constant2) { return 0; } for (i3 = 2; i3 <= 30; i3 += 2) { if ((constant2 & (((0xFFU << i3) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i3)))) == constant2) { return 0; } } return 1; case XorCqR: /* begin rotateable8bitBitwiseImmediate:ifTrue:ifFalse: */ constant3 = ((self_in_usesOutOfLineLiteral->operands))[0]; value2 = constant3; while (1) { if ((value2 & 0xFF) == value2) { return 0; } for (i4 = 2; i4 <= 30; i4 += 2) { if ((value2 & (((0xFFU << i4) & 0xFFFFFFFFU) | (((usqInt) 0xFF) >> (32 - i4)))) == value2) { return 0; } } if (!(value2 == constant3)) break; value2 = (constant3 < 0 ? -1 - constant3 : (unsigned int)~constant3); } return 1; case MoveCwR: case PushCw: return !(((addressIsInInstructions(((AbstractInstruction *) (((self_in_usesOutOfLineLiteral->operands))[0])))) || ((((AbstractInstruction *) (((self_in_usesOutOfLineLiteral->operands))[0]))) == (methodLabel()))) || (((((usqInt)(((self_in_usesOutOfLineLiteral->operands))[0]))) >= ((methodLabel->address))) && ((((usqInt)(((self_in_usesOutOfLineLiteral->operands))[0]))) < (youngReferrers())))); case MoveAwR: case MoveAbR: case PrefetchAw: return (((((self_in_usesOutOfLineLiteral->operands))[0]) != null) && (((((self_in_usesOutOfLineLiteral->operands))[0]) >= (varBaseAddress())) && (((((self_in_usesOutOfLineLiteral->operands))[0]) - (varBaseAddress())) < (1U << 12))) ? 0 : 1); case MoveRAw: case MoveRAb: return (((((self_in_usesOutOfLineLiteral->operands))[1]) != null) && (((((self_in_usesOutOfLineLiteral->operands))[1]) >= (varBaseAddress())) && (((((self_in_usesOutOfLineLiteral->operands))[1]) - (varBaseAddress())) < (1U << 12))) ? 0 : 1); case MoveRMwr: case MoveRdM64r: case MoveRMbr: case MoveRM16r: /* begin is12BitValue:ifTrue:ifFalse: */ constant4 = ((self_in_usesOutOfLineLiteral->operands))[1]; if ((SQABS(constant4)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant4 >= 0) { return 0; } else { return 0; } } else { return 1; } case MoveMbrR: case MoveM64rRd: case MoveMwrR: /* begin is12BitValue:ifTrue:ifFalse: */ constant5 = ((self_in_usesOutOfLineLiteral->operands))[0]; if ((SQABS(constant5)) <= 0xFFF) { /* (2 raisedTo: 12)-1 */ if (constant5 >= 0) { return 0; } else { return 0; } } else { return 1; } default: assert(0); } return 0; } /* CogSimStackEntry>>#ensureSpilledAt:from: */ static SimStackEntry * NoDbgRegParms ensureSpilledAtfrom(SimStackEntry * self_in_ensureSpilledAtfrom, sqInt baseOffset, sqInt baseRegister) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *inst; sqInt literal; sqInt reg; sqInt wordConstant; if ((self_in_ensureSpilledAtfrom->spilled)) { if (((self_in_ensureSpilledAtfrom->type)) == SSSpill) { assert(((((self_in_ensureSpilledAtfrom->offset)) == baseOffset) && (((self_in_ensureSpilledAtfrom->registerr)) == baseRegister)) || (violatesEnsureSpilledSpillAssert())); return self_in_ensureSpilledAtfrom; } } assert(((self_in_ensureSpilledAtfrom->type)) != SSSpill); traceSpill(self_in_ensureSpilledAtfrom); if (((self_in_ensureSpilledAtfrom->type)) == SSConstant) { if (shouldAnnotateObjectReference((self_in_ensureSpilledAtfrom->constant))) { inst = annotateobjRef(gPushCw((self_in_ensureSpilledAtfrom->constant)), (self_in_ensureSpilledAtfrom->constant)); } else { /* begin PushCq: */ wordConstant = (self_in_ensureSpilledAtfrom->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperand(PushCq, wordConstant); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(wordConstant)); } inst = anInstruction; } } else { if (((self_in_ensureSpilledAtfrom->type)) == SSBaseOffset) { /* begin checkQuickConstant:forInstruction: */ literal = (self_in_ensureSpilledAtfrom->offset); anInstruction1 = genoperandoperandoperand(MoveMwrR, (self_in_ensureSpilledAtfrom->offset), (self_in_ensureSpilledAtfrom->registerr), TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(literal)); } /* begin PushR: */ inst = genoperand(PushR, TempReg); } else { assert(((self_in_ensureSpilledAtfrom->type)) == SSRegister); /* begin PushR: */ reg = (self_in_ensureSpilledAtfrom->registerr); inst = genoperand(PushR, reg); } (self_in_ensureSpilledAtfrom->type) = SSSpill; (self_in_ensureSpilledAtfrom->offset) = baseOffset; (self_in_ensureSpilledAtfrom->registerr) = baseRegister; } (self_in_ensureSpilledAtfrom->spilled) = 1; return self_in_ensureSpilledAtfrom; } /* CogSimStackEntry>>#isSameEntryAs: */ static sqInt NoDbgRegParms isSameEntryAs(SimStackEntry * self_in_isSameEntryAs, CogSimStackEntry *ssEntry) { return (((self_in_isSameEntryAs->type)) == ((ssEntry->type))) && ((((((self_in_isSameEntryAs->type)) == SSBaseOffset) || (((self_in_isSameEntryAs->type)) == SSSpill)) && ((((self_in_isSameEntryAs->offset)) == ((ssEntry->offset))) && (((self_in_isSameEntryAs->registerr)) == ((ssEntry->registerr))))) || (((((self_in_isSameEntryAs->type)) == SSRegister) && (((self_in_isSameEntryAs->registerr)) == ((ssEntry->registerr)))) || ((((self_in_isSameEntryAs->type)) == SSConstant) && (((self_in_isSameEntryAs->constant)) == ((ssEntry->constant)))))); } /* CogSimStackEntry>>#popToReg: */ static SimStackEntry * NoDbgRegParms popToReg(SimStackEntry * self_in_popToReg, sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt literal; sqInt quickConstant; sqInt reg1; if ((self_in_popToReg->spilled)) { /* begin PopR: */ genoperand(PopR, reg); } else { switch ((self_in_popToReg->type)) { case SSBaseOffset: /* begin checkQuickConstant:forInstruction: */ literal = (self_in_popToReg->offset); anInstruction = genoperandoperandoperand(MoveMwrR, (self_in_popToReg->offset), (self_in_popToReg->registerr), reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } break; case SSConstant: if (shouldAnnotateObjectReference((self_in_popToReg->constant))) { annotateobjRef(gMoveCwR((self_in_popToReg->constant), reg), (self_in_popToReg->constant)); } else { /* begin MoveCq:R: */ quickConstant = (self_in_popToReg->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } } break; case SSRegister: if (reg != ((self_in_popToReg->registerr))) { /* begin MoveR:R: */ reg1 = (self_in_popToReg->registerr); genoperandoperand(MoveRR, reg1, reg); } else { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } break; default: error("Case not found and no otherwise clause"); } } return self_in_popToReg; } /* Answer a bit mask for the receiver's register, if any. */ /* CogSimStackEntry>>#registerMask */ static sqInt NoDbgRegParms registerMask(SimStackEntry * self_in_registerMask) { sqInt reg; return ((((self_in_registerMask->type)) == SSBaseOffset) || (((self_in_registerMask->type)) == SSRegister) ? (/* begin registerMaskFor: */ (reg = (self_in_registerMask->registerr)), 1U << reg) : 0); } /* CogSimStackEntry>>#registerMaskOrNone */ static sqInt NoDbgRegParms registerMaskOrNone(SimStackEntry * self_in_registerMaskOrNone) { sqInt reg; return (((self_in_registerMaskOrNone->type)) == SSRegister ? (/* begin registerMaskFor: */ (reg = (self_in_registerMaskOrNone->registerr)), 1U << reg) : 0); } /* CogSimStackEntry>>#registerOrNone */ static sqInt NoDbgRegParms registerOrNone(SimStackEntry * self_in_registerOrNone) { return (((self_in_registerOrNone->type)) == SSRegister ? (self_in_registerOrNone->registerr) : NoReg); } /* CogSimStackEntry>>#storeToReg: */ static SimStackEntry * NoDbgRegParms storeToReg(SimStackEntry * self_in_storeToReg, sqInt reg) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt literal; sqInt quickConstant; sqInt reg1; switch ((self_in_storeToReg->type)) { case SSBaseOffset: case SSSpill: /* begin checkQuickConstant:forInstruction: */ literal = (self_in_storeToReg->offset); anInstruction = genoperandoperandoperand(MoveMwrR, (self_in_storeToReg->offset), (self_in_storeToReg->registerr), reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } break; case SSConstant: if (shouldAnnotateObjectReference((self_in_storeToReg->constant))) { annotateobjRef(gMoveCwR((self_in_storeToReg->constant), reg), (self_in_storeToReg->constant)); } else { /* begin MoveCq:R: */ quickConstant = (self_in_storeToReg->constant); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, quickConstant, reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } } break; case SSRegister: if (reg != ((self_in_storeToReg->registerr))) { /* begin MoveR:R: */ reg1 = (self_in_storeToReg->registerr); genoperandoperand(MoveRR, reg1, reg); } else { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } break; default: error("Case not found and no otherwise clause"); } return self_in_storeToReg; } /* CogSSBytecodeFixup>>#isMergeFixup */ static sqInt NoDbgRegParms isMergeFixup(BytecodeFixup * self_in_isMergeFixup) { return (((usqInt)((self_in_isMergeFixup->targetInstruction)))) == NeedsMergeFixupFlag; } /* Allocate an unsharable Literal instruction for the literal and answer it. */ /* OutOfLineLiteralsManager>>#allocateLiteral: */ static AbstractInstruction * NoDbgRegParms allocateLiteral(sqInt aLiteral) { AbstractInstruction *existingInst; sqInt i; sqInt iLimiT; sqInt initialNumLiterals; AbstractInstruction *litInst; AbstractInstruction *newInst; AbstractInstruction *newLiterals; if (nextLiteralIndex >= literalsSize) { /* begin allocateLiterals: */ initialNumLiterals = literalsSize + 8; if (initialNumLiterals > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(initialNumLiterals, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i = 0; i < nextLiteralIndex; i += 1) { existingInst = literalInstructionAt(i); newInst = (&(newLiterals[i])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i = 0, iLimiT = (opcodeIndex - 1); i <= iLimiT; i += 1) { existingInst = abstractInstructionAt(i); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = initialNumLiterals; } } litInst = literalInstructionAt(nextLiteralIndex); initializeUniqueLiteral(litInst, aLiteral); /* Record the opcodeIndex of the first dependent instruction (the first instruction that references an out-of-line literal) */ nextLiteralIndex += 1; if (firstOpcodeIndex > opcodeIndex) { firstOpcodeIndex = opcodeIndex - 1; } return litInst; } /* OutOfLineLiteralsManager>>#checkLiteral:forInstruction: */ static AbstractInstruction * NoDbgRegParms checkLiteralforInstruction(sqInt literal, AbstractInstruction *anInstruction) { if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } return anInstruction; } /* OutOfLineLiteralsManager>>#checkQuickConstant:forInstruction: */ static AbstractInstruction * NoDbgRegParms checkQuickConstantforInstruction(sqInt literal, AbstractInstruction *anInstruction) { if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } return anInstruction; } /* Output all pending literal instructions, making the originals dependents of the generated ones so that a later pass will copy the address of each generated literl inst to its original in literals, and hence allow the instruction using the literal to compute the correct address.. */ /* OutOfLineLiteralsManager>>#dumpLiterals: */ static sqInt NoDbgRegParms dumpLiterals(sqInt generateBranchAround) { sqInt i; sqInt index; AbstractInstruction *jump; AbstractInstruction *litInst; jump = ((AbstractInstruction *) 0); if (generateBranchAround) { /* begin Jump: */ jump = genoperand(Jump, ((sqInt)0)); } for (i = lastDumpedLiteralIndex; i < nextLiteralIndex; i += 1) { litInst = literalInstructionAt(i); ((genoperand(Literal, ((litInst->operands))[0]))->dependent = litInst); /* begin setLiteralOpcodeIndex: */ index = opcodeIndex; assert(((litInst->opcode)) == Literal); ((litInst->operands))[2] = index; } if (generateBranchAround) { jmpTarget(jump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* begin getOpcodeIndex */ firstOpcodeIndex = opcodeIndex; lastDumpedLiteralIndex = nextLiteralIndex; return 0; } /* return the offset need from the cPICEndSize in order to point to just after the last instruction - here that means bytesPerOop * list size */ /* OutOfLineLiteralsManager>>#endSizeOffset */ static sqInt endSizeOffset(void) { return nextLiteralIndex * BytesPerOop; } /* A literal is in range if its opcode index is within outOfLineLiteralOpcodeLimit, or if its index has yet to be assigned. */ /* OutOfLineLiteralsManager>>#literalInstructionInRange: */ static sqInt NoDbgRegParms literalInstructionInRange(AbstractInstruction *litInst) { sqInt opcodeIdx; /* begin literalOpcodeIndex */ assert(((litInst->opcode)) == Literal); opcodeIdx = ((sqInt)(((litInst->operands))[2])); return ((((sqInt)opcodeIdx)) < 0) || ((assert((getOpcodeIndex()) >= opcodeIdx), (opcodeIndex - opcodeIdx) < (outOfLineLiteralOpcodeLimit(backEnd())))); } /* Search for a Literal instruction that is in-range and answer it. Otherwise allocate a new sharable Literal instruction for the literal and answer it. */ /* OutOfLineLiteralsManager>>#locateLiteral: */ static AbstractInstruction * NoDbgRegParms locateLiteral(sqInt aLiteral) { AbstractInstruction *existingInst; sqInt i; sqInt i1; sqInt iLimiT; sqInt initialNumLiterals; AbstractInstruction *litInst; AbstractInstruction *newInst; AbstractInstruction *newLiterals; for (i = 0; i < nextLiteralIndex; i += 1) { litInst = literalInstructionAt(i); if (((((litInst->operands))[0]) == aLiteral) && (((assert(((litInst->opcode)) == Literal), ((litInst->operands))[1])) && (literalInstructionInRange(litInst)))) { return litInst; } } if (nextLiteralIndex >= literalsSize) { /* begin allocateLiterals: */ initialNumLiterals = literalsSize + 8; if (initialNumLiterals > literalsSize) { /* Must copy across state (not using realloc, cuz...) and must also update existing instructions to refer to the new ones... It's either this or modify all generation routines to be able to retry with more literals after running out of literals. */ newLiterals = calloc(initialNumLiterals, sizeof(CogAbstractInstruction)); if (!(literals == null)) { for (i1 = 0; i1 < nextLiteralIndex; i1 += 1) { existingInst = literalInstructionAt(i1); newInst = (&(newLiterals[i1])); cloneLiteralFrom(newInst, existingInst); assert(((existingInst->dependent)) == null); (existingInst->dependent = newInst); } for (i1 = 0, iLimiT = (opcodeIndex - 1); i1 <= iLimiT; i1 += 1) { existingInst = abstractInstructionAt(i1); if ((((existingInst->dependent)) != null) && (((((existingInst->dependent))->opcode)) == Literal)) { (existingInst->dependent = (((existingInst->dependent))->dependent)); } } } free(literals); literals = newLiterals; literalsSize = initialNumLiterals; } } litInst = literalInstructionAt(nextLiteralIndex); initializeSharableLiteral(litInst, aLiteral); /* Record the opcodeIndex of the first dependent instruction (the first instruction that references an out-of-line literal) */ nextLiteralIndex += 1; if (firstOpcodeIndex > opcodeIndex) { firstOpcodeIndex = opcodeIndex - 1; } return litInst; } /* OutOfLineLiteralsManager>>#mustDumpLiterals: */ static sqInt NoDbgRegParms mustDumpLiterals(sqInt currentOpcodeIndex) { return (currentOpcodeIndex >= firstOpcodeIndex) && ((currentOpcodeIndex - firstOpcodeIndex) >= (outOfLineLiteralOpcodeLimit(backEnd()))); } /* Compile the jump instruction(s) at the end of the method that dispatch to each block body. */ /* SimpleStackBasedCogit>>#compileBlockDispatch */ static sqInt compileBlockDispatch(void) { AbstractInstruction *anInstruction; AbstractInstruction *jumpSkip; assert(blockCount > 0); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } blockEntryNoContextSwitch = anInstruction; /* begin Jump: */ jumpSkip = genoperand(Jump, ((sqInt)0)); /* begin MoveR:R: */ blockEntryLabel = genoperandoperand(MoveRR, ReceiverResultReg, SendNumArgsReg); jmpTarget(jumpSkip, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (blockCount > 1) { genLoadSlotsourceRegdestReg(ClosureStartPCIndex, ReceiverResultReg, TempReg); } compileBlockDispatchFromto(0, blockCount - 1); return 0; } /* After pushing the temporaries but before the stack limit check a primitive method needs to fetch the error code, if any. If the primitive has failed, call the trampoline that will assign it to the last temp. */ /* SimpleStackBasedCogit>>#compileGetErrorCode */ static void compileGetErrorCode(void) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *jmpNoError; /* begin MoveAw:R: */ address = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmpNoError = genConditionalBranchoperand(JumpZero, ((sqInt)0)); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), ClassReg))); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceReapAndResetErrorCodeTrampoline); (abstractInstruction->annotation = IsRelativeCall); jmpTarget(jmpNoError, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* SimpleStackBasedCogit>>#compileInterpreterPrimitive */ static sqInt compileInterpreterPrimitive(void) { void (*primitiveRoutine)(void); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); return compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)); } /* Compile a call to an interpreter primitive. Call the C routine with the usual stack-switching dance, test the primFailCode and then either return on success or continue to the method body. */ /* SimpleStackBasedCogit>>#compileInterpreterPrimitive:flags: */ static sqInt NoDbgRegParms compileInterpreterPrimitiveflags(void (*primitiveRoutine)(void), sqInt flags) { sqInt address; sqInt address1; sqInt address10; sqInt address11; sqInt address12; sqInt address13; sqInt address3; sqInt address4; sqInt address5; sqInt address6; sqInt address8; sqInt address9; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; AbstractInstruction *anInstruction8; AbstractInstruction *continuePostSampleNonPrim; AbstractInstruction *continuePostSamplePrim; AbstractInstruction *jmp; AbstractInstruction *jmpSampleNonPrim; AbstractInstruction *jmpSamplePrim; sqInt offset; sqInt offset1; sqInt offset2; sqInt operand1; sqInt operand3; sqInt reg; sqInt retpc; /* Save processor fp, sp and return pc in the interpreter's frame stack and instruction pointers */ continuePostSampleNonPrim = ((AbstractInstruction *) 0); continuePostSamplePrim = ((AbstractInstruction *) 0); jmpSampleNonPrim = ((AbstractInstruction *) 0); jmpSamplePrim = ((AbstractInstruction *) 0); genExternalizePointersForPrimitiveCall(); genLoadCStackPointersForPrimCall(); if (flags & PrimCallCollectsProfileSamples) { /* Test nextProfileTick for being non-zero and call checkProfileTick if so */ /* begin MoveAw:R: */ address = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin MoveAw:R: */ address1 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSampleNonPrim = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSampleNonPrim = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } if (recordPrimTrace()) { genFastPrimTraceUsingand(ClassReg, SendNumArgsReg); } /* begin checkQuickConstant:forInstruction: */ anInstruction8 = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction8)) { (anInstruction8->dependent = locateLiteral(0)); } /* begin MoveR:Aw: */ address11 = primFailCodeAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address11, genoperandoperand(MoveRAw, TempReg, address11)); if (methodOrBlockNumArgs != 0) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, methodOrBlockNumArgs, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(methodOrBlockNumArgs)); } } /* begin MoveR:Aw: */ address12 = argumentCountAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address12, genoperandoperand(MoveRAw, TempReg, address12)); if (flags & PrimCallNeedsPrimitiveFunction) { /* begin MoveCw:R: */ checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperandoperand(MoveCwR, ((sqInt)primitiveRoutine), TempReg)); /* begin MoveR:Aw: */ address3 = primitiveFunctionPointerAddress(); /* begin gen:operand:literal: */ primSetFunctionLabel = checkLiteralforInstruction(address3, genoperandoperand(MoveRAw, TempReg, address3)); } if (flags & (PrimCallNeedsNewMethod + PrimCallMayCallBack)) { /* The ceActivateFailingPrimitiveMethod: machinery can't handle framelessness. */ if (flags & PrimCallMayCallBack) { needsFrame = 1; } addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), ClassReg))); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, methodObject); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset)); } /* begin MoveR:Aw: */ address4 = newMethodAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address4, genoperandoperand(MoveRAw, TempReg, address4)); } /* begin PrefetchAw: */ address13 = primFailCodeAddress(); /* begin gen:literal: */ checkLiteralforInstruction(address13, genoperand(PrefetchAw, address13)); if (flags & PrimCallMayCallBack) { /* Sideways call the C primitive routine so that we return through cePrimReturnEnterCogCode. */ /* On Spur ceActivateFailingPrimitiveMethod: would like to retry if forwarders are found. So insist on PrimCallNeedsPrimitiveFunction being set too. */ assert(flags & PrimCallNeedsPrimitiveFunction); /* begin genMarshallNArgs:arg:arg:arg:arg: */ ((AbstractInstruction *) backEnd); goto l33; genoperandoperand(MoveRR, 0, CArg0Reg); genoperandoperand(MoveRR, 0, CArg1Reg); genoperandoperand(MoveRR, 0, CArg2Reg); genoperandoperand(MoveRR, 0, CArg3Reg); ((AbstractInstruction *) backEnd); l33: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin genSubstituteReturnAddress: */ retpc = (flags & PrimCallCollectsProfileSamples ? cePrimReturnEnterCogCodeProfiling : cePrimReturnEnterCogCode); /* begin gen:literal:operand: */ checkLiteralforInstruction(retpc, genoperandoperand(MoveCwR, retpc, LR)); /* begin gen:literal: */ primInvokeInstruction = checkLiteralforInstruction(((sqInt)(((sqInt)primitiveRoutine))), genoperand(JumpFull, ((sqInt)(((sqInt)primitiveRoutine))))); jmp = (jmpSamplePrim = (continuePostSamplePrim = null)); } else { /* Call the C primitive routine. */ /* begin genMarshallNArgs:arg:arg:arg:arg: */ ((AbstractInstruction *) backEnd); goto l38; genoperandoperand(MoveRR, 0, CArg0Reg); genoperandoperand(MoveRR, 0, CArg1Reg); genoperandoperand(MoveRR, 0, CArg2Reg); genoperandoperand(MoveRR, 0, CArg3Reg); ((AbstractInstruction *) backEnd); l38: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ primInvokeInstruction = checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperand(CallFull, ((sqInt)primitiveRoutine))); /* begin genRemoveNArgsFromStack: */ assert(0 <= 4); if (flags & PrimCallCollectsProfileSamples) { assert(flags & PrimCallNeedsNewMethod); /* begin MoveAw:R: */ address5 = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address5, genoperandoperand(MoveAwR, address5, TempReg)); /* begin MoveAw:R: */ address6 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address6, genoperandoperand(MoveAwR, address6, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSamplePrim = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSamplePrim = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } maybeCompileRetryOnPrimitiveFail(primitiveIndex); maybeCompileAllocFillerCheck(); /* begin MoveAw:R: */ address8 = instructionPointerAddress(); reg = LinkReg; /* begin gen:literal:operand: */ checkLiteralforInstruction(address8, genoperandoperand(MoveAwR, address8, reg)); genLoadStackPointers(backEnd); /* begin MoveAw:R: */ address9 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address9, genoperandoperand(MoveAwR, address9, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jmp = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset1 = 0; /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveMwrR, offset1, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(offset1)); } /* begin RetN: */ genoperand(RetN, BytesPerWord); } if (flags & PrimCallCollectsProfileSamples) { /* The sample is collected by cePrimReturnEnterCogCode for external calls */ if (!(jmpSamplePrim == null)) { /* Call ceCheckProfileTick: to record sample and then continue. */ jmpTarget(jmpSamplePrim, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); assert(flags & PrimCallNeedsNewMethod); /* begin gen:literal: */ operand1 = ((usqIntptr_t)ceCheckProfileTick); checkLiteralforInstruction(operand1, genoperand(CallFull, operand1)); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSamplePrim)); } jmpTarget(jmpSampleNonPrim, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(0)); } /* begin MoveR:Aw: */ address10 = newMethodAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address10, genoperandoperand(MoveRAw, TempReg, address10)); /* begin gen:literal: */ operand3 = ((usqIntptr_t)ceCheckProfileTick); checkLiteralforInstruction(operand3, genoperand(CallFull, operand3)); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSampleNonPrim)); } if (!(jmp == null)) { /* Jump to restore of receiver reg and proceed to frame build for failure. */ jmpTarget(jmp, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin MoveMw:r:R: */ offset2 = BytesPerWord * (methodOrBlockNumArgs + (0)); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperandoperand(MoveMwrR, offset2, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(offset2)); } } return 0; } /* Compile a call to a machine-code convention interpreter primitive. Call the C routine on the Smalltalk stack, assuming it consumes little or no stack space. */ /* for now handle functions with less than 4 arguments; our C call marshalling machinery extends up to 4 arguments only, and the first argument of an mcprim is the receiver. */ /* SimpleStackBasedCogit>>#compileMachineCodeInterpreterPrimitive: */ static sqInt NoDbgRegParms compileMachineCodeInterpreterPrimitive(void (*primitiveRoutine)(void)) { AbstractInstruction *anInstruction; AbstractInstruction * jmpFail; sqInt liveRegsMask; sqInt n; sqInt offset; sqInt reg1; assert(methodOrBlockNumArgs <= 3); if ((methodOrBlockNumArgs > 2 /* numRegArgs */) || (methodOrBlockNumArgs == 0)) { /* begin registerMaskFor: */ liveRegsMask = 1U << ReceiverResultReg; } else { if (methodOrBlockNumArgs > 1) { /* begin registerMaskFor:and:and: */ liveRegsMask = ((1U << ReceiverResultReg) | (1U << Arg0Reg)) | (1U << Arg1Reg); } else { /* begin registerMaskFor:and: */ liveRegsMask = (1U << ReceiverResultReg) | (1U << Arg0Reg); } } /* begin genSaveRegs: */ if ((liveRegsMask & CallerSavedRegisterMask) == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PushSTM, liveRegsMask & CallerSavedRegisterMask); } if (methodOrBlockNumArgs > 2 /* numRegArgs */) { /* Wrangle args into Arg0Reg, Arg1Reg, SendNumArgsReg & ClassReg */ /* offset := self bitCountOf: (liveRegsMask bitAnd: CallerSavedRegisterMask). */ error("shouldBeImplemented"); } /* begin genMarshallNArgs:arg:arg:arg:arg: */ if ((methodOrBlockNumArgs + 1) == 0) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, ReceiverResultReg, CArg0Reg); if ((methodOrBlockNumArgs + 1) == 1) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, Arg0Reg, CArg1Reg); if ((methodOrBlockNumArgs + 1) == 2) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, Arg1Reg, CArg2Reg); if ((methodOrBlockNumArgs + 1) == 3) { ((AbstractInstruction *) backEnd); goto l12; } genoperandoperand(MoveRR, SendNumArgsReg, CArg3Reg); ((AbstractInstruction *) backEnd); l12: /* end genMarshallNArgs:arg:arg:arg:arg: */; /* begin gen:literal: */ checkLiteralforInstruction(((sqInt)primitiveRoutine), genoperand(CallFull, ((sqInt)primitiveRoutine))); /* begin genRemoveNArgsFromStack: */ n = methodOrBlockNumArgs + 1; assert(n <= 4); /* begin genRestoreRegs: */ if ((liveRegsMask & CallerSavedRegisterMask) == 0) { genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { genoperand(PopLDM, liveRegsMask & CallerSavedRegisterMask); } /* begin CmpCq:R: */ anInstruction = genoperandoperand(CmpCqR, 0, R0); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin JumpZero: */ jmpFail = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin MoveR:R: */ reg1 = R0; genoperandoperand(MoveRR, reg1, ReceiverResultReg); /* begin RetN: */ offset = (methodOrBlockNumArgs > 2 /* numRegArgs */ ? (methodOrBlockNumArgs + 1) * BytesPerWord : 0); genoperand(RetN, offset); jmpTarget(jmpFail, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* Compile one method cache probe in an OpenPIC's lookup of selector. Answer the jump taken if the selector probe fails. The class tag of the receiver must be in SendNumArgsReg. ClassReg and TempReg are used as scratch registers. On a hit, the offset of the entry is in ClassReg. */ /* SimpleStackBasedCogit>>#compileOpenPICMethodCacheProbeFor:withShift:baseRegOrNone: */ static AbstractInstruction * NoDbgRegParms compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selector, sqInt shift, sqInt baseRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpSelectorMiss; sqInt offset; sqInt offset1; /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ClassReg); maybeShiftClassTagRegisterForMethodCacheProbe(ClassReg); annotateobjRef(gXorCwR(selector, ClassReg), selector); assert(shift <= (shiftForWord())); if (shift < (shiftForWord())) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - shift, ClassReg); } /* begin AndCq:R: */ anInstruction4 = genoperandoperand(AndCqR, ((int)((usqInt)(MethodCacheMask) << (shiftForWord()))), ClassReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(((int)((usqInt)(MethodCacheMask) << (shiftForWord()))))); } if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheSelector) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } else { /* begin AddR:R: */ genoperandoperand(AddRR, baseRegOrNone, ClassReg); /* begin MoveMw:r:R: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))))); } } annotateobjRef(checkLiteralforInstruction(selector, genoperandoperand(CmpCwR, selector, TempReg)), selector); /* begin JumpNonZero: */ jumpSelectorMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset1 = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheClass) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset1, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset1)); } } else { /* begin MoveMw:r:R: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheClass) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(((int)((usqInt)(MethodCacheClass) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, SendNumArgsReg, TempReg); return jumpSelectorMiss; } /* Compile the code for an open PIC. Perform a probe of the first-level method lookup cache followed by a call of ceSendFromInLineCacheMiss: if the probe fails. */ /* SimpleStackBasedCogit>>#compileOpenPIC:numArgs: */ static void NoDbgRegParms compileOpenPICnumArgs(sqInt selector, sqInt numArgs) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt cacheBaseReg; AbstractInstruction *itsAHit; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpClassMiss; AbstractInstruction *jumpSelectorMiss; sqInt offset; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compilePICAbort(numArgs); entry = genGetClassTagOfintoscratchReg(ReceiverResultReg, SendNumArgsReg, TempReg); flag("lookupInMethodCacheSel:classTag:"); cacheBaseReg = NoReg; jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 0, cacheBaseReg); /* begin JumpNonZero: */ jumpClassMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset = (cacheBaseReg == NoReg ? (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))) : ((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } itsAHit = anInstruction1; genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); jmpTarget(jumpBCMethod, picInterpretAbort); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, cmNoCheckEntryOffset, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(cmNoCheckEntryOffset)); } /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpSelectorMiss, jmpTarget(jumpClassMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 1, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSelectorMiss = compileOpenPICMethodCacheProbeForwithShiftbaseRegOrNone(selector, 2, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); genSmalltalkToCStackSwitch(1); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), SendNumArgsReg))); compileCallFornumArgsargargargargresultRegregsToSave(ceSendFromInLineCacheMiss, 1, SendNumArgsReg, null, null, null, NoReg, 0 /* emptyRegisterMask */); } /* Compile one method cache probe in a perform: primitive's lookup of selector. Answer the jump taken if the selector probe fails. */ /* SimpleStackBasedCogit>>#compilePerformMethodCacheProbeFor:withShift:baseRegOrNone: */ static AbstractInstruction * NoDbgRegParms compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(sqInt selectorReg, sqInt shift, sqInt baseRegOrNone) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *jumpSelectorMiss; sqInt offset; sqInt offset1; /* begin MoveR:R: */ genoperandoperand(MoveRR, SendNumArgsReg, ClassReg); maybeShiftClassTagRegisterForMethodCacheProbe(ClassReg); /* begin XorR:R: */ genoperandoperand(XorRR, selectorReg, ClassReg); assert(shift <= (shiftForWord())); if (shift < (shiftForWord())) { /* begin LogicalShiftLeftCq:R: */ genoperandoperand(LogicalShiftLeftCqR, (shiftForWord()) - shift, ClassReg); } /* begin AndCq:R: */ anInstruction4 = genoperandoperand(AndCqR, ((int)((usqInt)(MethodCacheMask) << (shiftForWord()))), ClassReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(((int)((usqInt)(MethodCacheMask) << (shiftForWord()))))); } if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheSelector) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } else { /* begin AddR:R: */ genoperandoperand(AddRR, baseRegOrNone, ClassReg); /* begin MoveMw:r:R: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(((int)((usqInt)(MethodCacheSelector) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, selectorReg, TempReg); /* begin JumpNonZero: */ jumpSelectorMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); if (baseRegOrNone == NoReg) { /* begin MoveMw:r:R: */ offset1 = (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheClass) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset1, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset1)); } } else { /* begin MoveMw:r:R: */ anInstruction3 = genoperandoperandoperand(MoveMwrR, ((int)((usqInt)(MethodCacheClass) << (shiftForWord()))), ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(((int)((usqInt)(MethodCacheClass) << (shiftForWord()))))); } } /* begin CmpR:R: */ genoperandoperand(CmpRR, SendNumArgsReg, TempReg); return jumpSelectorMiss; } /* Compile a primitive. If possible, performance-critical primtiives will be generated by their own routines (primitiveGenerator). Otherwise, if there is a primitive at all, we call the C routine with the usual stack-switching dance, test the primFailCode and then either return on success or continue to the method body. */ /* SimpleStackBasedCogit>>#compilePrimitive */ static sqInt compilePrimitive(void) { sqInt code; sqInt flags; sqInt opcodeIndexAtPrimitive; PrimitiveDescriptor *primitiveDescriptor; void (*primitiveRoutine)(void); if (primitiveIndex == 0) { return 0; } /* Note opcodeIndex so that compileFallbackToInterpreterPrimitive: can discard arg load instructions for unimplemented primitives. */ code = 0; /* If a descriptor specifies an argument count (by numArgs >= 0) then it must match for the generated code to be correct. For example for speed many primitives use ResultReceiverReg instead of accessing the stack, so the receiver better be at numArgs down the stack. Use the interpreter version if not. */ opcodeIndexAtPrimitive = opcodeIndex; if ((((primitiveDescriptor = primitiveGeneratorOrNil())) != null) && ((((primitiveDescriptor->primitiveGenerator)) != null) && ((((primitiveDescriptor->primNumArgs)) < 0) || (((primitiveDescriptor->primNumArgs)) == (argumentCountOf(methodObj)))))) { code = ((primitiveDescriptor->primitiveGenerator))(); } if ((code < 0) && (code != UnimplementedPrimitive)) { /* Generator failed, so no point continuing... */ return code; } if (code == UnfailingPrimitive) { return 0; } if ((code == CompletePrimitive) && (!(((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))))) { return 0; } if (code == UnimplementedPrimitive) { opcodeIndex = opcodeIndexAtPrimitive; } flags = primitivePropertyFlags(primitiveIndex); if (flags & PrimCallDoNotJIT) { return ShouldNotJIT; } if (flags & PrimCallOnSmalltalkStack) { assert(flags == PrimCallOnSmalltalkStack); return compileMachineCodeInterpreterPrimitive(mcprimFunctionForPrimitiveIndex(primitiveIndex)); } if ((((primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex))) == 0) || (primitiveRoutine == primitiveFail)) { return genFastPrimFail(); } minValidCallAddress = ((minValidCallAddress < (((usqInt)primitiveRoutine))) ? minValidCallAddress : (((usqInt)primitiveRoutine))); return compileInterpreterPrimitiveflags(primitiveRoutine, flags); } /* SimpleStackBasedCogit>>#extendedPushBytecode */ static sqInt extendedPushBytecode(void) { sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genPushReceiverVariable(variableIndex); } if (variableType == 1) { return genPushTemporaryVariable(variableIndex); } if (variableType == 2) { return genPushLiteralIndex(variableIndex); } return genPushLiteralVariable(variableIndex); } /* SimpleStackBasedCogit>>#extendedStoreAndPopBytecode */ static sqInt extendedStoreAndPopBytecode(void) { AbstractInstruction *abstractInstruction; sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } if (variableType == 1) { genStorePopTemporaryVariable(1, variableIndex); # if IMMUTABILITY /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); # endif /* IMMUTABILITY */ return 0; } if (variableType == 3) { return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(1, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#extendedStoreBytecode */ static sqInt extendedStoreBytecode(void) { AbstractInstruction *abstractInstruction; sqInt variableIndex; sqInt variableType; variableType = (((usqInt) byte1) >> 6) & 3; variableIndex = byte1 & 0x3F; if (variableType == 0) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } if (variableType == 1) { genStorePopTemporaryVariable(0, variableIndex); # if IMMUTABILITY /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); # endif /* IMMUTABILITY */ return 0; } if (variableType == 3) { return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, variableIndex, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#frameOffsetOfTemporary: */ static sqInt NoDbgRegParms frameOffsetOfTemporary(sqInt index) { return (index < methodOrBlockNumArgs ? FoxCallerSavedIP + ((methodOrBlockNumArgs - index) * BytesPerWord) : (FoxMFReceiver - BytesPerWord) + ((methodOrBlockNumArgs - index) * BytesPerWord)); } /* Implemented with SistaCogit only */ /* SimpleStackBasedCogit>>#genCallMappedInlinedPrimitive */ static sqInt genCallMappedInlinedPrimitive(void) { return EncounteredUnknownBytecode; } /* SimpleStackBasedCogit>>#genDoubleFailIfZeroArgRcvr:arg: */ static AbstractInstruction * NoDbgRegParms genDoubleFailIfZeroArgRcvrarg(int rcvrReg, int argReg) { AbstractInstruction *anInstruction; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin ConvertR:Rd: */ genoperandoperand(ConvertRRd, TempReg, DPFPReg2); /* begin CmpRd:Rd: */ genoperandoperand(CmpRdRd, DPFPReg2, argReg); return gJumpFPEqual(0); } /* Can use any of the first 32 literals for the selector and pass up to 7 arguments. */ /* SimpleStackBasedCogit>>#genExtendedSendBytecode */ static sqInt genExtendedSendBytecode(void) { return genSendnumArgs(byte1 & 0x1F, ((usqInt) byte1) >> 5); } /* SimpleStackBasedCogit>>#genExtendedSuperBytecode */ static sqInt genExtendedSuperBytecode(void) { return genSendSupernumArgs(byte1 & 0x1F, ((usqInt) byte1) >> 5); } /* 244 11110100 i i i i i i i i Pop and Jump 0n False i i i i i i i i (+ Extend B * 256, where Extend B >= 0) */ /* SimpleStackBasedCogit>>#genExtJumpIfFalse */ static sqInt genExtJumpIfFalse(void) { sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongForwardBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; return genJumpIfto(falseObject(), target); } /* 243 11110011 i i i i i i i i Pop and Jump 0n True i i i i i i i i (+ Extend B * 256, where Extend B >= 0) */ /* SimpleStackBasedCogit>>#genExtJumpIfTrue */ static sqInt genExtJumpIfTrue(void) { sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongForwardBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; return genJumpIfto(trueObject(), target); } /* NewspeakV4: 221 11011101 Nop */ /* SistaV1: 91 01011011' Nop */ /* SimpleStackBasedCogit>>#genExtNopBytecode */ static sqInt genExtNopBytecode(void) { extA = (numExtB = (extB = 0)); return 0; } /* SistaV1: 233 11101001 iiiiiiii Push Character #iiiiiiii (+ Extend B * 256) */ /* SimpleStackBasedCogit>>#genExtPushCharacterBytecode */ static sqInt genExtPushCharacterBytecode(void) { sqInt value; value = byte1 + (((sqInt)((usqInt)(extB) << 8))); extB = 0; numExtB = 0; return genPushLiteral(characterObjectOf(value)); } /* NewsqueakV4: 229 11100101 iiiiiiii Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) SistaV1: 232 11101000 iiiiiiii Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#genExtPushIntegerBytecode */ static sqInt genExtPushIntegerBytecode(void) { sqInt value; value = byte1 + (((sqInt)((usqInt)(extB) << 8))); extB = 0; numExtB = 0; return genPushLiteral((((usqInt)value << 1) | 1)); } /* 228 11100100 i i i i i i i i Push Literal #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushLiteralBytecode */ static sqInt genExtPushLiteralBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genPushLiteralIndex(index); } /* 227 11100011 i i i i i i i i Push Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushLiteralVariableBytecode */ static sqInt genExtPushLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genPushLiteralVariable(index); } /* SistaV1: * 82 01010010 Push thisContext, (then Extend B = 1 => push thisProcess) */ /* SimpleStackBasedCogit>>#genExtPushPseudoVariable */ static sqInt genExtPushPseudoVariable(void) { sqInt ext; ext = extB; extB = 0; numExtB = 0; switch (ext) { case 0: return genPushActiveContextBytecode(); default: /* begin unknownBytecode */ return EncounteredUnknownBytecode; } return 0; } /* 226 11100010 i i i i i i i i Push Receiver Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtPushReceiverVariableBytecode */ static sqInt genExtPushReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isReadMediatedContextInstVarIndex(index) ? genPushMaybeContextReceiverVariable(index) : genPushReceiverVariable(index)); } /* 238 11101110 i i i i i j j j Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments */ /* SimpleStackBasedCogit>>#genExtSendBytecode */ static sqInt genExtSendBytecode(void) { sqInt litIndex; sqInt nArgs; litIndex = (((usqInt) byte1) >> 3) + (((sqInt)((usqInt)(extA) << 5))); extA = 0; nArgs = (byte1 & 7) + (((sqInt)((usqInt)(extB) << 3))); extB = 0; numExtB = 0; return genSendnumArgs(litIndex, nArgs); } /* 239 11101111 i i i i i j j j Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments */ /* SimpleStackBasedCogit>>#genExtSendSuperBytecode */ static sqInt genExtSendSuperBytecode(void) { int isDirected; sqInt litIndex; sqInt nArgs; if ((isDirected = extB >= 64)) { extB = extB & 0x3F; } litIndex = (((usqInt) byte1) >> 3) + (((sqInt)((usqInt)(extA) << 5))); extA = 0; nArgs = (byte1 & 7) + (((sqInt)((usqInt)(extB) << 3))); extB = 0; numExtB = 0; return (isDirected ? genSendDirectedSupernumArgs(litIndex, nArgs) : genSendSupernumArgs(litIndex, nArgs)); } /* 236 11101100 i i i i i i i i Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreAndPopLiteralVariableBytecode */ static sqInt genExtStoreAndPopLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* 235 11101011 i i i i i i i i Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreAndPopReceiverVariableBytecode */ static sqInt genExtStoreAndPopReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isWriteMediatedContextInstVarIndex(index) ? genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1) : genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1)); } /* 233 11101001 i i i i i i i i Store Literal Variable #iiiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreLiteralVariableBytecode */ static sqInt genExtStoreLiteralVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* 232 11101000 i i i i i i i i Store Receiver Variable #iiiiiii (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#genExtStoreReceiverVariableBytecode */ static sqInt genExtStoreReceiverVariableBytecode(void) { sqInt index; index = byte1 + (((sqInt)((usqInt)(extA) << 8))); extA = 0; return (isWriteMediatedContextInstVarIndex(index) ? genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1) : genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(0, index, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1)); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#genExtUnconditionalJump */ static sqInt genExtUnconditionalJump(void) { AbstractInstruction *abstractInstruction; sqInt distance; sqInt target; distance = byte1 + (((sqInt)((usqInt)(extB) << 8))); assert(distance == (v4LongBranchDistance(generatorAt(byte0), bytecodePC, ((extA != 0 ? 1 : 0)) + ((extB != 0 ? 1 : 0)), methodObj))); extB = 0; numExtB = 0; target = (distance + 2) + bytecodePC; if (distance < 0) { return genJumpBackTo(target); } genJumpTo(target); /* begin annotateBytecode: */ abstractInstruction = lastOpcode(); (abstractInstruction->annotation = HasBytecodePC); return 0; } /* SimpleStackBasedCogit>>#genFastPrimFail */ static sqInt genFastPrimFail(void) { primitiveIndex = 0; return UnfailingPrimitive; } /* Suport for compileInterpreterPrimitive. Generate inline code so as to record the primitive trace as fast as possible. */ /* SimpleStackBasedCogit>>#genFastPrimTraceUsing:and: */ static void NoDbgRegParms genFastPrimTraceUsingand(sqInt r1, sqInt r2) { sqInt address; sqInt address1; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt offset; sqInt wordConstant; /* begin MoveAb:R: */ address = primTraceLogIndexAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAbR, address, r2)); /* begin MoveR:R: */ genoperandoperand(MoveRR, r2, r1); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AddCqR, 1, r1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(1)); } /* begin MoveR:Ab: */ address1 = primTraceLogIndexAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAb, r1, address1)); addDependent(methodLabel, annotateAbsolutePCRef(gMoveCwR(((sqInt)methodLabel), r1))); /* begin MoveMw:r:R: */ offset = offsetof(CogMethod, selector); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperandoperand(MoveMwrR, offset, r1, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(offset)); } /* begin MoveCw:R: */ wordConstant = ((sqInt)(primTraceLogAddress())); /* begin gen:literal:operand: */ checkLiteralforInstruction(wordConstant, genoperandoperand(MoveCwR, wordConstant, r1)); /* begin MoveR:Xwr:R: */ genoperandoperandoperand(MoveRXwrR, TempReg, r2, r1); } /* SimpleStackBasedCogit>>#genLongJumpIfFalse */ static sqInt genLongJumpIfFalse(void) { sqInt distance; sqInt target; distance = v3LongForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 2) + bytecodePC; return genJumpIfto(falseObject(), target); } /* SimpleStackBasedCogit>>#genLongJumpIfTrue */ static sqInt genLongJumpIfTrue(void) { sqInt distance; sqInt target; distance = v3LongForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 2) + bytecodePC; return genJumpIfto(trueObject(), target); } /* 230 11100110 i i i i i i i i Push Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongPushTemporaryVariableBytecode */ static sqInt genLongPushTemporaryVariableBytecode(void) { return genPushTemporaryVariable(byte1); } /* 237 11101101 i i i i i i i i Pop and Store Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongStoreAndPopTemporaryVariableBytecode */ static sqInt genLongStoreAndPopTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(1, byte1); } /* 234 11101010 i i i i i i i i Store Temporary Variable #iiiiiiii */ /* SimpleStackBasedCogit>>#genLongStoreTemporaryVariableBytecode */ static sqInt genLongStoreTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(0, byte1); } /* SimpleStackBasedCogit>>#genLongUnconditionalBackwardJump */ static sqInt genLongUnconditionalBackwardJump(void) { sqInt distance; distance = v3LongBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); assert(distance < 0); return genJumpBackTo((distance + 2) + bytecodePC); } /* SimpleStackBasedCogit>>#genLongUnconditionalForwardJump */ static sqInt genLongUnconditionalForwardJump(void) { sqInt distance; sqInt targetpc; distance = v3LongBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); assert(distance >= 0); targetpc = (distance + 2) + bytecodePC; return genJumpTo(targetpc); } /* Compile the code for a probe of the first-level method cache for a perform primtiive. The selector is assumed to be in Arg0Reg. Defer to adjustArgumentsForPerform: to adjust the arguments before the jump to the method. */ /* SimpleStackBasedCogit>>#genLookupForPerformNumArgs: */ static sqInt NoDbgRegParms genLookupForPerformNumArgs(sqInt numArgs) { AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt cacheBaseReg; AbstractInstruction *itsAHit; AbstractInstruction *jumpClassMiss; AbstractInstruction *jumpInterpret; AbstractInstruction *jumpSelectorMiss; sqInt offset; /* N.B. Can't assume TempReg already contains the tag because a method can of course be invoked via the unchecked entry-point, e.g. as does perform:. */ genGetInlineCacheClassTagFromintoforEntry(ReceiverResultReg, SendNumArgsReg, 0); flag("lookupInMethodCacheSel:classTag:"); cacheBaseReg = NoReg; jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 0, cacheBaseReg); /* begin JumpNonZero: */ jumpClassMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveMw:r:R: */ offset = (cacheBaseReg == NoReg ? (((usqInt)(methodCacheAddress()))) + (((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))) : ((int)((usqInt)(MethodCacheMethod) << (shiftForWord())))); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, offset, ClassReg, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(offset)); } itsAHit = anInstruction1; genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); /* Adjust arguments and jump to the method's unchecked entry-point. */ jumpInterpret = genJumpImmediate(ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, cmNoCheckEntryOffset, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(cmNoCheckEntryOffset)); } adjustArgumentsForPerform(numArgs); /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpSelectorMiss, jmpTarget(jumpClassMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 1, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jumpSelectorMiss = compilePerformMethodCacheProbeForwithShiftbaseRegOrNone(Arg0Reg, 2, cacheBaseReg); /* begin JumpZero: */ genConditionalBranchoperand(JumpZero, ((sqInt)itsAHit)); jmpTarget(jumpSelectorMiss, jmpTarget(jumpInterpret, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* If the objectMemory allows it, generates a quick constant move, else generates a word constant move */ /* SimpleStackBasedCogit>>#genMoveConstant:R: */ static AbstractInstruction * NoDbgRegParms genMoveConstantR(sqInt constant, sqInt reg) { AbstractInstruction *anInstruction; return (shouldAnnotateObjectReference(constant) ? annotateobjRef(gMoveCwR(constant, reg), constant) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction = genoperandoperand(MoveCqR, constant, reg)), (usesOutOfLineLiteral(anInstruction) ? (anInstruction->dependent = locateLiteral(constant)) : 0), anInstruction)); } /* SimpleStackBasedCogit>>#genMustBeBooleanTrampolineFor:called: */ static sqInt NoDbgRegParms genMustBeBooleanTrampolineForcalled(sqInt boolean, char *trampolineName) { AbstractInstruction *anInstruction; zeroOpcodeIndex(); assert(!(shouldAnnotateObjectReference(boolean))); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, boolean, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(boolean)); } return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceSendMustBeBoolean, trampolineName, 1, TempReg, null, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); } /* Implement 28-bit hashMultiply for SmallInteger and LargePositiveInteger receivers. */ /* SimpleStackBasedCogit>>#genPrimitiveHashMultiply */ static sqInt genPrimitiveHashMultiply(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction * jmpFailImm; AbstractInstruction * jmpFailNonImm; AbstractInstruction * jmpNotSmallInt; AbstractInstruction * reenter; jmpNotSmallInt = genJumpNotSmallInteger(ReceiverResultReg); genConvertSmallIntegerToIntegerInReg(ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, HashMultiplyConstant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(HashMultiplyConstant)); } reenter = anInstruction; /* begin MulR:R: */ genMulRR(backEnd, TempReg, ReceiverResultReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(AndCqR, HashMultiplyMask, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(HashMultiplyMask)); } genConvertIntegerToSmallIntegerInReg(ReceiverResultReg); /* begin RetN: */ genoperand(RetN, 0); jmpTarget(jmpNotSmallInt, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); jmpFailImm = genJumpImmediate(ReceiverResultReg); genGetCompactClassIndexNonImmOfinto(ReceiverResultReg, ClassReg); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, ClassLargePositiveIntegerCompactIndex, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(ClassLargePositiveIntegerCompactIndex)); } /* begin JumpNonZero: */ jmpFailNonImm = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(0, ReceiverResultReg, ReceiverResultReg); /* begin Jump: */ genoperand(Jump, ((sqInt)reenter)); jmpTarget(jmpFailImm, jmpTarget(jmpFailNonImm, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* Generate the substitute return code for an external or FFI primitive call. On success simply return, extracting numArgs from newMethod. On primitive failure call ceActivateFailingPrimitiveMethod: newMethod. */ /* SimpleStackBasedCogit>>#genPrimReturnEnterCogCodeEnilopmart: */ static void NoDbgRegParms genPrimReturnEnterCogCodeEnilopmart(sqInt profiling) { sqInt address; sqInt address1; sqInt address3; sqInt address6; sqInt address7; sqInt address8; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction7; sqInt callTarget; AbstractInstruction *continuePostSample; AbstractInstruction * inst; AbstractInstruction *jmpFail; AbstractInstruction *jmpSample; sqInt quickConstant; sqInt reg; continuePostSample = ((AbstractInstruction *) 0); jmpSample = ((AbstractInstruction *) 0); zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } if (profiling) { /* Test nextProfileTick for being non-zero and call checkProfileTick: if so. N.B. nextProfileTick is 64-bits so 32-bit systems need to test both halves. */ /* begin MoveAw:R: */ address = nextProfileTickAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin MoveAw:R: */ address1 = (nextProfileTickAddress()) + BytesPerWord; /* begin gen:literal:operand: */ checkLiteralforInstruction(address1, genoperandoperand(MoveAwR, address1, ClassReg)); /* begin OrR:R: */ genoperandoperand(OrRR, TempReg, ClassReg); /* begin JumpNonZero: */ jmpSample = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin Label */ continuePostSample = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } maybeCompileAllocFillerCheck(); /* begin MoveAw:R: */ address6 = primFailCodeAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address6, genoperandoperand(MoveAwR, address6, TempReg)); flag("ask concrete code gen if move sets condition codes?"); /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(CmpCqR, 0, TempReg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jmpFail = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadStackPointers(backEnd); /* begin PopR: */ genoperand(PopR, ReceiverResultReg); /* begin MoveAw:R: */ address3 = instructionPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address3, genoperandoperand(MoveAwR, address3, PCReg)); jmpTarget(jmpFail, gMoveAwR(newMethodAddress(), SendNumArgsReg)); /* begin MoveAw:R: */ address7 = cStackPointerAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address7, genoperandoperand(MoveAwR, address7, SPReg)); compileCallFornumArgsargargargargresultRegregsToSave(ceActivateFailingPrimitiveMethod, 1, SendNumArgsReg, null, null, null, NoReg, 0 /* emptyRegisterMask */); /* begin MoveAw:R: */ address8 = instructionPointerAddress(); reg = LinkReg; /* begin gen:literal:operand: */ checkLiteralforInstruction(address8, genoperandoperand(MoveAwR, address8, reg)); genLoadStackPointers(backEnd); /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperandoperand(MoveMwrR, 0, SPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(0)); } /* begin RetN: */ genoperand(RetN, BytesPerWord); if (profiling) { /* Call ceCheckProfileTick: to record sample and then continue. newMethod should be up-to-date. Need to save and restore the link reg around this call. */ jmpTarget(jmpSample, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); /* begin saveAndRestoreLinkRegAround: */ inst = genoperand(PushR, LinkReg); /* begin CallFullRT: */ callTarget = (usqIntptr_t)ceCheckProfileTick; /* begin gen:literal: */ checkLiteralforInstruction(callTarget, genoperand(CallFull, callTarget)); genoperand(PopR, LinkReg); /* begin Jump: */ genoperand(Jump, ((sqInt)continuePostSample)); } } /* SistaV1: 230 11100110 iiiiiiii PushNClosureTemps iiiiiiii */ /* SimpleStackBasedCogit>>#genPushClosureTempsBytecode */ static sqInt genPushClosureTempsBytecode(void) { sqInt i; for (i = 1; i <= byte1; i += 1) { genPushLiteral(nilObject()); } return 0; } /* SimpleStackBasedCogit>>#genPushConstantFalseBytecode */ static sqInt genPushConstantFalseBytecode(void) { return genPushLiteral(falseObject()); } /* SimpleStackBasedCogit>>#genPushConstantNilBytecode */ static sqInt genPushConstantNilBytecode(void) { return genPushLiteral(nilObject()); } /* 79 01001111 Push 1 */ /* SimpleStackBasedCogit>>#genPushConstantOneBytecode */ static sqInt genPushConstantOneBytecode(void) { return genPushLiteral((((usqInt)1 << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushConstantTrueBytecode */ static sqInt genPushConstantTrueBytecode(void) { return genPushLiteral(trueObject()); } /* 78 01001110 Push 0 */ /* SimpleStackBasedCogit>>#genPushConstantZeroBytecode */ static sqInt genPushConstantZeroBytecode(void) { return genPushLiteral((((usqInt)0 << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushLiteralConstantBytecode */ static sqInt genPushLiteralConstantBytecode(void) { return genPushLiteralIndex(byte0 & 0x1F); } /* 16-31 0001 i i i i Push Literal Variable #iiii */ /* SimpleStackBasedCogit>>#genPushLiteralVariable16CasesBytecode */ static sqInt genPushLiteralVariable16CasesBytecode(void) { return genPushLiteralVariable(byte0 & 15); } /* SimpleStackBasedCogit>>#genPushLiteralVariableBytecode */ static sqInt genPushLiteralVariableBytecode(void) { return genPushLiteralVariable(byte0 & 0x1F); } /* SimpleStackBasedCogit>>#genPushQuickIntegerConstantBytecode */ static sqInt genPushQuickIntegerConstantBytecode(void) { return genPushLiteral((((usqInt)(byte0 - 117) << 1) | 1)); } /* SimpleStackBasedCogit>>#genPushReceiverVariableBytecode */ static sqInt genPushReceiverVariableBytecode(void) { return genPushReceiverVariable(byte0 & 15); } /* SimpleStackBasedCogit>>#genPushTemporaryVariableBytecode */ static sqInt genPushTemporaryVariableBytecode(void) { return genPushTemporaryVariable(byte0 & 15); } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnConst */ sqInt genQuickReturnConst(void) { AbstractInstruction *anInstruction; sqInt constant; constant = quickPrimitiveConstantFor(primitiveIndex); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } genUpArrowReturn(); return UnfailingPrimitive; } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnInstVar */ sqInt genQuickReturnInstVar(void) { sqInt index; index = quickPrimitiveInstVarIndexFor(primitiveIndex); genLoadSlotsourceRegdestReg(index, ReceiverResultReg, ReceiverResultReg); genUpArrowReturn(); return UnfailingPrimitive; } /* because selected by CoInterpreter>>quickPrimitiveGeneratorFor: */ /* SimpleStackBasedCogit>>#genQuickReturnSelf */ sqInt genQuickReturnSelf(void) { genUpArrowReturn(); return UnfailingPrimitive; } /* SimpleStackBasedCogit>>#genReturnFalse */ static sqInt genReturnFalse(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveFalseR: */ constant = falseObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* SimpleStackBasedCogit>>#genReturnNil */ static sqInt genReturnNil(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* SimpleStackBasedCogit>>#genReturnNilFromBlock */ static sqInt genReturnNilFromBlock(void) { AbstractInstruction *anInstruction; sqInt constant; assert(inBlock > 0); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genBlockReturn(); } /* SimpleStackBasedCogit>>#genReturnTrue */ static sqInt genReturnTrue(void) { AbstractInstruction *anInstruction; sqInt constant; /* begin genMoveTrueR: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, ReceiverResultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } return genUpArrowReturn(); } /* Can use any of the first 64 literals for the selector and pass up to 3 arguments. */ /* SimpleStackBasedCogit>>#genSecondExtendedSendBytecode */ static sqInt genSecondExtendedSendBytecode(void) { return genSendnumArgs(byte1 & 0x3F, ((usqInt) byte1) >> 6); } /* SimpleStackBasedCogit>>#genSendLiteralSelector0ArgsBytecode */ static sqInt genSendLiteralSelector0ArgsBytecode(void) { return genSendnumArgs(byte0 & 15, 0); } /* SimpleStackBasedCogit>>#genSendLiteralSelector1ArgBytecode */ static sqInt genSendLiteralSelector1ArgBytecode(void) { return genSendnumArgs(byte0 & 15, 1); } /* SimpleStackBasedCogit>>#genSendLiteralSelector2ArgsBytecode */ static sqInt genSendLiteralSelector2ArgsBytecode(void) { return genSendnumArgs(byte0 & 15, 2); } /* SimpleStackBasedCogit>>#genShortJumpIfFalse */ static sqInt genShortJumpIfFalse(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpIfto(falseObject(), target); } /* SimpleStackBasedCogit>>#genShortJumpIfTrue */ static sqInt genShortJumpIfTrue(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpIfto(trueObject(), target); } /* SimpleStackBasedCogit>>#genShortUnconditionalJump */ static sqInt genShortUnconditionalJump(void) { sqInt distance; sqInt target; distance = v3ShortForwardBranchDistance(generatorAt(byte0), bytecodePC, 0, methodObj); target = (distance + 1) + bytecodePC; return genJumpTo(target); } /* SimpleStackBasedCogit>>#genSpecialSelectorEqualsEquals */ static sqInt genSpecialSelectorEqualsEquals(void) { return genInlinedIdenticalOrNotIf(0); } /* SimpleStackBasedCogit>>#genSpecialSelectorNotEqualsEquals */ static sqInt genSpecialSelectorNotEqualsEquals(void) { return genInlinedIdenticalOrNotIf(1); } /* SimpleStackBasedCogit>>#genSpecialSelectorSend */ static sqInt genSpecialSelectorSend(void) { sqInt index; sqInt numArgs; index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); numArgs = specialSelectorNumArgs(index); return genSendnumArgs((-index) - 1, numArgs); } /* SimpleStackBasedCogit>>#genStoreAndPopReceiverVariableBytecode */ static sqInt genStoreAndPopReceiverVariableBytecode(void) { return genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(1, byte0 & 7, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } /* SimpleStackBasedCogit>>#genStoreAndPopRemoteTempLongBytecode */ static sqInt genStoreAndPopRemoteTempLongBytecode(void) { return genStorePopRemoteTempAtneedsStoreCheck(1, byte1, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant))))); } /* SimpleStackBasedCogit>>#genStoreAndPopTemporaryVariableBytecode */ static sqInt genStoreAndPopTemporaryVariableBytecode(void) { return genStorePopTemporaryVariable(1, byte0 & 7); } /* SimpleStackBasedCogit>>#genStoreRemoteTempLongBytecode */ static sqInt genStoreRemoteTempLongBytecode(void) { return genStorePopRemoteTempAtneedsStoreCheck(0, byte1, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant))))); } /* SistaV1: * 217 Trap */ /* SimpleStackBasedCogit>>#genUnconditionalTrapBytecode */ static sqInt genUnconditionalTrapBytecode(void) { return EncounteredUnknownBytecode; } /* Collect the branch and send data for cogMethod, storing it into arrayObj. */ /* SimpleStackBasedCogit>>#mapPCDataFor:into: */ sqInt mapPCDataForinto(CogMethod *cogMethod, sqInt arrayObj) { sqInt aMethodHeader; sqInt aMethodHeader1; sqInt aMethodObj; sqInt annotation; sqInt bcpc; sqInt bsOffset; sqInt byte; CogBlockMethod *cogMethod1; BytecodeDescriptor *descriptor; sqInt distance; sqInt endbcpc; sqInt errCode; CogMethod *homeMethod; sqInt isBackwardBranch; sqInt isInBlock; sqInt latestContinuation; usqInt map; sqInt mapByte; usqInt mcpc; sqInt nExts; sqInt nextBcpc; sqInt result; sqInt startbcpc; sqInt targetPC; latestContinuation = 0; introspectionDataIndex = 0; introspectionData = arrayObj; if (((cogMethod->stackCheckOffset)) == 0) { assert(introspectionDataIndex == 0); if ((cogMethod->cpicHasMNUCaseOrCMIsFullBlock)) { storePointerUncheckedofObjectwithValue(0, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(1, introspectionData, (((usqInt)cbNoSwitchEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(3, introspectionData, (((usqInt)cbEntryOffset << 1) | 1)); } else { storePointerUncheckedofObjectwithValue(0, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(1, introspectionData, (((usqInt)cmEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(3, introspectionData, (((usqInt)cmNoCheckEntryOffset << 1) | 1)); } return 4; } /* begin mapFor:bcpc:performUntil:arg: */ cogMethod1 = ((CogBlockMethod *) cogMethod); startbcpc = startPCOfMethod((cogMethod->methodObject)); assert(((cogMethod1->stackCheckOffset)) > 0); /* The stack check maps to the start of the first bytecode, the first bytecode being effectively after frame build. */ mcpc = (((usqInt)cogMethod1)) + ((cogMethod1->stackCheckOffset)); result = pcDataForAnnotationMcpcBcpcMethod(null, (0 + (((int)((usqInt)(HasBytecodePC) << 1)))), (((char *) mcpc)), startbcpc, (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } /* In both CMMethod and CMBlock cases find the start of the map and skip forward to the bytecode pc map entry for the stack check. */ bcpc = startbcpc; if (((cogMethod1->cmType)) == CMMethod) { /* begin cmIsFullBlock */ isInBlock = (cogMethod1->cpicHasMNUCaseOrCMIsFullBlock); homeMethod = ((CogMethod *) cogMethod1); assert(startbcpc == (startPCOfMethodHeader((homeMethod->methodHeader)))); map = ((((usqInt)homeMethod)) + ((homeMethod->blockSize))) - 1; annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert((annotation == IsAbsPCReference) || ((annotation == IsObjectReference) || ((annotation == IsRelativeCall) || (annotation == IsDisplacementX2N)))); latestContinuation = startbcpc; aMethodObj = (homeMethod->methodObject); endbcpc = (numBytesOf(aMethodObj)) - 1; /* begin bytecodeSetOffsetForHeader: */ aMethodHeader = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; bcpc += deltaToSkipPrimAndErrorStoreInheader(aMethodObj, (homeMethod->methodHeader)); } else { isInBlock = 1; assert(bcpc == ((cogMethod1->startpc))); homeMethod = cmHomeMethod(cogMethod1); map = findMapLocationForMcpcinMethod((((usqInt)cogMethod1)) + (sizeof(CogBlockMethod)), homeMethod); assert(map != 0); annotation = ((usqInt) (byteAt(map))) >> AnnotationShift; assert(((((usqInt) annotation) >> AnnotationShift) == HasBytecodePC) || ((((usqInt) annotation) >> AnnotationShift) == IsDisplacementX2N)); while (((annotation = ((usqInt) (byteAt(map))) >> AnnotationShift)) != HasBytecodePC) { map -= 1; } /* skip fiducial; i.e. the map entry for the pc immediately following the method header. */ map -= 1; aMethodObj = (homeMethod->methodObject); bcpc = startbcpc - ( #if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet((homeMethod->methodHeader)) ? AltBlockCreationBytecodeSize : BlockCreationBytecodeSize) #else /* MULTIPLEBYTECODESETS */ BlockCreationBytecodeSize #endif /* MULTIPLEBYTECODESETS */ ); /* begin bytecodeSetOffsetForHeader: */ aMethodHeader1 = (homeMethod->methodHeader); bsOffset = # if MULTIPLEBYTECODESETS (headerIndicatesAlternateBytecodeSet(aMethodHeader1) ? 256 : 0) # else /* MULTIPLEBYTECODESETS */ 0 # endif /* MULTIPLEBYTECODESETS */ ; byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); endbcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, -1, aMethodObj)) : 0)); bcpc = startbcpc; } nExts = 0; while ((((usqInt) (byteAt(map))) >> AnnotationShift) != HasBytecodePC) { map -= 1; } map -= 1; while (((mapByte = byteAt(map))) != MapEnd) { /* defensive; we exit on bcpc */ if (mapByte >= FirstAnnotation) { annotation = ((usqInt) mapByte) >> AnnotationShift; mcpc += (mapByte & DisplacementMask) * 4 /* codeGranularity */; if (annotation >= HasBytecodePC) { if ((annotation == IsSendCall) && ((((usqInt) ((mapByte = byteAt(map - 1)))) >> AnnotationShift) == IsAnnotationExtension)) { annotation += mapByte & DisplacementMask; map -= 1; } while (1) { byte = (fetchByteofObject(bcpc, aMethodObj)) + bsOffset; descriptor = generatorAt(byte); if (isInBlock) { if (bcpc >= endbcpc) { errCode = 0; goto l7; } } else { if (((descriptor->isReturn)) && (bcpc >= latestContinuation)) { errCode = 0; goto l7; } if ((isBranch(descriptor)) || ((descriptor->isBlockCreation))) { /* begin latestContinuationPCFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj); targetPC = (bcpc + ((descriptor->numBytes))) + (((distance < 0) ? 0 : distance)); latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } latestContinuation = latestContinuation; } nextBcpc = (bcpc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? (/* begin spanFor:at:exts:in: */ ((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) : 0)); if (((descriptor->isMapped)) || (isInBlock && ((descriptor->isMappedInBlock)))) break; bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } isBackwardBranch = (isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, bcpc, nExts, aMethodObj)) < 0)); result = pcDataForAnnotationMcpcBcpcMethod(descriptor, ((isBackwardBranch ? (((sqInt)((usqInt)(annotation) << 1))) + 1 : ((sqInt)((usqInt)(annotation) << 1)))), (((char *) mcpc)), ((isBackwardBranch ? bcpc - (2 * nExts) : bcpc)), (((void *)cogMethod))); if (result != 0) { errCode = result; goto l7; } bcpc = nextBcpc; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } else { assert(((((usqInt) mapByte) >> AnnotationShift) == IsDisplacementX2N) || ((((usqInt) mapByte) >> AnnotationShift) == IsAnnotationExtension)); if (mapByte < (((int)((usqInt)(IsAnnotationExtension) << AnnotationShift)))) { mcpc += (((sqInt)((usqInt)((mapByte - DisplacementX2N)) << AnnotationShift))) * 4 /* codeGranularity */; } } map -= 1; } errCode = 0; l7: /* end mapFor:bcpc:performUntil:arg: */; if (errCode != 0) { assert(errCode == PrimErrNoMemory); return -1; } if (((cogMethod->blockEntryOffset)) != 0) { errCode = blockDispatchTargetsForperformarg(cogMethod, pcDataForBlockEntryMethod, ((sqInt)cogMethod)); if (errCode != 0) { assert(errCode == PrimErrNoMemory); return -1; } } return introspectionDataIndex; } /* If allocCheckFiller is true, words in newSpace from freeStart to scavengeThreshold are filled with their address, and after each call of a plugin primitive, the VM checks that freeStart points to a word containing the value of freeStart. This is a simple check for primitives overwriting the ends of an object. */ /* SimpleStackBasedCogit>>#maybeCompileAllocFillerCheck */ static void maybeCompileAllocFillerCheck(void) { sqInt address; sqInt address1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmpOk; if (getCheckAllocFiller()) { /* begin MoveAw:R: */ address = freeStartAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, ClassReg)); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin CmpR:R: */ genoperandoperand(CmpRR, ClassReg, TempReg); /* begin JumpZero: */ jmpOk = genConditionalBranchoperand(JumpZero, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, PrimErrWritePastObject, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(PrimErrWritePastObject)); } /* begin MoveR:Aw: */ address1 = primFailCodeAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, TempReg, address1)); jmpTarget(jmpOk, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } } /* SimpleStackBasedCogit>>#numSpecialSelectors */ static sqInt numSpecialSelectors(void) { return # if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltNumSpecialSelectors : NumSpecialSelectors) # else /* MULTIPLEBYTECODESETS */ NumSpecialSelectors # endif /* MULTIPLEBYTECODESETS */ ; } /* Collect the branch and send data for the block method starting at blockEntryMcpc, storing it into picData. */ /* SimpleStackBasedCogit>>#pcDataForBlockEntry:Method: */ static usqInt NoDbgRegParms pcDataForBlockEntryMethod(sqInt blockEntryMcpc, sqInt cogMethod) { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)(blockEntryMcpc - blockNoContextSwitchOffset) << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)blockEntryMcpc << 1) | 1)); introspectionDataIndex += 4; return 0; } /* SimpleStackBasedCogit>>#pcDataFor:Annotation:Mcpc:Bcpc:Method: */ static sqInt NoDbgRegParms pcDataForAnnotationMcpcBcpcMethod(BytecodeDescriptor *descriptor, sqInt isBackwardBranchAndAnnotation, char *mcpc, sqInt bcpc, void *cogMethodArg) { sqInt actualBcpc; sqInt actualMcpc; if (!(descriptor)) { /* this is the stackCheck offset */ assert(introspectionDataIndex == 0); if (((((CogMethod *) cogMethodArg))->cpicHasMNUCaseOrCMIsFullBlock)) { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)cbNoSwitchEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)cbEntryOffset << 1) | 1)); } else { storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)cmEntryOffset << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 2, introspectionData, nilObject()); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 3, introspectionData, (((usqInt)cmNoCheckEntryOffset << 1) | 1)); } storePointerUncheckedofObjectwithValue(introspectionDataIndex + 4, introspectionData, (((usqInt)(bcpc + 1) << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 5, introspectionData, (((((((CogMethod *) cogMethodArg))->stackCheckOffset)) << 1) | 1)); introspectionDataIndex += 6; return 0; } if ((((usqInt) isBackwardBranchAndAnnotation) >> 1) >= HasBytecodePC) { actualBcpc = (isBackwardBranchAndAnnotation & 1 ? bcpc + 1 : (bcpc + ((descriptor->numBytes))) + 1); actualMcpc = (((usqInt)mcpc)) - (((usqInt)cogMethodArg)); storePointerUncheckedofObjectwithValue(introspectionDataIndex, introspectionData, (((usqInt)actualBcpc << 1) | 1)); storePointerUncheckedofObjectwithValue(introspectionDataIndex + 1, introspectionData, (((usqInt)actualMcpc << 1) | 1)); introspectionDataIndex += 2; } return 0; } /* If there is a generator for the current primitive then answer it; otherwise answer nil. */ /* SimpleStackBasedCogit>>#primitiveGeneratorOrNil */ static PrimitiveDescriptor * primitiveGeneratorOrNil(void) { PrimitiveDescriptor *primitiveDescriptor; static PrimitiveDescriptor primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1] = { { 0, -1 }, { genPrimitiveAdd, 1 }, { genPrimitiveSubtract, 1 }, { genPrimitiveLessThan, 1 }, { genPrimitiveGreaterThan, 1 }, { genPrimitiveLessOrEqual, 1 }, { genPrimitiveGreaterOrEqual, 1 }, { genPrimitiveEqual, 1 }, { genPrimitiveNotEqual, 1 }, { genPrimitiveMultiply, 1 }, { genPrimitiveDivide, 1 }, { genPrimitiveMod, 1 }, { genPrimitiveDiv, 1 }, { genPrimitiveQuo, 1 }, { genPrimitiveBitAnd, 1 }, { genPrimitiveBitOr, 1 }, { genPrimitiveBitXor, 1 }, { genPrimitiveBitShift, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveAsFloat, 0 }, { genPrimitiveFloatAdd, 1 }, { genPrimitiveFloatSubtract, 1 }, { genPrimitiveFloatLessThan, 1 }, { genPrimitiveFloatGreaterThan, 1 }, { genPrimitiveFloatLessOrEqual, 1 }, { genPrimitiveFloatGreaterOrEqual, 1 }, { genPrimitiveFloatEqual, 1 }, { genPrimitiveFloatNotEqual, 1 }, { genPrimitiveFloatMultiply, 1 }, { genPrimitiveFloatDivide, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveFloatSquareRoot, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveAt, 1 }, { genPrimitiveAtPut, 2 }, { genPrimitiveSize, 0 }, { genPrimitiveStringAt, 1 }, { genPrimitiveStringAtPut, 2 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { genPrimitiveObjectAt, 1 }, { 0, -1 }, { genPrimitiveNew, 0 }, { genPrimitiveNewWithArg, 1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentityHash, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveNewMethod, 2 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitivePerform, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveStringReplace, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentical, 1 }, { genPrimitiveClass, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveShallowCopy, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveStringCompareWith, 1 }, { genPrimitiveHashMultiply, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIntegerAt, 1 }, { genPrimitiveIntegerAtPut, 2 }, { 0, -1 }, { 0, -1 }, { genPrimitiveNotIdentical, 1 }, { genPrimitiveAsCharacter, -1 }, { genPrimitiveImmediateAsInteger, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveIdentityHash, 0 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genFastPrimFail, -1 }, { genFastPrimFail, -1 }, { 0, -1 }, { genPrimitiveClosureValue, 0 }, { genPrimitiveClosureValue, 1 }, { genPrimitiveClosureValue, 2 }, { genPrimitiveClosureValue, 3 }, { genPrimitiveClosureValue, 4 }, { 0, -1 }, { genPrimitiveFullClosureValue, -1 }, { 0, -1 }, { genPrimitiveFullClosureValue, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { 0, -1 }, { genPrimitiveClosureValue, 0 }, { genPrimitiveClosureValue, 1 } }; if (isQuickPrimitiveIndex(primitiveIndex)) { /* an unused one */ primitiveDescriptor = (&(primitiveGeneratorTable[0])); (primitiveDescriptor->primitiveGenerator = quickPrimitiveGeneratorFor(primitiveIndex)); return primitiveDescriptor; } if (((primitiveIndex >= 1) && (primitiveIndex <= MaxCompiledPrimitiveIndex))) { return (&(primitiveGeneratorTable[primitiveIndex])); } return null; } /* SimpleStackBasedCogit>>#recordCallOffsetIn: */ void recordCallOffsetIn(CogMethod *cogMethod) { sqInt offset; sqInt *offsetTable; offset = ((primSetFunctionLabel->address)) - (((sqInt)cogMethod)); if ((externalSetPrimOffsets[(cogMethod->cmNumArgs)]) == null) { externalSetPrimOffsets[(cogMethod->cmNumArgs)] = offset; } else { assert((externalSetPrimOffsets[(cogMethod->cmNumArgs)]) == offset); } offsetTable = (isJump(primInvokeInstruction) ? externalPrimJumpOffsets : externalPrimCallOffsets); offset = (((primInvokeInstruction->address)) + ((primInvokeInstruction->machineCodeSize))) - (((sqInt)cogMethod)); if ((offsetTable[(cogMethod->cmNumArgs)]) == null) { offsetTable[(cogMethod->cmNumArgs)] = offset; } else { assert((offsetTable[(cogMethod->cmNumArgs)]) == offset); } } /* SimpleStackBasedCogit>>#rewritePrimInvocationIn:to: */ void rewritePrimInvocationInto(CogMethod *cogMethod, void (*primFunctionPointer)(void)) { usqInt address; sqInt callTargetAddress; sqInt callTargetAddress1; sqInt extent; sqInt flags; sqInt primIndex; assert(((cogMethod->cmType)) == CMMethod); primIndex = primitiveIndexOfMethodheader((cogMethod->methodObject), (cogMethod->methodHeader)); flags = primitivePropertyFlags(primIndex); if (flags & PrimCallNeedsPrimitiveFunction) { storeLiteralbeforeFollowingAddress(backEnd, ((usqInt)primFunctionPointer), (((usqInt)cogMethod)) + (externalSetPrimOffsets[(cogMethod->cmNumArgs)])); } if (flags & PrimCallMayCallBack) { address = (((usqInt)cogMethod)) + (externalPrimJumpOffsets[(cogMethod->cmNumArgs)]); /* begin rewriteJumpFullAt:target: */ callTargetAddress = ((usqInt)primFunctionPointer); extent = rewriteFullTransferAttargetexpectedInstruction(((AbstractInstruction *) backEnd), address, callTargetAddress, 3778019100U); } else { address = (((usqInt)cogMethod)) + (externalPrimCallOffsets[(cogMethod->cmNumArgs)]); /* begin rewriteCallFullAt:target: */ callTargetAddress1 = ((usqInt)primFunctionPointer); extent = rewriteFullTransferAttargetexpectedInstruction(((AbstractInstruction *) backEnd), address, callTargetAddress1, 3778019132U); } flushICacheFromto(processor, (((usqInt)cogMethod)) + cmNoCheckEntryOffset, (((usqInt)address)) + extent); } /* Answers if the code is installed in a class instantiating objects with the format. Used in primitive generation to make a quick path based on where the method is installed. This method cannot be used as a guarantee as there can be false positive, it's just a heuristic. Tries to interpret the last literal of the method as a behavior (more than 3 fields, 3rd field a Smi). If it can be interpreted as a behavior, answers if instSpec matches the format, else answers false. */ /* SimpleStackBasedCogit>>#seemsToBeInstantiating: */ static sqInt NoDbgRegParms seemsToBeInstantiating(sqInt format) { return maybeMethodClassOfseemsToBeInstantiating(methodObj, format); } /* SimpleStackBasedCogit>>#v3:Block:Code:Size: */ static sqInt NoDbgRegParms v3BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts <= 0); return (((sqInt)((usqInt)((fetchByteofObject(pc + 2, aMethodObj))) << 8))) + (fetchByteofObject(pc + 3, aMethodObj)); } /* Answer the distance of a two byte forward long jump. */ /* SimpleStackBasedCogit>>#v3:LongForward:Branch:Distance: */ static sqInt NoDbgRegParms v3LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return (((sqInt)((usqInt)(((fetchByteofObject(pc, aMethodObj)) & 3)) << 8))) + (fetchByteofObject(pc + 1, aMethodObj)); } /* Answer the distance of a two byte forward long jump. */ /* SimpleStackBasedCogit>>#v3:Long:Branch:Distance: */ static sqInt NoDbgRegParms v3LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return (((sqInt)((usqInt)((((fetchByteofObject(pc, aMethodObj)) & 7) - 4)) << 8))) + (fetchByteofObject(pc + 1, aMethodObj)); } /* N.B. This serves for both BlueBook/V3 and V4 short jumps. */ /* SimpleStackBasedCogit>>#v3:ShortForward:Branch:Distance: */ static sqInt NoDbgRegParms v3ShortForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { assert(nExts == 0); return ((fetchByteofObject(pc, aMethodObj)) & 7) + 1; } /* 253 11111101 eei i i kkk jjjjjjjj Push Closure Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8) BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions */ /* SimpleStackBasedCogit>>#v4:Block:Code:Size: */ static sqInt NoDbgRegParms v4BlockCodeSize(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt byteOne; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; /* If nExts < 0 it isn't known and we rely on the number of extensions encoded in the eeiiikkk byte. */ byteOne = fetchByteofObject(pc + 1, aMethodObj); assert((nExts < 0) || (nExts == (((usqInt) byteOne) >> 6))); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - (((usqInt) byteOne) >> 6)) - (((usqInt) byteOne) >> 6); while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 2, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* 243 11110011 i i i i i i i i Pop and Jump 0n True i i i i i i i i (+ Extend A * 256) */ /* 244 11110100 i i i i i i i i Pop and Jump 0n False i i i i i i i i (+ Extend A * 256) */ /* SimpleStackBasedCogit>>#v4:LongForward:Branch:Distance: */ static sqInt NoDbgRegParms v4LongForwardBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; assert(nExts >= 0); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - nExts) - nExts; while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 1, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* 242 11110010 i i i i i i i i Jump i i i i i i i i (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1) */ /* SimpleStackBasedCogit>>#v4:Long:Branch:Distance: */ static sqInt NoDbgRegParms v4LongBranchDistance(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { sqInt byte; sqInt extAValue; sqInt extBValue; sqInt extBValue1; sqInt extByte; sqInt pc1; assert(nExts >= 0); /* begin parseV4Exts:priorTo:in:into: */ extAValue = (extBValue1 = 0); pc1 = (pc - nExts) - nExts; while (pc1 < pc) { byte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; extByte = fetchByteofObject(pc1, aMethodObj); pc1 += 1; assert((byte == 224) || (byte == 225)); if (byte == 224) { extAValue = (((usqInt) extAValue << 8)) + extByte; } else { extBValue1 = ((extBValue1 == 0) && (extByte > 0x7F) ? extByte - 256 : (((usqInt) extBValue1 << 8)) + extByte); } } extBValue = extBValue1; return (fetchByteofObject(pc + 1, aMethodObj)) + (((sqInt)((usqInt)(extBValue) << 8))); } /* SimpleStackBasedCogit>>#voidCogCompiledCode */ void voidCogCompiledCode(void) { sqInt i; clearCogCompiledCode(); for (i = 0; i <= MaxNumArgs; i += 1) { externalPrimJumpOffsets[i] = null; externalPrimCallOffsets[i] = null; externalSetPrimOffsets[i] = null; } } /* Add a blockStart for an embedded block. For a binary tree walk block dispatch blocks must be compiled in pc/depth-first order but are scanned in breadth-first order, so do an insertion sort (which of course is really a bubble sort because we have to move everything higher to make room). */ /* StackToRegisterMappingCogit>>#addBlockStartAt:numArgs:numCopied:span: */ static BlockStart * NoDbgRegParms addBlockStartAtnumArgsnumCopiedspan(sqInt bytecodepc, sqInt numArgs, sqInt numCopied, sqInt span) { BlockStart *blockStart; sqInt i; sqInt j; /* Transcript ensureCr; nextPutAll: 'addBlockStartAt: '; print: bytecodepc; cr; flush. */ if (blockCount > 0) { 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; } for (j = blockCount; j >= (i + 1); j += -1) { blockStarts[j] = (blockStarts[j - 1]); } blockStart = (&(blockStarts[i + 1])); } else { blockStart = (&(blockStarts[blockCount])); } blockCount += 1; (blockStart->startpc = bytecodepc); (blockStart->numArgs = numArgs); (blockStart->numCopied = numCopied); (blockStart->numInitialNils = 0); (blockStart->stackCheckLabel = null); (blockStart->hasInstVarRef = 0); (blockStart->span = span); return blockStart; } /* e.g. Receiver Receiver or Receiver Receiver (RISC) Selector/Arg0 => Arg1 Selector/Arg0 => Arg1 Arg1 Arg2 Arg1 Arg2 Arg2 Arg3 Arg2 sp-> Arg3 Arg3 sp-> retpc sp-> Arg3 sp-> retpc */ /* Generate code to adjust the possibly stacked arguments immediately before jumping to a method looked up by a perform primitive. */ /* StackToRegisterMappingCogit>>#adjustArgumentsForPerform: */ static void NoDbgRegParms adjustArgumentsForPerform(sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction10; AbstractInstruction *anInstruction11; AbstractInstruction *anInstruction12; AbstractInstruction *anInstruction3; sqInt index; assert((numRegArgs()) <= 2); assert(numArgs >= 1); if (numArgs <= 2 /* numRegArgs */) { if (numArgs == 2) { /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg1Reg, Arg0Reg); } return; } if ((2 /* numRegArgs */ + 1) == numArgs) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, 0, SPReg, Arg1Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperandoperand(MoveMwrR, BytesPerWord, SPReg, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(AddCqR, (numArgs + 1) * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral((numArgs + 1) * BytesPerWord)); } return; } for (index = (numArgs - 2); index >= 0; index += -1) { /* begin checkQuickConstant:forInstruction: */ anInstruction10 = genoperandoperandoperand(MoveMwrR, index * BytesPerWord, SPReg, TempReg); if (usesOutOfLineLiteral(anInstruction10)) { (anInstruction10->dependent = locateLiteral(index * BytesPerWord)); } /* begin checkQuickConstant:forInstruction: */ anInstruction11 = genoperandoperandoperand(MoveRMwr, TempReg, (index + 1) * BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction11)) { (anInstruction11->dependent = locateLiteral((index + 1) * BytesPerWord)); } } /* begin checkQuickConstant:forInstruction: */ anInstruction12 = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction12)) { (anInstruction12->dependent = locateLiteral(BytesPerWord)); } } /* If the stack entry is already in a register not conflicting with regMask, answers it, else allocate a new register not conflicting with reg mask */ /* StackToRegisterMappingCogit>>#allocateRegForStackEntryAt:notConflictingWith: */ static sqInt NoDbgRegParms allocateRegForStackEntryAtnotConflictingWith(sqInt index, sqInt regMask) { sqInt mask; CogSimStackEntry *stackEntry; stackEntry = ssValue(index); mask = registerMaskOrNone(stackEntry); if ((mask != 0) && ((mask & regMask) == 0)) { flag("TODO"); return registerOrNone(stackEntry); } return allocateRegNotConflictingWith(regMask); } /* if there's a free register, use it */ /* StackToRegisterMappingCogit>>#allocateRegNotConflictingWith: */ static sqInt NoDbgRegParms allocateRegNotConflictingWith(sqInt regMask) { sqInt reg; reg = availableRegisterOrNoneFor(backEnd, (liveRegisters()) | regMask); if (reg == NoReg) { /* No free register, choose one that does not conflict with regMask */ reg = freeAnyRegNotConflictingWith(regMask); } if (reg == ReceiverResultReg) { /* If we've allocated RcvrResultReg, it's not live anymore */ voidReceiverResultRegContainsSelf(); } return reg; } /* StackToRegisterMappingCogit>>#anyReferencesToRegister:inTopNItems: */ static sqInt NoDbgRegParms anyReferencesToRegisterinTopNItems(sqInt reg, sqInt n) { sqInt i; sqInt regMask; /* begin registerMaskFor: */ regMask = 1U << reg; for (i = simStackPtr; i >= ((simStackPtr - n) + 1); i += -1) { if ((registerMask(simStackAt(i))) & regMask) { return 1; } } return 0; } /* This is a static version of ceCallCogCodePopReceiverArg0Regs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* StackToRegisterMappingCogit>>#callCogCodePopReceiverArg0Regs */ void callCogCodePopReceiverArg0Regs(void) { realCECallCogCodePopReceiverArg0Regs(); } /* This is a static version of ceCallCogCodePopReceiverArg1Arg0Regs for break-pointing when debugging in C. */ /* This exists only for break-pointing. */ /* StackToRegisterMappingCogit>>#callCogCodePopReceiverArg1Arg0Regs */ void callCogCodePopReceiverArg1Arg0Regs(void) { realCECallCogCodePopReceiverArg1Arg0Regs(); } /* Loop over bytecodes, dispatching to the generator for each bytecode, handling fixups in due course. */ /* StackToRegisterMappingCogit>>#compileAbstractInstructionsFrom:through: */ static sqInt NoDbgRegParms compileAbstractInstructionsFromthrough(sqInt start, sqInt end) { BytecodeDescriptor *descriptor; BytecodeFixup *fixup; sqInt nExts; sqInt nextOpcodeIndex; sqInt result; traceSimStack(); bytecodePC = start; nExts = (result = 0); descriptor = null; deadCode = 0; while (1) { maybeHaltIfDebugPC(); mergeWithFixupIfRequired((fixup = fixupAt(bytecodePC))); descriptor = loadBytesAndGetDescriptor(); nextOpcodeIndex = opcodeIndex; result = (deadCode ? mapDeadDescriptorIfNeeded(descriptor) : ((descriptor->generator))()); if (result == 0) { /* begin assertExtsAreConsumed: */ if (!((descriptor->isExtension))) { assert((extA == 0) && ((extB == 0) && (numExtB == 0))); } } traceDescriptor(descriptor); traceSimStack(); /* begin patchFixupTargetIfNeeded:nextOpcodeIndex: */ if ((((((usqInt)((fixup->targetInstruction)))) >= NeedsNonMergeFixupFlag) && ((((usqInt)((fixup->targetInstruction)))) <= NeedsMergeFixupFlag))) { /* There is a fixup for this bytecode. It must point to the first generated instruction for this bytecode. If there isn't one we need to add a label. */ if (opcodeIndex == nextOpcodeIndex) { /* begin Label */ genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (fixup->targetInstruction = abstractInstructionAt(nextOpcodeIndex)); } /* begin maybeDumpLiterals: */ if ((mustDumpLiterals(opcodeIndex)) || (((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) || ((descriptor->isReturn)))) { dumpLiterals(!(((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) || ((descriptor->isReturn)))); } /* begin nextBytecodePCFor:exts: */ bytecodePC = (bytecodePC + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? ((descriptor->spanFunction))(descriptor, bytecodePC, nExts, methodObj) : 0)); if (!((result == 0) && (bytecodePC <= end))) break; nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } /* begin checkEnoughOpcodes */ if (opcodeIndex > numAbstractOpcodes) { error("Cog JIT internal error. Too many abstract opcodes. Num opcodes heuristic is too optimistic."); } return result; } /* StackToRegisterMappingCogit>>#compileBlockBodies */ static sqInt compileBlockBodies(void) { BlockStart *blockStart; sqInt compiledBlocksCount; sqInt initialCounterIndex; sqInt initialOpcodeIndex; sqInt initialStackPtr; sqInt (* const pushNilSizeFunction)(sqInt,sqInt) = squeakV3orSistaV1PushNilSizenumInitialNils; sqInt result; sqInt savedFirstOpcodeIndex; sqInt savedLastDumpedLiteralIndex; sqInt savedNeedsFrame; sqInt savedNextLiteralIndex; sqInt savedNumArgs; sqInt savedNumTemps; assert(blockCount > 0); savedNeedsFrame = needsFrame; savedNumArgs = methodOrBlockNumArgs; savedNumTemps = methodOrBlockNumTemps; inBlock = InVanillaBlock; compiledBlocksCount = 0; while (compiledBlocksCount < blockCount) { compilationPass = 1; blockStart = blockStartAt(compiledBlocksCount); if (((result = scanBlock(blockStart))) < 0) { return result; } initialOpcodeIndex = opcodeIndex; /* for SistaCogit */ initialCounterIndex = 0 /* maybeCounterIndex */; /* begin saveForRecompile */ savedFirstOpcodeIndex = firstOpcodeIndex; savedNextLiteralIndex = nextLiteralIndex; savedLastDumpedLiteralIndex = lastDumpedLiteralIndex; while (1) { compileBlockEntry(blockStart); initialStackPtr = simStackPtr; if (((result = compileAbstractInstructionsFromthrough(((blockStart->startpc)) + (pushNilSizeFunction(methodObj, ((blockStart->numInitialNils)))), (((blockStart->startpc)) + ((blockStart->span))) - 1))) < 0) { return result; } if (initialStackPtr == simStackPtr) break; assert((initialStackPtr > simStackPtr) || (deadCode)); /* for asserts */ compilationPass += 1; (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; /* begin resetForRecompile */ firstOpcodeIndex = savedFirstOpcodeIndex; nextLiteralIndex = savedNextLiteralIndex; lastDumpedLiteralIndex = savedLastDumpedLiteralIndex; } compiledBlocksCount += 1; } needsFrame = savedNeedsFrame; methodOrBlockNumArgs = savedNumArgs; methodOrBlockNumTemps = savedNumTemps; return 0; } /* Build a frame for a block activation. See CoInterpreter class>>initializeFrameIndices. closure (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... 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). */ /* StackToRegisterMappingCogit>>#compileBlockFrameBuild: */ static void NoDbgRegParms compileBlockFrameBuild(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction * cascade0; sqInt constant; sqInt constant1; sqInt i; sqInt ign; /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); cascade0 = (blockStart->fakeHeader); addDependent(cascade0, annotateAbsolutePCRef(gPushCw(((sqInt)((blockStart->fakeHeader)))))); /* begin setLabelOffset: */ ((cascade0->operands))[1] = MFMethodFlagIsBlockFlag; annotateobjRef(gPushCw(nilObject()), nilObject()); if ((blockStart->hasInstVarRef)) { /* Use ReceiverResultReg for Context to agree with store check trampoline */ genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ClassReg, ReceiverResultReg); genLoadSlotsourceRegdestReg(ReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, ReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } else { genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ClassReg, Arg0Reg); genLoadSlotsourceRegdestReg(ReceiverIndex, Arg0Reg, ReceiverResultReg); } /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = 0; i < ((blockStart->numCopied)); i += 1) { genLoadSlotsourceRegdestReg(i + ClosureFirstCopiedValueIndex, ClassReg, TempReg); /* begin PushR: */ genoperand(PushR, TempReg); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); (blockStart->stackCheckLabel = annotateBytecode(genoperandoperand(Label, (labelCounter += 1), bytecodePC))); methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); initSimStackForFramefulMethod((blockStart->startpc)); if (((blockStart->numInitialNils)) > 0) { if (((blockStart->numInitialNils)) > 1) { /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, TempReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } for (ign = 1; ign <= ((blockStart->numInitialNils)); ign += 1) { /* begin PushR: */ genoperand(PushR, TempReg); } } else { /* begin genPushConstant: */ constant1 = nilObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gPushCw(constant1), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperand(PushCq, constant1); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } } } } /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg. We must annotate the first instruction in vanilla blocks 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 */ /* StackToRegisterMappingCogit>>#compileBlockFramelessEntry: */ static void NoDbgRegParms compileBlockFramelessEntry(BlockStart *blockStart) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; methodOrBlockNumTemps = (((blockStart->numArgs)) + ((blockStart->numCopied))) + ((blockStart->numInitialNils)); initSimStackForFramelessBlock((blockStart->startpc)); if (!(((blockStart->entryLabel)) == null)) { /* begin annotateBytecode: */ abstractInstruction = (blockStart->entryLabel); (abstractInstruction->annotation = HasBytecodePC); /* begin annotateBytecode: */ abstractInstruction1 = (blockStart->entryLabel); (abstractInstruction1->annotation = HasBytecodePC); } if ((blockStart->hasInstVarRef)) { /* Use ReceiverResultReg for Context to agree with store check trampoline */ genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, ReceiverResultReg); genLoadSlotsourceRegdestReg(ReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, ReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } else { genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, TempReg); genLoadSlotsourceRegdestReg(ReceiverIndex, TempReg, ReceiverResultReg); } } /* StackToRegisterMappingCogit>>#compileCogFullBlockMethod: */ static CogMethod * NoDbgRegParms compileCogFullBlockMethod(sqInt numCopied) { sqInt allocBytes; sqInt fixupBytes; sqInt numBlocks; sqInt numBytecodes; sqInt numberOfAbstractOpcodes; sqInt numCleanBlocks; sqInt opcodeBytes; sqInt result; methodOrBlockNumTemps = tempCountOf(methodObj); hasYoungReferent = isYoungObject(methodObj); methodOrBlockNumArgs = argumentCountOf(methodObj); inBlock = InFullBlock; postCompileHook = null; maxLitIndex = -1; assert((primitiveIndexOf(methodObj)) == 0); /* initial estimate. Actual endPC is determined in scanMethod. */ initialPC = startPCOfMethod(methodObj); endPC = numBytesOf(methodObj); numBytecodes = (endPC - initialPC) + 1; primitiveIndex = 0; /* begin allocateOpcodes:bytecodes:ifFail: */ numberOfAbstractOpcodes = (numBytecodes + 10) * 10 /* estimateOfAbstractOpcodesPerBytecodes */; numAbstractOpcodes = numberOfAbstractOpcodes; opcodeBytes = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupBytes = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; /* Document the fact that the MaxStackAllocSize ensures that the number of abstract opcodes fits in a 16 bit integer (e.g. CogBytecodeFixup's instructionIndex). */ allocBytes = opcodeBytes + fixupBytes; assert((((sizeof(CogAbstractInstruction)) + (sizeof(CogBytecodeFixup))) * 49152) > MaxStackAllocSize); if (allocBytes > MaxStackAllocSize) { return ((CogMethod *) MethodTooBig); goto l1; } abstractOpcodes = alloca(allocBytes); bzero(abstractOpcodes, allocBytes); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeBytes)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; l1: /* end allocateOpcodes:bytecodes:ifFail: */; flag("TODO"); if (((numBlocks = scanMethod())) < 0) { return ((CogMethod *) numBlocks); } assert(numBlocks == 0); numCleanBlocks = scanForCleanBlocks(); assert(numCleanBlocks == 0); allocateBlockStarts(numBlocks + numCleanBlocks); blockCount = 0; if (numCleanBlocks > 0) { addCleanBlockStarts(); } if (!(maybeAllocAndInitIRCs())) { /* Inaccurate error code, but it'll do. This will likely never fail. */ return ((CogMethod *) InsufficientCodeSpace); } blockEntryLabel = null; (methodLabel->dependent = null); if (((result = compileEntireFullBlockMethod(numCopied))) < 0) { return ((CogMethod *) result); } return generateCogFullBlock(); } /* StackToRegisterMappingCogit>>#compileCogMethod: */ static CogMethod * NoDbgRegParms compileCogMethod(sqInt selector) { sqInt allocBytes; int extra; sqInt fixupBytes; sqInt numBlocks; sqInt numBytecodes; sqInt numberOfAbstractOpcodes; sqInt numCleanBlocks; sqInt opcodeBytes; sqInt result; methodOrBlockNumTemps = tempCountOf(methodObj); hasYoungReferent = (isYoungObject(methodObj)) || (isYoung(selector)); methodOrBlockNumArgs = argumentCountOf(methodObj); inBlock = 0; postCompileHook = null; maxLitIndex = -1; extra = ((((primitiveIndex = primitiveIndexOf(methodObj))) > 0) && (!(isQuickPrimitiveIndex(primitiveIndex))) ? 30 : 10); /* initial estimate. Actual endPC is determined in scanMethod. */ initialPC = startPCOfMethod(methodObj); endPC = (isQuickPrimitiveIndex(primitiveIndex) ? initialPC - 1 : numBytesOf(methodObj)); numBytecodes = (endPC - initialPC) + 1; /* begin allocateOpcodes:bytecodes:ifFail: */ numberOfAbstractOpcodes = (numBytecodes + extra) * 10 /* estimateOfAbstractOpcodesPerBytecodes */; numAbstractOpcodes = numberOfAbstractOpcodes; opcodeBytes = (sizeof(CogAbstractInstruction)) * numAbstractOpcodes; fixupBytes = (sizeof(CogBytecodeFixup)) * numAbstractOpcodes; /* Document the fact that the MaxStackAllocSize ensures that the number of abstract opcodes fits in a 16 bit integer (e.g. CogBytecodeFixup's instructionIndex). */ allocBytes = opcodeBytes + fixupBytes; assert((((sizeof(CogAbstractInstruction)) + (sizeof(CogBytecodeFixup))) * 49152) > MaxStackAllocSize); if (allocBytes > MaxStackAllocSize) { return ((CogMethod *) MethodTooBig); goto l1; } abstractOpcodes = alloca(allocBytes); bzero(abstractOpcodes, allocBytes); fixups = ((void *)((((usqInt)abstractOpcodes)) + opcodeBytes)); zeroOpcodeIndexForNewOpcodes(); labelCounter = 0; l1: /* end allocateOpcodes:bytecodes:ifFail: */; if (((numBlocks = scanMethod())) < 0) { return ((CogMethod *) numBlocks); } numCleanBlocks = scanForCleanBlocks(); if (methodFoundInvalidPostScan()) { return ((CogMethod *) ShouldNotJIT); } allocateBlockStarts(numBlocks + numCleanBlocks); blockCount = 0; if (numCleanBlocks > 0) { addCleanBlockStarts(); } if (!(maybeAllocAndInitIRCs())) { /* Inaccurate error code, but it'll do. This will likely never fail. */ return ((CogMethod *) InsufficientCodeSpace); } blockEntryLabel = null; (methodLabel->dependent = null); if (((result = compileEntireMethod())) < 0) { return ((CogMethod *) result); } return generateCogMethod(selector); } /* Compile the abstract instructions for the entire method, including blocks. */ /* Compile the abstract instructions for the entire method, including blocks. */ /* StackToRegisterMappingCogit>>#compileEntireMethod */ static sqInt compileEntireMethod(void) { sqInt result; regArgsHaveBeenPushed = 0; /* begin preenMethodLabel */ (((((AbstractInstruction *) methodLabel))->operands))[1] = 0; compileAbort(); compileEntry(); if (((result = compilePrimitive())) < 0) { return result; } compileFrameBuild(); if (((result = compileMethodBody())) < 0) { return result; } if (blockCount == 0) { return 0; } if (((result = compileBlockBodies())) < 0) { return result; } return compileBlockDispatch(); } /* Build a frame for a CogMethod activation. See CoInterpreter class>>initializeFrameIndices. receiver (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp If there is a primitive and an error code the Nth temp is the error code. 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. */ /* StackToRegisterMappingCogit>>#compileFrameBuild */ static void compileFrameBuild(void) { sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt constant; sqInt i; sqInt iLimiT; AbstractInstruction *jumpSkip; # if IMMUTABILITY if (useTwoPaths) { compileTwoPathFrameBuild(); return; } # endif /* IMMUTABILITY */ if (!needsFrame) { if (useTwoPaths) { compileTwoPathFramelessInit(); } initSimStackForFramelessMethod(initialPC); return; } assert(!(useTwoPaths)); genPushRegisterArgs(); if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = (methodOrBlockNumArgs + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } if (((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))) { compileGetErrorCode(); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); if (canContextSwitchIfActivatingheader(methodObj, methodHeader)) { /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin Label */ stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { /* begin JumpAboveOrEqual: */ jumpSkip = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin Jump: */ genoperand(Jump, ((sqInt)stackOverflowCall)); jmpTarget(jumpSkip, (stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } /* begin annotateBytecode: */ (stackCheckLabel->annotation = HasBytecodePC); initSimStackForFramefulMethod(initialPC); } /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg. */ /* Make sure ReceiverResultReg holds the receiver, loaded from the closure, which is what is initially in ReceiverResultReg */ /* StackToRegisterMappingCogit>>#compileFullBlockFramelessEntry: */ static void NoDbgRegParms compileFullBlockFramelessEntry(sqInt numCopied) { initSimStackForFramelessBlock(initialPC); flag("TODO"); genLoadSlotsourceRegdestReg(FullClosureReceiverIndex, ReceiverResultReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, FullClosureReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); } /* Build a frame for a block activation. See CoInterpreter class>>initializeFrameIndices. closure (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp Avoid use of SendNumArgsReg which is the flag determining whether context switch is allowed on stack-overflow. */ /* StackToRegisterMappingCogit>>#compileFullBlockMethodFrameBuild: */ static void NoDbgRegParms compileFullBlockMethodFrameBuild(sqInt numCopied) { AbstractInstruction *abstractInstruction; sqInt address; AbstractInstruction *anInstruction; sqInt constant; sqInt i; sqInt iLimiT; if (useTwoPaths) { /* method with only inst var store, we compile only slow path for now */ useTwoPaths = 0; # if IMMUTABILITY needsFrame = 1; # endif /* IMMUTABILITY */ } if (!needsFrame) { assert(numCopied == 0); compileFullBlockFramelessEntry(numCopied); initSimStackForFramelessBlock(initialPC); return; } if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, ReceiverResultReg, ClassReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin setLabelOffset: */ (((((AbstractInstruction *) methodLabel))->operands))[1] = MFMethodFlagIsBlockFlag; /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); flag("TODO"); genLoadSlotsourceRegdestReg(FullClosureReceiverIndex, ClassReg, Arg0Reg); genEnsureOopInRegNotForwardedscratchRegupdatingSlotin(Arg0Reg, TempReg, FullClosureReceiverIndex, ReceiverResultReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, Arg0Reg, ReceiverResultReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = 0; i < numCopied; i += 1) { genLoadSlotsourceRegdestReg(i + FullClosureFirstCopiedValueIndex, ClassReg, TempReg); /* begin PushR: */ genoperand(PushR, TempReg); } for (i = ((methodOrBlockNumArgs + numCopied) + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin annotateBytecode: */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction->annotation = HasBytecodePC); stackCheckLabel = abstractInstruction; initSimStackForFramefulMethod(initialPC); } /* Build a frame for a CogMethod activation. See CoInterpreter class>>initializeFrameIndices. receiver (in ReceiverResultReg) arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (uninitialized?) receiver first temp ... sp-> Nth temp If there is a primitive and an error code the Nth temp is the error code. Ensure SendNumArgsReg is set early on (incidentally to nilObj) because it is the flag determining whether context switch is allowed on stack-overflow. */ /* We are in a method where the frame is needed *only* for instance variable store, typically a setter method. This case has 20% overhead with Immutability compared to setter without immutability because of the stack frame creation. We compile two path, one where the object is immutable, one where it isn't. At the beginning of the frame build, we take one path or the other depending on the receiver mutability. Note: this specific case happens only where there are only instance variabel stores. We could do something similar for literal variable stores, but we don't as it's too uncommon. */ /* StackToRegisterMappingCogit>>#compileTwoPathFrameBuild */ #if IMMUTABILITY static void compileTwoPathFrameBuild(void) { sqInt address; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt constant; sqInt i; sqInt iLimiT; AbstractInstruction * jumpImmutable; AbstractInstruction * jumpOld; AbstractInstruction *jumpSkip; sqInt quickConstant; assert(useTwoPaths); assert(blockCount == 0); jumpImmutable = genJumpImmutablescratchReg(ReceiverResultReg, TempReg); /* first path. The receiver is mutable */ /* N.B. FLAGS := destReg - scratchReg */ /* begin CmpCq:R: */ quickConstant = storeCheckBoundary(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); assert(!needsFrame); initSimStackForFramelessMethod(initialPC); /* begin compileMethodBody */ if (endPC < initialPC) { goto l8; } compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); l8: /* end compileMethodBody */; /* reset because it impacts inst var store compilation */ useTwoPaths = 0; needsFrame = 1; jmpTarget(jumpOld, jmpTarget(jumpImmutable, genoperandoperand(Label, (labelCounter += 1), bytecodePC))); genPushRegisterArgs(); if (!needsFrame) { return; } /* begin PushR: */ genoperand(PushR, LinkReg); /* begin PushR: */ genoperand(PushR, FPReg); /* begin MoveR:R: */ genoperandoperand(MoveRR, SPReg, FPReg); addDependent(methodLabel, annotateAbsolutePCRef(gPushCw(((sqInt)methodLabel)))); /* begin genMoveNilR: */ constant = nilObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, SendNumArgsReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, constant, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant)); } } /* begin PushR: */ genoperand(PushR, SendNumArgsReg); /* begin PushR: */ genoperand(PushR, ReceiverResultReg); for (i = (methodOrBlockNumArgs + 1), iLimiT = (temporaryCountOfMethodHeader(methodHeader)); i <= iLimiT; i += 1) { /* begin PushR: */ genoperand(PushR, SendNumArgsReg); } if (((primitiveIndexOfMethodheader(methodObj, methodHeader)) > 0) && ((longStoreBytecodeForHeader(methodHeader)) == (fetchByteofObject((startPCOfMethod(methodObj)) + (sizeOfCallPrimitiveBytecode(methodHeader)), methodObj)))) { compileGetErrorCode(); } /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); if (canContextSwitchIfActivatingheader(methodObj, methodHeader)) { /* begin JumpBelow: */ genConditionalBranchoperand(JumpBelow, ((sqInt)stackOverflowCall)); /* begin Label */ stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } else { /* begin JumpAboveOrEqual: */ jumpSkip = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, 0, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(0)); } /* begin Jump: */ genoperand(Jump, ((sqInt)stackOverflowCall)); jmpTarget(jumpSkip, (stackCheckLabel = genoperandoperand(Label, (labelCounter += 1), bytecodePC))); } /* begin annotateBytecode: */ (stackCheckLabel->annotation = HasBytecodePC); initSimStackForFramefulMethod(initialPC); } #endif /* IMMUTABILITY */ /* We are in a frameless method with at least two inst var stores. We compile two paths, one where the object is in new space, and one where it isn't. At the beginning of the method, we take one path or the other depending on the receiver being in newSpace. */ /* StackToRegisterMappingCogit>>#compileTwoPathFramelessInit */ static void compileTwoPathFramelessInit(void) { AbstractInstruction *anInstruction; AbstractInstruction * jumpOld; sqInt quickConstant; assert(!(IMMUTABILITY)); assert(!(needsFrame)); assert(useTwoPaths); /* first path. The receiver is young */ /* N.B. FLAGS := destReg - scratchReg */ /* begin CmpCq:R: */ quickConstant = storeCheckBoundary(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, quickConstant, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } /* begin JumpAboveOrEqual: */ jumpOld = genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)0)); initSimStackForFramelessMethod(initialPC); /* begin compileMethodBody */ if (endPC < initialPC) { goto l1; } compileAbstractInstructionsFromthrough(initialPC + (deltaToSkipPrimAndErrorStoreInheader(methodObj, methodHeader)), endPC); l1: /* end compileMethodBody */; /* reset because it impacts inst var store compilation */ useTwoPaths = 0; jmpTarget(jumpOld, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } /* StackToRegisterMappingCogit>>#cPICMissTrampolineFor: */ static sqInt NoDbgRegParms cPICMissTrampolineFor(sqInt numArgs) { return picMissTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* Replaces the Blue Book double-extended send [132], in which the first byte was wasted on 8 bits of argument count. Here we use 3 bits for the operation sub-type (opType), and the remaining 5 bits for argument count where needed. The last byte give access to 256 instVars or literals. See also secondExtendedSendBytecode */ /* StackToRegisterMappingCogit>>#doubleExtendedDoAnythingBytecode */ static sqInt doubleExtendedDoAnythingBytecode(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; sqInt opType; opType = ((usqInt) byte1) >> 5; if (opType == 0) { return genSendnumArgs(byte2, byte1 & 0x1F); } if (opType == 1) { return genSendSupernumArgs(byte2, byte1 & 0x1F); } switch (opType) { case 2: if (isReadMediatedContextInstVarIndex(byte2)) { genPushMaybeContextReceiverVariable(byte2); } else { genPushReceiverVariable(byte2); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); return 0; } break; case 3: genPushLiteralIndex(byte2); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction1 = gen(Nop); } else { /* begin Label */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction1->annotation = HasBytecodePC); return 0; case 4: genPushLiteralVariable(byte2); break; case 7: genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(0, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); # if IMMUTABILITY /* genStorePop:LiteralVariable: annotates; don't annotate twice */ return 0; # endif /* IMMUTABILITY */ break; default: /* 5 & 6 */ if (isWriteMediatedContextInstVarIndex(byte2)) { genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(opType == 6, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } else { genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(opType == 6, byte2, ((((ssTop())->type)) != SSConstant) || ((isNonImmediate(((ssTop())->constant))) && (shouldAnnotateObjectReference(((ssTop())->constant)))), 1); } # if IMMUTABILITY /* genStorePop:...ReceiverVariable: annotate; don't annotate twice */ return 0; # endif /* IMMUTABILITY */ ; } assert(needsFrame); assert(!(prevInstIsPCAnnotated())); /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); return 0; } /* StackToRegisterMappingCogit>>#duplicateTopBytecode */ static sqInt duplicateTopBytecode(void) { SimStackEntry desc; /* begin ssTopDescriptor */ desc = simStack[simStackPtr]; return ssPushDesc(desc); } /* Make sure there's a flagged fixup at the target pc in fixups. Initially a fixup's target is just a flag. Later on it is replaced with a proper instruction. */ /* StackToRegisterMappingCogit>>#ensureFixupAt: */ static BytecodeFixup * NoDbgRegParms ensureFixupAt(sqInt targetPC) { BytecodeFixup *fixup; /* begin fixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); traceFixupmerge(fixup, 1); if ((((usqInt)((fixup->targetInstruction)))) <= NeedsNonMergeFixupFlag) { /* convert a non-merge into a merge */ /* begin becomeMergeFixup */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); (fixup->simStackPtr = simStackPtr); } else { if ((fixup->isTargetOfBackwardBranch)) { /* this is the target of a backward branch and so doesn't have a simStackPtr assigned yet. */ (fixup->simStackPtr = simStackPtr); } else { assert(((fixup->simStackPtr)) == simStackPtr); } } /* begin recordBcpc: */ return fixup; } /* Make sure there's a flagged fixup at the target pc in fixups. Initially a fixup's target is just a flag. Later on it is replaced with a proper instruction. */ /* StackToRegisterMappingCogit>>#ensureNonMergeFixupAt: */ static BytecodeFixup * NoDbgRegParms ensureNonMergeFixupAt(sqInt targetPC) { BytecodeFixup *fixup; /* begin fixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); traceFixupmerge(fixup, 1); if (((fixup->targetInstruction)) == 0) { /* begin becomeNonMergeFixup */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsNonMergeFixupFlag); } /* begin recordBcpc: */ return fixup; } /* StackToRegisterMappingCogit>>#ensureReceiverResultRegContainsSelf */ static void ensureReceiverResultRegContainsSelf(void) { if (needsFrame) { if (!((((simSelf())->liveRegister)) == ReceiverResultReg)) { /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); ((simSelf())->liveRegister = ReceiverResultReg); } } else { assert(((((simSelf())->type)) == SSRegister) && (((((simSelf())->registerr)) == ReceiverResultReg) && (receiverIsInReceiverResultReg()))); } } /* StackToRegisterMappingCogit>>#evaluate:at: */ static void NoDbgRegParms evaluateat(BytecodeDescriptor *descriptor, sqInt pc) { byte0 = fetchByteofObject(pc, methodObj); assert(descriptor == (generatorAt(bytecodeSetOffset + byte0))); loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } /* Attempt to follow a branch to a pc. Handle branches to unconditional jumps and branches to push: aBoolean; conditional branch pairs. If the branch cannot be followed answer targetBytecodePC. It is not possible to follow jumps to conditional branches because the stack changes depth. That following is left to the genJumpIf:to: clients. */ /* StackToRegisterMappingCogit>>#eventualTargetOf: */ static sqInt NoDbgRegParms eventualTargetOf(sqInt targetBytecodePC) { sqInt cond; sqInt currentTarget; BytecodeDescriptor *descriptor; sqInt nExts; sqInt nextPC; sqInt span; cond = 0; nextPC = (currentTarget = targetBytecodePC); while(1) { nExts = 0; while (1) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC, methodObj))); if ((descriptor->isReturn)) { return currentTarget; } if (!((descriptor->isExtension))) break; nExts += 1; nextPC += (descriptor->numBytes); } if ((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) { /* begin spanFor:at:exts:in: */ span = ((descriptor->spanFunction))(descriptor, nextPC, nExts, methodObj); if (span < 0) { /* Do *not* follow backward branches; these are interrupt points and should not be elided. */ return currentTarget; } nextPC = (nextPC + ((descriptor->numBytes))) + span; } else { if (((descriptor->generator)) == genPushConstantTrueBytecode) { cond = 1; } else { if (((descriptor->generator)) == genPushConstantFalseBytecode) { cond = 0; } else { return currentTarget; } } if (((fixupAt(nextPC))->isTargetOfBackwardBranch)) { return currentTarget; } nextPC = eventualTargetOf(nextPC + ((descriptor->numBytes))); nExts = 0; while (1) { /* begin generatorForPC: */ descriptor = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC, methodObj))); if ((descriptor->isReturn)) { return currentTarget; } if (!((descriptor->isExtension))) break; nExts += 1; nextPC += (descriptor->numBytes); } if (!(isBranch(descriptor))) { return currentTarget; } if ((isBranch(descriptor)) && (!(((descriptor->isBranchTrue)) || ((descriptor->isBranchFalse))))) { return currentTarget; } nextPC = (cond == ((descriptor->isBranchTrue)) ? (nextPC + ((descriptor->numBytes))) + (((descriptor->spanFunction))(descriptor, nextPC, nExts, methodObj)) : nextPC + ((descriptor->numBytes))); } currentTarget = nextPC; } return 0; } /* Spill the closest register on stack not conflicting with regMask. Assertion Failure if regMask has already all the registers */ /* StackToRegisterMappingCogit>>#freeAnyRegNotConflictingWith: */ static sqInt NoDbgRegParms freeAnyRegNotConflictingWith(sqInt regMask) { CogSimStackEntry *desc; sqInt index; sqInt reg; assert(needsFrame); reg = NoReg; index = ((simSpillBase < 0) ? 0 : simSpillBase); while ((reg == NoReg) && (index < simStackPtr)) { desc = simStackAt(index); if (((desc->type)) == SSRegister) { if (!(regMask & (1U << ((desc->registerr))))) { reg = (desc->registerr); } } index += 1; } assert(!((reg == NoReg))); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << reg, simStackPtr, simNativeStackPtr); return reg; } /* Return from block, assuming result already loaded into ReceiverResultReg. */ /* Return from block, assuming result already loaded into ReceiverResultReg. */ /* StackToRegisterMappingCogit>>#genBlockReturn */ static sqInt genBlockReturn(void) { if (needsFrame) { /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, SPReg); /* begin PopR: */ genoperand(PopR, FPReg); /* begin PopR: */ genoperand(PopR, LinkReg); } /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); /* can't fall through */ deadCode = 1; return 0; } /* Generate special versions of the ceCallCogCodePopReceiverAndClassRegs enilopmart that also pop register args from the stack to undo the pushing of register args in the abort/miss trampolines. */ /* StackToRegisterMappingCogit>>#genCallPICEnilopmartNumArgs: */ static void (*genCallPICEnilopmartNumArgs(sqInt numArgs))(void) { AbstractInstruction *anInstruction; sqInt endAddress; sqInt enilopmart; sqInt quickConstant; sqInt reg; sqInt size; zeroOpcodeIndex(); /* begin MoveCq:R: */ quickConstant = varBaseAddress(); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, quickConstant, VarBaseReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(quickConstant)); } genLoadStackPointers(backEnd); /* begin PopR: */ genoperand(PopR, ClassReg); /* begin PopR: */ genoperand(PopR, TempReg); /* begin PopR: */ reg = LinkReg; genoperand(PopR, reg); if (numArgs > 0) { if (numArgs > 1) { /* begin PopR: */ genoperand(PopR, Arg1Reg); assert((numRegArgs()) == 2); } /* begin PopR: */ genoperand(PopR, Arg0Reg); } /* begin PopR: */ genoperand(PopR, ReceiverResultReg); /* begin JumpR: */ genoperand(JumpR, TempReg); computeMaximumSizes(); size = generateInstructionsAt(methodZoneBase); endAddress = outputInstructionsAt(methodZoneBase); assert((methodZoneBase + size) == endAddress); enilopmart = methodZoneBase; methodZoneBase = alignUptoRoutineBoundary(endAddress); stopsFromto(backEnd, endAddress, methodZoneBase - 1); recordGeneratedRunTimeaddress(trampolineNamenumRegArgs("ceCallPIC", numArgs), enilopmart); return ((void (*)(void)) enilopmart); } /* SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution. See EncoderForSistaV1's class comment and StackInterpreter>>#inlinePrimitiveBytecode: */ /* StackToRegisterMappingCogit>>#genCallPrimitiveBytecode */ static sqInt genCallPrimitiveBytecode(void) { sqInt prim; sqInt primSet; if (byte2 < 128) { return (bytecodePC == initialPC ? 0 : EncounteredUnknownBytecode); } prim = (((sqInt)((usqInt)((byte2 - 128)) << 8))) + byte1; primSet = (((usqInt) prim) >> 13) & 3; prim = prim & 0x1FFF; return EncounteredUnknownBytecode; } /* Override to push the register receiver and register arguments, if any. */ /* StackToRegisterMappingCogit>>#genExternalizePointersForPrimitiveCall */ static sqInt genExternalizePointersForPrimitiveCall(void) { sqInt address; sqInt address1; sqInt address4; genPushRegisterArgs(); /* begin MoveR:Aw: */ address4 = framePointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address4, genoperandoperand(MoveRAw, FPReg, address4)); /* Set coInterpreter stackPointer to the topmost argument, skipping the return address. */ /* begin MoveR:Aw: */ address = stackPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address, genoperandoperand(MoveRAw, SPReg, address)); /* begin MoveR:Aw: */ address1 = instructionPointerAddress(); /* begin gen:operand:literal: */ checkLiteralforInstruction(address1, genoperandoperand(MoveRAw, LinkReg, address1)); return 0; } /* Block compilation. At this point in the method create the block. Note its start and defer generating code for it until after the method and any other preceding blocks. The block's actual code will be compiled later. */ /* 253 11111101 eei i i kkk jjjjjjjj Push Closure Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8) BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions */ /* StackToRegisterMappingCogit>>#genExtPushClosureBytecode */ static sqInt genExtPushClosureBytecode(void) { sqInt i; sqInt numArgs; sqInt numCopied; sqInt reg; sqInt startpc; assert(needsFrame); startpc = bytecodePC + (((generatorAt(byte0))->numBytes)); addBlockStartAtnumArgsnumCopiedspan(startpc, (numArgs = (byte1 & 7) + ((extA % 16) * 8)), (numCopied = ((((usqInt) byte1) >> 3) & 7) + ((extA / 16) * 8)), byte2 + (((sqInt)((usqInt)(extB) << 8)))); extA = (numExtB = (extB = 0)); /* begin genInlineClosure:numArgs:numCopied: */ assert(getActiveContextAllocatesInMachineCode()); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(startpc + 1, numArgs, numCopied, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (ClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } ssPushRegister(ReceiverResultReg); return 0; } /* Full Block creation compilation. The block's actual code will be compiled separatedly. */ /* * 255 11111111 xxxxxxxx siyyyyyy push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1 */ /* StackToRegisterMappingCogit>>#genExtPushFullClosureBytecode */ static sqInt genExtPushFullClosureBytecode(void) { sqInt compiledBlock; sqInt i; int ignoreContext; sqInt numCopied; int receiverIsOnStack; sqInt reg; assert(needsFrame); compiledBlock = getLiteral(byte1 + (((sqInt)((usqInt)(extA) << 8)))); extA = 0; numCopied = byte2 & ((1U << 6) - 1); receiverIsOnStack = byte2 & (1U << 7); ignoreContext = byte2 & (1U << 6); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genCreateFullClosurenumArgsnumCopiedignoreContextcontextNumArgslargeinBlock(compiledBlock, argumentCountOf(compiledBlock), numCopied, ignoreContext, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (FullClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } if (receiverIsOnStack) { reg = ssStorePoptoPreferredReg(1, TempReg); } else { storeToReg(simSelf(), (reg = TempReg)); } genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, FullClosureReceiverIndex, ReceiverResultReg); ssPushRegister(ReceiverResultReg); return 0; } /* 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. */ /* StackToRegisterMappingCogit>>#generateEnilopmarts */ static void generateEnilopmarts(void) { # if Debug /* begin genEnilopmartFor:forCall:called: */ realCEEnterCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 0, "realCEEnterCogCodePopReceiverReg"); ceEnterCogCodePopReceiverReg = enterCogCodePopReceiver; /* begin genEnilopmartFor:forCall:called: */ realCECallCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 1, "realCEEnterCogCodePopReceiverReg"); ceCallCogCodePopReceiverReg = callCogCodePopReceiver; /* begin genEnilopmartFor:and:forCall:called: */ realCECallCogCodePopReceiverAndClassRegs = genEnilopmartForandandforCallcalled(ReceiverResultReg, ClassReg, NoReg, 1, "realCECallCogCodePopReceiverAndClassRegs"); ceCallCogCodePopReceiverAndClassRegs = callCogCodePopReceiverAndClassRegs; # else /* Debug */ /* begin genEnilopmartFor:forCall:called: */ ceEnterCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 0, "ceEnterCogCodePopReceiverReg"); /* begin genEnilopmartFor:forCall:called: */ ceCallCogCodePopReceiverReg = genEnilopmartForandandforCallcalled(ReceiverResultReg, NoReg, NoReg, 1, "ceCallCogCodePopReceiverReg"); /* begin genEnilopmartFor:and:forCall:called: */ ceCallCogCodePopReceiverAndClassRegs = genEnilopmartForandandforCallcalled(ReceiverResultReg, ClassReg, NoReg, 1, "ceCallCogCodePopReceiverAndClassRegs"); # endif /* Debug */ genPrimReturnEnterCogCodeEnilopmart(0); cePrimReturnEnterCogCode = methodZoneBase; outputInstructionsForGeneratedRuntimeAt(cePrimReturnEnterCogCode); recordGeneratedRunTimeaddress("cePrimReturnEnterCogCode", cePrimReturnEnterCogCode); genPrimReturnEnterCogCodeEnilopmart(1); cePrimReturnEnterCogCodeProfiling = methodZoneBase; outputInstructionsForGeneratedRuntimeAt(cePrimReturnEnterCogCodeProfiling); recordGeneratedRunTimeaddress("cePrimReturnEnterCogCodeProfiling", cePrimReturnEnterCogCodeProfiling); # if Debug /* begin genEnilopmartFor:and:forCall:called: */ realCECallCogCodePopReceiverArg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, NoReg, 1, "realCECallCogCodePopReceiverArg0Regs"); ceCallCogCodePopReceiverArg0Regs = callCogCodePopReceiverArg0Regs; realCECallCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, 1, "realCECallCogCodePopReceiverArg1Arg0Regs"); ceCallCogCodePopReceiverArg1Arg0Regs = callCogCodePopReceiverArg1Arg0Regs; # else /* Debug */ /* begin genEnilopmartFor:and:forCall:called: */ ceCallCogCodePopReceiverArg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, NoReg, 1, "ceCallCogCodePopReceiverArg0Regs"); ceCallCogCodePopReceiverArg1Arg0Regs = genEnilopmartForandandforCallcalled(ReceiverResultReg, Arg0Reg, Arg1Reg, 1, "ceCallCogCodePopReceiverArg1Arg0Regs"); # endif /* Debug */ ceCall0ArgsPIC = genCallPICEnilopmartNumArgs(0); ceCall1ArgsPIC = genCallPICEnilopmartNumArgs(1); ceCall2ArgsPIC = genCallPICEnilopmartNumArgs(2); assert((numRegArgs()) == 2); } /* Size pc-dependent instructions and assign eventual addresses to all instructions. Answer the size of the code. Compute forward branches based on virtual address (abstract code starts at 0), assuming that any branches branched over are long. Compute backward branches based on actual address. Reuse the fixups array to record the pc-dependent instructions that need to have their code generation postponed until after the others. Override to andd handling for null branches (branches to the immediately following instruction) occasioned by StackToRegisterMapping's following of jumps. */ /* StackToRegisterMappingCogit>>#generateInstructionsAt: */ static sqInt NoDbgRegParms generateInstructionsAt(sqInt eventualAbsoluteAddress) { sqInt absoluteAddress; AbstractInstruction *abstractInstruction; BytecodeFixup *fixup; sqInt i; sqInt j; sqInt pcDependentIndex; absoluteAddress = eventualAbsoluteAddress; pcDependentIndex = 0; for (i = 0; i < opcodeIndex; i += 1) { maybeBreakGeneratingAt(absoluteAddress); abstractInstruction = abstractInstructionAt(i); if (isPCDependent(abstractInstruction)) { sizePCDependentInstructionAt(abstractInstruction, absoluteAddress); if ((isJump(abstractInstruction)) && ((((i + 1) < opcodeIndex) && ((((AbstractInstruction *) (((abstractInstruction->operands))[0]))) == (abstractInstructionAt(i + 1)))) || (((i + 2) < opcodeIndex) && (((((AbstractInstruction *) (((abstractInstruction->operands))[0]))) == (abstractInstructionAt(i + 2))) && ((((abstractInstructionAt(i + 1))->opcode)) == Nop))))) { (abstractInstruction->opcode = Nop); concretizeAt(abstractInstruction, absoluteAddress); } else { fixup = fixupAtIndex(pcDependentIndex); pcDependentIndex += 1; (fixup->instructionIndex = i); } absoluteAddress += (abstractInstruction->machineCodeSize); } else { absoluteAddress = concretizeAt(abstractInstruction, absoluteAddress); } } for (j = 0; j < pcDependentIndex; j += 1) { fixup = fixupAtIndex(j); abstractInstruction = abstractInstructionAt((fixup->instructionIndex)); maybeBreakGeneratingAt((abstractInstruction->address)); concretizeAt(abstractInstruction, (abstractInstruction->address)); } return absoluteAddress - eventualAbsoluteAddress; } /* Generate the run-time entries for the various method and PIC entry misses and aborts. Read the class-side method trampolines for documentation on the various trampolines */ /* StackToRegisterMappingCogit>>#generateMissAbortTrampolines */ static void generateMissAbortTrampolines(void) { sqInt numArgs; sqInt numArgsLimiT; for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { methodAbortTrampolines[numArgs] = (genMethodAbortTrampolineFor(numArgs)); } for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { picAbortTrampolines[numArgs] = (genPICAbortTrampolineFor(numArgs)); } for (numArgs = 0, numArgsLimiT = (2 /* numRegArgs */ + 1); numArgs <= numArgsLimiT; numArgs += 1) { picMissTrampolines[numArgs] = (genPICMissTrampolineFor(numArgs)); } ceReapAndResetErrorCodeTrampoline = genTrampolineForcalledarg(ceReapAndResetErrorCodeFor, "ceReapAndResetErrorCodeTrampoline", ClassReg); } /* Override to generate code to push the register arg(s) for <= numRegArg arity sends. */ /* StackToRegisterMappingCogit>>#generateSendTrampolines */ static void generateSendTrampolines(void) { sqInt numArgs; for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { ordinarySendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSend", numArgs), ClassReg, trampolineArgConstant(0), ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { directedSuperSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendabovetonumArgs, numArgs, trampolineNamenumArgs("ceDirectedSuperSend", numArgs), ClassReg, TempReg, ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); directedSuperBindingSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendaboveClassBindingtonumArgs, numArgs, trampolineNamenumArgs("ceDirectedSuperBindingSend", numArgs), ClassReg, TempReg, ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } for (numArgs = 0; numArgs < NumSendTrampolines; numArgs += 1) { superSendTrampolines[numArgs] = (genSendTrampolineFornumArgscalledargargargarg(ceSendsupertonumArgs, numArgs, trampolineNamenumArgs("ceSuperSend", numArgs), ClassReg, trampolineArgConstant(1), ReceiverResultReg, (numArgs <= (NumSendTrampolines - 2) ? (/* begin trampolineArgConstant: */ assert(numArgs >= 0), -2 - numArgs) : SendNumArgsReg))); } firstSend = ordinarySendTrampolines[0]; lastSend = superSendTrampolines[NumSendTrampolines - 1]; } /* Generate trampolines for tracing. In the simulator we can save a lot of time and avoid noise instructions in the lastNInstructions log by short-cutting these trampolines, but we need them in the real vm. */ /* StackToRegisterMappingCogit>>#generateTracingTrampolines */ static void generateTracingTrampolines(void) { ceTraceLinkedSendTrampoline = genTrampolineForcalledargregsToSave(ceTraceLinkedSend, "ceTraceLinkedSendTrampoline", ReceiverResultReg, CallerSavedRegisterMask); ceTraceBlockActivationTrampoline = genTrampolineForcalledregsToSave(ceTraceBlockActivation, "ceTraceBlockActivationTrampoline", CallerSavedRegisterMask); ceTraceStoreTrampoline = genTrampolineForcalledargargregsToSave(ceTraceStoreOfinto, "ceTraceStoreTrampoline", TempReg, ReceiverResultReg, CallerSavedRegisterMask); } /* StackToRegisterMappingCogit>>#genForwardersInlinedIdenticalOrNotIf: */ static sqInt NoDbgRegParms genForwardersInlinedIdenticalOrNotIf(sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; sqInt argReg; sqInt argReg1; BytecodeDescriptor *branchDescriptor; BytecodeDescriptor *branchDescriptor1; sqInt constant; sqInt constant1; BytecodeFixup * fixup; sqInt i; void *jumpTarget; void *jumpTarget1; AbstractInstruction *label; sqInt nExts; sqInt nextPC; sqInt nextPC1; sqInt postBranchPC; sqInt postBranchPC1; BytecodeDescriptor *primDescriptor; sqInt rcvrReg; sqInt rcvrReg1; sqInt reg; sqInt rNext1; sqInt rTop1; sqInt targetBytecodePC; sqInt targetBytecodePC1; sqInt topRegistersMask; int unforwardArg; int unforwardRcvr; /* begin extractMaybeBranchDescriptorInto: */ primDescriptor = generatorAt(byte0); nextPC1 = bytecodePC + ((primDescriptor->numBytes)); nExts = 0; while (1) { while (1) { /* begin generatorForPC: */ branchDescriptor1 = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC1, methodObj))); if (!((branchDescriptor1->isExtension))) break; nExts += 1; nextPC1 += (branchDescriptor1->numBytes); } /* begin isUnconditionalBranch */ if (!((isBranch(branchDescriptor1)) && (!(((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse)))))) break; nextPC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); } targetBytecodePC1 = (postBranchPC1 = 0); if (((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse))) { targetBytecodePC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); postBranchPC1 = eventualTargetOf(nextPC1 + ((branchDescriptor1->numBytes))); } else { nextPC1 = bytecodePC + ((primDescriptor->numBytes)); } branchDescriptor = branchDescriptor1; nextPC = nextPC1; postBranchPC = postBranchPC1; targetBytecodePC = targetBytecodePC1; unforwardRcvr = !(isUnannotatableConstant(ssValue(1))); unforwardArg = !(isUnannotatableConstant(ssTop())); /* begin allocateEqualsEqualsRegistersArgNeedsReg:rcvrNeedsReg:into: */ assert(unforwardArg || (unforwardRcvr)); argReg1 = (rcvrReg1 = NoReg); if (unforwardArg) { if (unforwardRcvr) { /* begin allocateRegForStackTopTwoEntriesInto: */ topRegistersMask = 0; rTop1 = (rNext1 = NoReg); if ((registerOrNone(ssTop())) != NoReg) { rTop1 = registerOrNone(ssTop()); } if ((registerOrNone(ssValue(1))) != NoReg) { /* begin registerMaskFor: */ reg = (rNext1 = registerOrNone(ssValue(1))); topRegistersMask = 1U << reg; } if (rTop1 == NoReg) { rTop1 = allocateRegNotConflictingWith(topRegistersMask); } if (rNext1 == NoReg) { rNext1 = allocateRegNotConflictingWith(1U << rTop1); } assert(!(((rTop1 == NoReg) || (rNext1 == NoReg)))); argReg1 = rTop1; rcvrReg1 = rNext1; popToReg(ssTop(), argReg1); popToReg(ssValue(1), rcvrReg1); } else { argReg1 = allocateRegForStackEntryAtnotConflictingWith(0, 0); popToReg(ssTop(), argReg1); if (((ssValue(1))->spilled)) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(BytesPerWord)); } } } } else { assert(unforwardRcvr); assert(!((((ssTop())->spilled)))); rcvrReg1 = allocateRegForStackEntryAtnotConflictingWith(1, 0); popToReg(ssValue(1), rcvrReg1); } assert(!((unforwardArg && (argReg1 == NoReg)))); assert(!((unforwardRcvr && (rcvrReg1 == NoReg)))); rcvrReg = rcvrReg1; argReg = argReg1; if (!(((branchDescriptor->isBranchTrue)) || ((branchDescriptor->isBranchFalse)))) { return genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(!unforwardArg, !unforwardRcvr, argReg, rcvrReg, orNot); } /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } /* begin Label */ label = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin genCmpArgIsConstant:rcvrIsConstant:argReg:rcvrReg: */ assert((argReg != NoReg) || (rcvrReg != NoReg)); if (!unforwardArg) { /* begin genCmpConstant:R: */ constant = ((ssTop())->constant); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(checkLiteralforInstruction(constant, genoperandoperand(CmpCwR, constant, rcvrReg)), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, constant, rcvrReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant)); } } } else { if (!unforwardRcvr) { /* begin genCmpConstant:R: */ constant1 = ((ssValue(1))->constant); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(checkLiteralforInstruction(constant1, genoperandoperand(CmpCwR, constant1, argReg)), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, constant1, argReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant1)); } } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, argReg, rcvrReg); } } ssPop(2); if ((((fixupAt(nextPC))->targetInstruction)) == 0) { /* The next instruction is dead. we can skip it. */ deadCode = 1; ensureFixupAt(targetBytecodePC); ensureFixupAt(postBranchPC); } else { assert(!(deadCode)); } assert(unforwardArg || (unforwardRcvr)); if (orNot == ((branchDescriptor->isBranchTrue))) { /* a == b ifFalse: ... or a ~~ b ifTrue: ... jump on equal to post-branch pc */ fixup = ensureNonMergeFixupAt(targetBytecodePC); /* begin JumpZero: */ jumpTarget = ensureNonMergeFixupAt(postBranchPC); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget)); } else { /* orNot is true for ~~ */ /* a == b ifTrue: ... or a ~~ b ifFalse: ... jump on equal to target pc */ fixup = ensureNonMergeFixupAt(postBranchPC); /* begin JumpZero: */ jumpTarget1 = ensureNonMergeFixupAt(targetBytecodePC); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget1)); } if (unforwardArg && (unforwardRcvr)) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(argReg, TempReg, label, 0); } genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder((unforwardRcvr ? rcvrReg : argReg), TempReg, label, fixup); if (!deadCode) { ssPushConstant(trueObject()); } return 0; } /* Generates the machine code for #== in the case where the instruction is not followed by a branch */ /* StackToRegisterMappingCogit>>#genIdenticalNoBranchArgIsConstant:rcvrIsConstant:argReg:rcvrReg:orNotIf: */ static sqInt NoDbgRegParms genIdenticalNoBranchArgIsConstantrcvrIsConstantargRegrcvrRegorNotIf(sqInt argIsConstant, sqInt rcvrIsConstant, sqInt argReg, sqInt rcvrRegOrNone, sqInt orNot) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; sqInt constant; sqInt constant1; sqInt constant11; sqInt constant2; sqInt constant3; sqInt constant4; AbstractInstruction *jumpEqual; AbstractInstruction *jumpNotEqual; AbstractInstruction *label; sqInt resultReg; /* begin Label */ label = genoperandoperand(Label, (labelCounter += 1), bytecodePC); /* begin genCmpArgIsConstant:rcvrIsConstant:argReg:rcvrReg: */ assert((argReg != NoReg) || (rcvrRegOrNone != NoReg)); if (argIsConstant) { /* begin genCmpConstant:R: */ constant4 = ((ssTop())->constant); if (shouldAnnotateObjectReference(constant4)) { annotateobjRef(checkLiteralforInstruction(constant4, genoperandoperand(CmpCwR, constant4, rcvrRegOrNone)), constant4); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, constant4, rcvrRegOrNone); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(constant4)); } } } else { if (rcvrIsConstant) { /* begin genCmpConstant:R: */ constant11 = ((ssValue(1))->constant); if (shouldAnnotateObjectReference(constant11)) { annotateobjRef(checkLiteralforInstruction(constant11, genoperandoperand(CmpCwR, constant11, argReg)), constant11); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, constant11, argReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(constant11)); } } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, argReg, rcvrRegOrNone); } } ssPop(2); resultReg = (rcvrRegOrNone == NoReg ? argReg : rcvrRegOrNone); /* begin JumpZero: */ jumpEqual = genConditionalBranchoperand(JumpZero, ((sqInt)0)); if (!argIsConstant) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(argReg, TempReg, label, 0); } if (!rcvrIsConstant) { /* begin genEnsureOopInRegNotForwarded:scratchReg:jumpBackTo: */ genEnsureOopInRegNotForwardedscratchRegifForwarderifNotForwarder(rcvrRegOrNone, TempReg, label, 0); } if (orNot) { /* begin genMoveTrueR: */ constant = trueObject(); if (shouldAnnotateObjectReference(constant)) { annotateobjRef(gMoveCwR(constant, resultReg), constant); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, constant, resultReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(constant)); } } } else { /* begin genMoveFalseR: */ constant1 = falseObject(); if (shouldAnnotateObjectReference(constant1)) { annotateobjRef(gMoveCwR(constant1, resultReg), constant1); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(MoveCqR, constant1, resultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(constant1)); } } } /* begin Jump: */ jumpNotEqual = genoperand(Jump, ((sqInt)0)); jmpTarget(jumpEqual, (orNot ? (/* begin genMoveFalseR: */ (constant2 = falseObject()), (shouldAnnotateObjectReference(constant2) ? annotateobjRef(gMoveCwR(constant2, resultReg), constant2) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction4 = genoperandoperand(MoveCqR, constant2, resultReg)), (usesOutOfLineLiteral(anInstruction4) ? (anInstruction4->dependent = locateLiteral(constant2)) : 0), anInstruction4))) : (/* begin genMoveTrueR: */ (constant3 = trueObject()), (shouldAnnotateObjectReference(constant3) ? annotateobjRef(gMoveCwR(constant3, resultReg), constant3) : (/* begin checkQuickConstant:forInstruction: */ (anInstruction5 = genoperandoperand(MoveCqR, constant3, resultReg)), (usesOutOfLineLiteral(anInstruction5) ? (anInstruction5->dependent = locateLiteral(constant3)) : 0), anInstruction5))))); jmpTarget(jumpNotEqual, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); ssPushRegister(resultReg); return 0; } /* Decompose code generation for #== into a common constant-folding version, followed by a double dispatch throguh the objectRepresentation to a version that doesn't deal with forwarders and a version that does. */ /* StackToRegisterMappingCogit>>#genInlinedIdenticalOrNotIf: */ static sqInt NoDbgRegParms genInlinedIdenticalOrNotIf(sqInt orNot) { BytecodeDescriptor *primDescriptor; sqInt result; primDescriptor = generatorAt(byte0); if ((isUnannotatableConstant(ssTop())) && (isUnannotatableConstant(ssValue(1)))) { assert(!((primDescriptor->isMapped))); result = ((orNot ? (((ssTop())->constant)) != (((ssValue(1))->constant)) : (((ssTop())->constant)) == (((ssValue(1))->constant))) ? trueObject() : falseObject()); ssPop(2); return ssPushConstant(result); } /* begin genInlinedIdenticalOrNotIfGuts: */ return genForwardersInlinedIdenticalOrNotIf(orNot); } /* StackToRegisterMappingCogit>>#genJumpBackTo: */ static sqInt NoDbgRegParms genJumpBackTo(sqInt targetBytecodePC) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; sqInt address; sqInt i; void *jumpTarget; void *jumpTarget1; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* can't fall through */ deadCode = 1; /* begin MoveAw:R: */ address = stackLimitAddress(); /* begin gen:literal:operand: */ checkLiteralforInstruction(address, genoperandoperand(MoveAwR, address, TempReg)); /* begin CmpR:R: */ genoperandoperand(CmpRR, TempReg, SPReg); /* begin JumpAboveOrEqual: */ jumpTarget = fixupAtIndex(targetBytecodePC - initialPC); genConditionalBranchoperand(JumpAboveOrEqual, ((sqInt)jumpTarget)); /* begin CallRT: */ abstractInstruction = genoperand(Call, ceCheckForInterruptTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin annotateBytecode: */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction1->annotation = HasBytecodePC); /* begin Jump: */ jumpTarget1 = fixupAtIndex(targetBytecodePC - initialPC); genoperand(Jump, ((sqInt)jumpTarget1)); return 0; } /* StackToRegisterMappingCogit>>#genJumpIf:to: */ static sqInt NoDbgRegParms genJumpIfto(sqInt boolean, sqInt targetBytecodePC) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; CogSimStackEntry *desc; sqInt eventualTarget; BytecodeFixup *fixup; sqInt i; void *jumpTarget; AbstractInstruction *ok; sqInt quickConstant; eventualTarget = eventualTargetOf(targetBytecodePC); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 1)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 1)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 1))); i < simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 1) + 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 annotate the bytecode for correct pc mapping. */ fixup = ensureFixupAt(eventualTarget); /* begin annotateBytecode: */ if (((desc->constant)) == boolean) { /* begin Jump: */ abstractInstruction = genoperand(Jump, ((sqInt)fixup)); } else { if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } } (abstractInstruction->annotation = HasBytecodePC); extA = 0; return 0; } popToReg(desc, TempReg); assert((objectAfter(falseObject())) == (trueObject())); /* begin genSubConstant:R: */ if (shouldAnnotateObjectReference(boolean)) { annotateobjRef(gSubCwR(boolean, TempReg), TempReg); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, boolean, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(boolean)); } } /* begin JumpZero: */ jumpTarget = ensureFixupAt(eventualTarget); genConditionalBranchoperand(JumpZero, ((sqInt)jumpTarget)); if (extA & 1) { extA = 0; /* begin annotateBytecode: */ abstractInstruction1 = lastOpcode(); (abstractInstruction1->annotation = HasBytecodePC); return 0; } extA = 0; /* begin CmpCq:R: */ quickConstant = (boolean == (falseObject()) ? (trueObject()) - (falseObject()) : (falseObject()) - (trueObject())); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpZero: */ ok = genConditionalBranchoperand(JumpZero, ((sqInt)0)); genCallMustBeBooleanFor(boolean); jmpTarget(ok, annotateBytecode(genoperandoperand(Label, (labelCounter += 1), bytecodePC))); return 0; } /* StackToRegisterMappingCogit>>#genJumpTo: */ static sqInt NoDbgRegParms genJumpTo(sqInt targetBytecodePC) { sqInt eventualTarget; BytecodeFixup * fixup; BytecodeDescriptor * generator; sqInt i; sqInt i1; eventualTarget = eventualTargetOf(targetBytecodePC); if ((eventualTarget > bytecodePC) && (((simStackPtr >= methodOrBlockNumArgs) && (stackEntryIsBoolean(ssTop()))) && ((((generator = generatorForPC(eventualTarget))->isBranchTrue)) || (((generator = generatorForPC(eventualTarget))->isBranchFalse))))) { eventualTarget = (eventualTarget + ((generator->numBytes))) + ((((generator->isBranchTrue)) == ((((ssTop())->constant)) == (trueObject())) ? (/* begin spanFor:at:exts:in: */ ((generator->spanFunction))(generator, eventualTarget, 0, methodObj)) : 0)); ssPop(1); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } fixup = ensureFixupAt(eventualTarget); ssPop(-1); } else { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } fixup = ensureFixupAt(eventualTarget); } /* can't fall through */ deadCode = 1; /* begin Jump: */ genoperand(Jump, ((sqInt)fixup)); return 0; } /* StackToRegisterMappingCogit>>#genMarshalledSend:numArgs:sendTable: */ static sqInt NoDbgRegParms genMarshalledSendnumArgssendTable(sqInt selectorIndex, sqInt numArgs, sqInt *sendTable) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt annotation; assert(needsFrame); /* begin annotationForSendTable: */ if (sendTable == ordinarySendTrampolines) { annotation = IsSendCall; goto l2; } if (sendTable == directedSuperSendTrampolines) { annotation = IsDirectedSuperSend; goto l2; } if (sendTable == directedSuperBindingSendTrampolines) { annotation = IsDirectedSuperBindingSend; goto l2; } assert(sendTable == superSendTrampolines); annotation = IsSuperSend; l2: /* end annotationForSendTable: */; if ((annotation == IsSuperSend) || (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend)))) { genEnsureOopInRegNotForwardedscratchReg(ReceiverResultReg, TempReg); } if (numArgs >= (NumSendTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, numArgs, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(numArgs)); } } if (((annotation >= IsDirectedSuperSend) && (annotation <= IsDirectedSuperBindingSend))) { /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(tempOop)) { annotateobjRef(gMoveCwR(tempOop, TempReg), tempOop); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, tempOop, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(tempOop)); } } } genLoadInlineCacheWithSelector(selectorIndex); ((genoperand(Call, sendTable[((numArgs < (NumSendTrampolines - 1)) ? numArgs : (NumSendTrampolines - 1))]))->annotation = annotation); /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); 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 stack overflow. It distinguishes the two by testing ResultReceiverReg. If the register is zero then this is a stack-overflow because a) the receiver has already been pushed and so can be set to zero before calling the abort, and b) the receiver must always contain an object (and hence be non-zero) on SIC miss. */ /* StackToRegisterMappingCogit>>#genMethodAbortTrampolineFor: */ static sqInt NoDbgRegParms genMethodAbortTrampolineFor(sqInt numArgs) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jumpSICMiss; zeroOpcodeIndex(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, 0, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(0)); } /* begin JumpNonZero: */ jumpSICMiss = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); /* begin MoveR:Mw:r: */ anInstruction = genoperandoperandoperand(MoveRMwr, LinkReg, 0, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(0)); } compileTrampolineFornumArgsargargargargregsToSavepushLinkRegresultReg(ceStackOverflow, 1, SendNumArgsReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg); jmpTarget(jumpSICMiss, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genPushRegisterArgsForAbortMissNumArgs(backEnd, numArgs); return genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceSICMiss, trampolineNamenumRegArgs("ceMethodAbort", numArgs), 1, ReceiverResultReg, null, null, null, 0 /* emptyRegisterMask */, 0, NoReg, 1); } /* Generate the abort for a PIC. This abort performs either a call of ceInterpretMethodFromPIC:receiver: to handle invoking an uncogged target or a call of ceMNUFromPICMNUMethod:receiver: to handle an MNU dispatch in a closed PIC. It distinguishes the two by testing ClassReg. If the register is zero then this is an MNU. */ /* StackToRegisterMappingCogit>>#genPICAbortTrampolineFor: */ static sqInt NoDbgRegParms genPICAbortTrampolineFor(sqInt numArgs) { zeroOpcodeIndex(); genPushRegisterArgsForAbortMissNumArgs(backEnd, numArgs); return genInnerPICAbortTrampoline(trampolineNamenumRegArgs("cePICAbort", numArgs)); } /* StackToRegisterMappingCogit>>#genPICMissTrampolineFor: */ static sqInt NoDbgRegParms genPICMissTrampolineFor(sqInt numArgs) { sqInt startAddress; startAddress = methodZoneBase; zeroOpcodeIndex(); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(ceCPICMissreceiver, trampolineNamenumRegArgs("cePICMiss", numArgs), 2, ClassReg, ReceiverResultReg, null, null, 0 /* emptyRegisterMask */, 1, NoReg, 1); return startAddress; } /* StackToRegisterMappingCogit>>#genPopStackBytecode */ static sqInt genPopStackBytecode(void) { AbstractInstruction *anInstruction; if (((ssTop())->spilled)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, BytesPerWord, SPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(BytesPerWord)); } } ssPop(1); return 0; } /* 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. */ /* 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. */ /* StackToRegisterMappingCogit>>#genPrimitiveClosureValue */ static sqInt genPrimitiveClosureValue(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpFail1; AbstractInstruction *jumpFail2; AbstractInstruction *jumpFail3; AbstractInstruction *jumpFail4; AbstractInstruction *jumpFailNArgs; sqInt literal; sqInt offset; void (*primitiveRoutine)(void); sqInt quickConstant; sqInt result; genPushRegisterArgs(); genLoadSlotsourceRegdestReg(ClosureNumArgsIndex, ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)methodOrBlockNumArgs << 1) | 1); anInstruction1 = genoperandoperand(CmpCqR, (((usqInt)methodOrBlockNumArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpFailNArgs = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(ClosureOuterContextIndex, ReceiverResultReg, ClassReg); jumpFail1 = genJumpImmediate(ClassReg); genGetCompactClassIndexNonImmOfinto(ClassReg, TempReg); genCmpClassMethodContextCompactIndexR(TempReg); /* begin JumpNonZero: */ jumpFail2 = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(MethodIndex, ClassReg, SendNumArgsReg); jumpFail3 = genJumpImmediate(SendNumArgsReg); genGetFormatOfinto(SendNumArgsReg, TempReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpFail4 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); /* begin MoveM16:r:R: */ offset = offsetof(CogMethod, blockEntryOffset); /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperandoperand(MoveM16rR, offset, ClassReg, TempReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(offset)); } /* begin AddR:R: */ genoperandoperand(AddRR, ClassReg, TempReg); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); if (primitiveRoutine == primitiveClosureValueNoContextSwitch) { if (blockNoContextSwitchOffset == null) { return NotFullyInitialized; } /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(SubCqR, blockNoContextSwitchOffset, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(blockNoContextSwitchOffset)); } } /* begin JumpR: */ genoperand(JumpR, TempReg); jmpTarget(jumpBCMethod, jmpTarget(jumpFail1, jmpTarget(jumpFail2, jmpTarget(jumpFail3, jmpTarget(jumpFail4, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))))); if (((result = compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)))) < 0) { return result; } jmpTarget(jumpFailNArgs, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* 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. */ /* StackToRegisterMappingCogit>>#genPrimitiveFullClosureValue */ static sqInt genPrimitiveFullClosureValue(void) { AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *jumpBCMethod; AbstractInstruction *jumpFail4; AbstractInstruction *jumpFailImmediateMethod; AbstractInstruction *jumpFailNArgs; sqInt literal; void (*primitiveRoutine)(void); sqInt quickConstant; sqInt quickConstant1; sqInt result; genPushRegisterArgs(); genLoadSlotsourceRegdestReg(ClosureNumArgsIndex, ReceiverResultReg, TempReg); /* begin checkQuickConstant:forInstruction: */ literal = (((usqInt)methodOrBlockNumArgs << 1) | 1); anInstruction = genoperandoperand(CmpCqR, (((usqInt)methodOrBlockNumArgs << 1) | 1), TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(literal)); } /* begin JumpNonZero: */ jumpFailNArgs = genConditionalBranchoperand(JumpNonZero, ((sqInt)0)); genLoadSlotsourceRegdestReg(FullClosureCompiledBlockIndex, ReceiverResultReg, SendNumArgsReg); jumpFailImmediateMethod = genJumpImmediate(SendNumArgsReg); genGetFormatOfinto(SendNumArgsReg, TempReg); /* begin CmpCq:R: */ quickConstant = firstCompiledMethodFormat(); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(CmpCqR, quickConstant, TempReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(quickConstant)); } /* begin JumpLess: */ jumpFail4 = genConditionalBranchoperand(JumpLess, ((sqInt)0)); genLoadSlotsourceRegdestReg(HeaderIndex, SendNumArgsReg, ClassReg); jumpBCMethod = genJumpImmediate(ClassReg); primitiveRoutine = functionPointerForCompiledMethodprimitiveIndex(methodObj, primitiveIndex); /* begin AddCq:R: */ quickConstant1 = (primitiveRoutine == primitiveFullClosureValueNoContextSwitch ? fullBlockNoContextSwitchEntryOffset() : fullBlockEntryOffset()); /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(AddCqR, quickConstant1, ClassReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(quickConstant1)); } /* begin JumpR: */ genoperand(JumpR, ClassReg); jmpTarget(jumpBCMethod, jmpTarget(jumpFailImmediateMethod, jmpTarget(jumpFail4, genoperandoperand(Label, (labelCounter += 1), bytecodePC)))); if (((result = compileInterpreterPrimitiveflags(primitiveRoutine, primitivePropertyFlags(primitiveIndex)))) < 0) { return result; } jmpTarget(jumpFailNArgs, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return CompletePrimitive; } /* Generate an in-line perform primitive. The lookup code requires the selector to be in Arg0Reg. adjustArgumentsForPerform: adjusts the arguments once genLookupForPerformNumArgs: has generated the code for the lookup. */ /* StackToRegisterMappingCogit>>#genPrimitivePerform */ static sqInt genPrimitivePerform(void) { AbstractInstruction *anInstruction; sqInt offset; if (methodOrBlockNumArgs > 2 /* numRegArgs */) { /* begin MoveMw:r:R: */ offset = (methodOrBlockNumArgs - 1) * BytesPerWord; /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, SPReg, Arg0Reg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } } return genLookupForPerformNumArgs(methodOrBlockNumArgs); } /* StackToRegisterMappingCogit>>#genPushActiveContextBytecode */ static sqInt genPushActiveContextBytecode(void) { assert(needsFrame); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genGetActiveContextNumArgslargeinBlock(methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); return ssPushRegister(ReceiverResultReg); } /* Block compilation. At this point in the method create the block. Note its start and defer generating code for it until after the method and any other preceding blocks. The block's actual code will be compiled later. */ /* 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii */ /* StackToRegisterMappingCogit>>#genPushClosureCopyCopiedValuesBytecode */ static sqInt genPushClosureCopyCopiedValuesBytecode(void) { sqInt i; sqInt numArgs; sqInt numCopied; sqInt reg; sqInt startpc; assert(needsFrame); startpc = bytecodePC + (((generatorAt(byte0))->numBytes)); addBlockStartAtnumArgsnumCopiedspan(startpc, (numArgs = byte1 & 15), (numCopied = ((usqInt) byte1) >> 4), (((sqInt)((usqInt)(byte2) << 8))) + byte3); /* begin genInlineClosure:numArgs:numCopied: */ assert(getActiveContextAllocatesInMachineCode()); voidReceiverResultRegContainsSelf(); /* begin ssAllocateCallReg:and:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | (((1U << ReceiverResultReg) | (1U << SendNumArgsReg)) | (1U << ClassReg)), simStackPtr, simNativeStackPtr); genNoPopCreateClosureAtnumArgsnumCopiedcontextNumArgslargeinBlock(startpc + 1, numArgs, numCopied, methodOrBlockNumArgs, methodNeedsLargeContext(methodObj), inBlock); for (i = 1; i <= numCopied; i += 1) { reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, (ClosureFirstCopiedValueIndex + numCopied) - i, ReceiverResultReg); } ssPushRegister(ReceiverResultReg); return 0; } /* <SmallInteger> */ /* Override to avoid the BytecodeSetHasDirectedSuperSend check, which is unnecessary here given the simulation stack. */ /* StackToRegisterMappingCogit>>#genPushLiteralIndex: */ static sqInt NoDbgRegParms genPushLiteralIndex(sqInt literalIndex) { sqInt literal; literal = getLiteral(literalIndex); return genPushLiteral(literal); } /* StackToRegisterMappingCogit>>#genPushLiteralVariable: */ static sqInt NoDbgRegParms genPushLiteralVariable(sqInt literalIndex) { AbstractInstruction *anInstruction; sqInt association; sqInt bcpc; BytecodeDescriptor *descriptor1; sqInt eA; sqInt eB; sqInt freeReg; sqInt savedB0; sqInt savedB1; sqInt savedB2; sqInt savedB3; sqInt savedEA; sqInt savedEB; sqInt savedNEB; /* If followed by a directed super send bytecode, avoid generating any code yet. The association will be passed to the directed send trampoline in a register and fully dereferenced only when first linked. It will be ignored in later sends. */ association = getLiteral(literalIndex); assert(!(directedSendUsesBinding)); /* begin nextDescriptorExtensionsAndNextPCInto: */ descriptor1 = generatorAt(byte0); savedB0 = byte0; savedB1 = byte1; savedB2 = byte2; savedB3 = byte3; savedEA = extA; savedEB = extB; savedNEB = numExtB; bcpc = bytecodePC + ((descriptor1->numBytes)); do { if (bcpc > endPC) { goto l1; } byte0 = (fetchByteofObject(bcpc, methodObj)) + bytecodeSetOffset; descriptor1 = generatorAt(byte0); loadSubsequentBytesForDescriptorat(descriptor1, bcpc); if (!((descriptor1->isExtension))) { eA = extA; eB = extB; extA = savedEA; extB = savedEB; numExtB = savedNEB; byte0 = savedB0; byte1 = savedB1; byte2 = savedB2; byte3 = savedB3; if ((descriptor1 != null) && ((((descriptor1->generator)) == genExtSendSuperBytecode) && (eB >= 64))) { ssPushConstant(association); directedSendUsesBinding = 1; return 0; } goto l1; } ((descriptor1->generator))(); bcpc += (descriptor1->numBytes); } while(1); l1: /* end nextDescriptorExtensionsAndNextPCInto: */; /* 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-of-evaluation issue if we defer the dereference. */ freeReg = allocateRegNotConflictingWith(0); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(association)) { annotateobjRef(gMoveCwR(association, TempReg), association); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, association, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(association)); } } genEnsureObjInRegNotForwardedscratchReg(TempReg, freeReg); genLoadSlotsourceRegdestReg(ValueIndex, TempReg, freeReg); ssPushRegister(freeReg); return 0; } /* StackToRegisterMappingCogit>>#genPushLiteral: */ static sqInt NoDbgRegParms genPushLiteral(sqInt literal) { return ssPushConstant(literal); } /* StackToRegisterMappingCogit>>#genPushMaybeContextReceiverVariable: */ static sqInt NoDbgRegParms genPushMaybeContextReceiverVariable(sqInt slotIndex) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *jmpDone; AbstractInstruction *jmpSingle; /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << ReceiverResultReg) | (1U << SendNumArgsReg)), simStackPtr, simNativeStackPtr); ensureReceiverResultRegContainsSelf(); /* begin genPushMaybeContextSlotIndex: */ assert(needsFrame); if (CallerSavedRegisterMask & (1U << ReceiverResultReg)) { /* We have no way of reloading ReceiverResultReg since we need the inst var value as the result. */ voidReceiverResultRegContainsSelf(); } if (slotIndex == InstructionPointerIndex) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceFetchContextInstVarTrampoline); (abstractInstruction->annotation = IsRelativeCall); return ssPushRegister(SendNumArgsReg); } genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); jmpSingle = genJumpNotSmallIntegerInScratchReg(TempReg); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceFetchContextInstVarTrampoline); (abstractInstruction1->annotation = IsRelativeCall); /* begin Jump: */ jmpDone = genoperand(Jump, ((sqInt)0)); jmpTarget(jmpSingle, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); genLoadSlotsourceRegdestReg(slotIndex, ReceiverResultReg, SendNumArgsReg); jmpTarget(jmpDone, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return ssPushRegister(SendNumArgsReg); } /* StackToRegisterMappingCogit>>#genPushNewArrayBytecode */ static sqInt genPushNewArrayBytecode(void) { sqInt i; sqInt i1; int popValues; sqInt size; assert(needsFrame); voidReceiverResultRegContainsSelf(); if ((popValues = byte1 > 0x7F)) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } } else { /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << SendNumArgsReg) | (1U << ReceiverResultReg)), simStackPtr, simNativeStackPtr); } size = byte1 & 0x7F; if (!popValues) { if (tryCollapseTempVectorInitializationOfSize(size)) { return 0; } } genNewArrayOfSizeinitialized(size, !popValues); if (popValues) { for (i = (size - 1); i >= 0; i += -1) { /* begin PopR: */ genoperand(PopR, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(TempReg, i, ReceiverResultReg); } ssPop(size); } return ssPushRegister(ReceiverResultReg); } /* StackToRegisterMappingCogit>>#genPushReceiverBytecode */ static sqInt genPushReceiverBytecode(void) { if ((((simSelf())->liveRegister)) == ReceiverResultReg) { return ssPushRegister(ReceiverResultReg); } return ssPushDesc(ssSelfDescriptor()); } /* StackToRegisterMappingCogit>>#genPushReceiverVariable: */ static sqInt NoDbgRegParms genPushReceiverVariable(sqInt index) { ensureReceiverResultRegContainsSelf(); return ssPushBaseoffset(ReceiverResultReg, slotOffsetOfInstVarIndex(index)); } /* 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. */ /* StackToRegisterMappingCogit>>#genPushRegisterArgs */ static void genPushRegisterArgs(void) { if (!(regArgsHaveBeenPushed || (methodOrBlockNumArgs > 2 /* numRegArgs */))) { genPushRegisterArgsForNumArgsscratchReg(backEnd, methodOrBlockNumArgs, SendNumArgsReg); regArgsHaveBeenPushed = 1; } } /* StackToRegisterMappingCogit>>#genPushRemoteTempLongBytecode */ static sqInt genPushRemoteTempLongBytecode(void) { AbstractInstruction *anInstruction; sqInt offset; sqInt regMask; sqInt remoteTempReg; sqInt tempVectReg; tempVectReg = allocateRegNotConflictingWith(0); /* begin MoveMw:r:R: */ offset = frameOffsetOfTemporary(byte2); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, FPReg, tempVectReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin availableRegOrNoneNotConflictingWith: */ regMask = 1U << tempVectReg; remoteTempReg = availableRegisterOrNoneFor(backEnd, (liveRegisters()) | regMask); if (remoteTempReg == NoReg) { remoteTempReg = tempVectReg; } genLoadSlotsourceRegdestReg(byte1, tempVectReg, remoteTempReg); return ssPushRegister(remoteTempReg); } /* If a frameless method (not a block), only argument temps can be accessed. This is assured by the use of needsFrameIfMod16GENumArgs: in pushTemp. */ /* StackToRegisterMappingCogit>>#genPushTemporaryVariable: */ static sqInt NoDbgRegParms genPushTemporaryVariable(sqInt index) { assert((inBlock > 0) || (needsFrame || (index < methodOrBlockNumArgs))); return ssPushDesc(simStack[index + 1]); } /* In a frameless method ReceiverResultReg already contains self. In a frameful method, ReceiverResultReg /may/ contain self. */ /* StackToRegisterMappingCogit>>#genReturnReceiver */ static sqInt genReturnReceiver(void) { if (needsFrame) { if (!((((simSelf())->liveRegister)) == ReceiverResultReg)) { /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); } } return genUpArrowReturn(); } /* StackToRegisterMappingCogit>>#genReturnTopFromBlock */ static sqInt genReturnTopFromBlock(void) { assert(inBlock > 0); popToReg(ssTop(), ReceiverResultReg); ssPop(1); return genBlockReturn(); } /* StackToRegisterMappingCogit>>#genReturnTopFromMethod */ static sqInt genReturnTopFromMethod(void) { popToReg(ssTop(), ReceiverResultReg); ssPop(1); return genUpArrowReturn(); } /* StackToRegisterMappingCogit>>#genSendDirectedSuper:numArgs: */ static sqInt NoDbgRegParms genSendDirectedSupernumArgs(sqInt selectorIndex, sqInt numArgs) { sqInt result; assert((((ssTop())->type)) == SSConstant); tempOop = ((ssTop())->constant); ssPop(1); marshallSendArguments(numArgs); result = genMarshalledSendnumArgssendTable(selectorIndex, numArgs, (directedSendUsesBinding ? directedSuperBindingSendTrampolines : directedSuperSendTrampolines)); directedSendUsesBinding = 0; return result; } /* StackToRegisterMappingCogit>>#genSendSuper:numArgs: */ static sqInt NoDbgRegParms genSendSupernumArgs(sqInt selectorIndex, sqInt numArgs) { marshallSendArguments(numArgs); return genMarshalledSendnumArgssendTable(selectorIndex, numArgs, superSendTrampolines); } /* Generate a trampoline with four arguments. Hack: a negative value indicates an abstract register, a non-negative value indicates a constant. */ /* StackToRegisterMappingCogit>>#genSendTrampolineFor:numArgs:called:arg:arg:arg:arg: */ static sqInt NoDbgRegParms genSendTrampolineFornumArgscalledargargargarg(void *aRoutine, sqInt numArgs, char *aString, sqInt regOrConst0, sqInt regOrConst1, sqInt regOrConst2, sqInt regOrConst3) { sqInt routine; sqInt startAddress; startAddress = methodZoneBase; zeroOpcodeIndex(); genPushRegisterArgsForNumArgsscratchReg(backEnd, numArgs, SendNumArgsReg); /* begin selectorIndexDereferenceRoutine */ routine = null; if (!(routine == null)) { /* begin Call: */ genoperand(Call, routine); } genTrampolineForcallednumArgsargargargargregsToSavepushLinkRegresultRegappendOpcodes(aRoutine, aString, 4, regOrConst0, regOrConst1, regOrConst2, regOrConst3, 0 /* emptyRegisterMask */, 1, NoReg, 1); return startAddress; } /* StackToRegisterMappingCogit>>#genSend:numArgs: */ static sqInt NoDbgRegParms genSendnumArgs(sqInt selectorIndex, sqInt numArgs) { marshallSendArguments(numArgs); return genMarshalledSendnumArgssendTable(selectorIndex, numArgs, ordinarySendTrampolines); } /* StackToRegisterMappingCogit>>#genSpecialSelectorArithmetic */ static sqInt genSpecialSelectorArithmetic(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; AbstractInstruction *anInstruction2; AbstractInstruction *anInstruction3; AbstractInstruction *anInstruction4; AbstractInstruction *anInstruction5; AbstractInstruction *anInstruction6; AbstractInstruction *anInstruction7; sqInt argInt; int argIsConst; sqInt argIsInt; sqInt i; sqInt index; AbstractInstruction *jumpContinue; AbstractInstruction *jumpNotSmallInts; BytecodeDescriptor *primDescriptor; sqInt rcvrInt; int 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))) || ((mclassIsSmallInteger()) && (isSameEntryAs(ssValue(1), simSelf()))); if (argIsInt && (rcvrIsInt && (rcvrIsConst))) { 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)) { /* Must annotate the bytecode for correct pc mapping. */ return (ssPop(2), ssPushAnnotatedConstant((((usqInt)result << 1) | 1))); } return genSpecialSelectorSend(); } if ((rcvrIsConst && (!rcvrIsInt)) || (argIsConst && (!argIsInt))) { return genSpecialSelectorSend(); } if (!(argIsInt || (rcvrIsInt))) { return genSpecialSelectorSend(); } if (argIsInt) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } popToReg(ssValue(1), ReceiverResultReg); ssPop(2); } else { marshallSendArguments(1); } jumpNotSmallInts = (!(rcvrIsInt && (argIsInt)) ? (argIsInt ? genJumpNotSmallInteger(ReceiverResultReg) : (rcvrIsInt ? genJumpNotSmallInteger(Arg0Reg) : (/* begin genJumpNotSmallIntegersIn:and:scratch: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg), /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, TempReg), genJumpNotSmallIntegerInScratchReg(TempReg)))) : 0); switch ((primDescriptor->opcode)) { case AddRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(AddCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(argInt - ConstZero)); } /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(SubCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(argInt - ConstZero)); } } else { genRemoveSmallIntegerTagsInScratchReg(ReceiverResultReg); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); if (rcvrIsInt && (rcvrIsConst)) { /* begin checkQuickConstant:forInstruction: */ anInstruction2 = genoperandoperand(MoveCqR, rcvrInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction2)) { (anInstruction2->dependent = locateLiteral(rcvrInt)); } } else { /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, ReceiverResultReg); genSetSmallIntegerTagsIn(ReceiverResultReg); } } break; case SubRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction3 = genoperandoperand(SubCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction3)) { (anInstruction3->dependent = locateLiteral(argInt - ConstZero)); } /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin checkQuickConstant:forInstruction: */ anInstruction4 = genoperandoperand(AddCqR, argInt - ConstZero, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction4)) { (anInstruction4->dependent = locateLiteral(argInt - ConstZero)); } } else { genRemoveSmallIntegerTagsInScratchReg(Arg0Reg); /* begin SubR:R: */ genoperandoperand(SubRR, Arg0Reg, ReceiverResultReg); /* begin JumpNoOverflow: */ jumpContinue = genConditionalBranchoperand(JumpNoOverflow, ((sqInt)0)); /* begin AddR:R: */ genoperandoperand(AddRR, Arg0Reg, ReceiverResultReg); genSetSmallIntegerTagsIn(Arg0Reg); } break; case AndRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction5 = genoperandoperand(AndCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction5)) { (anInstruction5->dependent = locateLiteral(argInt)); } } else { /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, ReceiverResultReg); } jumpContinue = (!(jumpNotSmallInts == null) ? (/* begin Jump: */ genoperand(Jump, ((sqInt)0))) : 0); break; case OrRR: if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction6 = genoperandoperand(OrCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction6)) { (anInstruction6->dependent = locateLiteral(argInt)); } } else { /* begin OrR:R: */ genoperandoperand(OrRR, Arg0Reg, ReceiverResultReg); } jumpContinue = (!(jumpNotSmallInts == null) ? (/* begin Jump: */ genoperand(Jump, ((sqInt)0))) : 0); break; default: error("Case not found and no otherwise clause"); } if (jumpNotSmallInts == null) { if (!(jumpContinue)) { /* overflow cannot happen */ /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); ssPushRegister(ReceiverResultReg); return 0; } } else { jmpTarget(jumpNotSmallInts, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } if (argIsInt) { /* begin checkQuickConstant:forInstruction: */ anInstruction7 = genoperandoperand(MoveCqR, argInt, Arg0Reg); if (usesOutOfLineLiteral(anInstruction7)) { (anInstruction7->dependent = locateLiteral(argInt)); } } index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); genMarshalledSendnumArgssendTable((-index) - 1, 1, ordinarySendTrampolines); jmpTarget(jumpContinue, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); return 0; } /* StackToRegisterMappingCogit>>#genSpecialSelectorClass */ static sqInt genSpecialSelectorClass(void) { sqInt requiredReg1; sqInt topReg; topReg = registerOrNone(ssTop()); ssPop(1); if ((topReg == NoReg) || (topReg == ClassReg)) { /* begin ssAllocateRequiredReg:and: */ requiredReg1 = (topReg = SendNumArgsReg); ssAllocateRequiredRegMaskupThroughupThroughNative((1U << requiredReg1) | (1U << ClassReg), simStackPtr, simNativeStackPtr); } else { /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr, simNativeStackPtr); } ssPush(1); popToReg(ssTop(), topReg); genGetClassObjectOfintoscratchReginstRegIsReceiver(topReg, ClassReg, TempReg, 0); return (ssPop(1), ssPushRegister(ClassReg)); } /* StackToRegisterMappingCogit>>#genSpecialSelectorComparison */ static sqInt genSpecialSelectorComparison(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt argInt; sqInt argIsIntConst; BytecodeDescriptor *branchDescriptor; BytecodeDescriptor *branchDescriptor1; sqInt i; sqInt index; sqInt inlineCAB; AbstractInstruction *jumpNotSmallInts; void *jumpTarget; sqInt nExts; sqInt nextPC; sqInt nextPC1; sqInt postBranchPC; sqInt postBranchPC1; BytecodeDescriptor *primDescriptor; BytecodeDescriptor *primDescriptor1; int rcvrIsConst; sqInt rcvrIsInt; sqInt targetBytecodePC; sqInt targetPC; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= (simStackPtr - 2)) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < (simStackPtr - 2)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : (simStackPtr - 2))); i <= (simStackPtr - 2); i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = (simStackPtr - 2) + 1; } primDescriptor = generatorAt(byte0); argIsIntConst = ((((ssTop())->type)) == SSConstant) && ((((argInt = ((ssTop())->constant))) & 1)); rcvrIsInt = (((rcvrIsConst = (((ssValue(1))->type)) == SSConstant)) && (((((ssValue(1))->constant)) & 1))) || ((mclassIsSmallInteger()) && (isSameEntryAs(ssValue(1), simSelf()))); if (argIsIntConst && (rcvrIsInt && (rcvrIsConst))) { return genStaticallyResolvedSpecialSelectorComparison(); } /* begin extractMaybeBranchDescriptorInto: */ primDescriptor1 = generatorAt(byte0); nextPC1 = bytecodePC + ((primDescriptor1->numBytes)); nExts = 0; while (1) { while (1) { /* begin generatorForPC: */ branchDescriptor1 = generatorAt(bytecodeSetOffset + (fetchByteofObject(nextPC1, methodObj))); if (!((branchDescriptor1->isExtension))) break; nExts += 1; nextPC1 += (branchDescriptor1->numBytes); } /* begin isUnconditionalBranch */ if (!((isBranch(branchDescriptor1)) && (!(((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse)))))) break; nextPC1 = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); } targetBytecodePC = (postBranchPC1 = 0); if (((branchDescriptor1->isBranchTrue)) || ((branchDescriptor1->isBranchFalse))) { targetBytecodePC = eventualTargetOf((nextPC1 + ((branchDescriptor1->numBytes))) + (((branchDescriptor1->spanFunction))(branchDescriptor1, nextPC1, nExts, methodObj))); postBranchPC1 = eventualTargetOf(nextPC1 + ((branchDescriptor1->numBytes))); } else { nextPC1 = bytecodePC + ((primDescriptor1->numBytes)); } branchDescriptor = branchDescriptor1; nextPC = nextPC1; postBranchPC = postBranchPC1; targetPC = targetBytecodePC; /* Further, only interested in inlining = and ~= if there's a SmallInteger constant involved. The relational operators successfully statically predict SmallIntegers; the equality operators do not. */ inlineCAB = ((branchDescriptor->isBranchTrue)) || ((branchDescriptor->isBranchFalse)); if (inlineCAB && ((((primDescriptor->opcode)) == JumpZero) || (((primDescriptor->opcode)) == JumpNonZero))) { inlineCAB = argIsIntConst || (rcvrIsInt); } if (!inlineCAB) { return genSpecialSelectorSend(); } if (argIsIntConst) { popToReg(ssValue(1), ReceiverResultReg); ssPop(2); } else { marshallSendArguments(1); } jumpNotSmallInts = (!(rcvrIsInt && (argIsIntConst)) ? (argIsIntConst ? genJumpNotSmallInteger(ReceiverResultReg) : (rcvrIsInt ? genJumpNotSmallInteger(Arg0Reg) : (/* begin genJumpNotSmallIntegersIn:and:scratch: */ genoperandoperand(MoveRR, ReceiverResultReg, TempReg), /* begin AndR:R: */ genoperandoperand(AndRR, Arg0Reg, TempReg), genJumpNotSmallIntegerInScratchReg(TempReg)))) : 0); if (argIsIntConst) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(CmpCqR, argInt, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(argInt)); } } else { /* begin CmpR:R: */ genoperandoperand(CmpRR, Arg0Reg, ReceiverResultReg); } genConditionalBranchoperand(((branchDescriptor->isBranchTrue) ? (primDescriptor->opcode) : inverseBranchFor((primDescriptor->opcode))), ((usqInt)(ensureNonMergeFixupAt(targetPC)))); /* begin Jump: */ jumpTarget = ensureNonMergeFixupAt(postBranchPC); genoperand(Jump, ((sqInt)jumpTarget)); if (!(jumpNotSmallInts)) { /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); ensureFixupAt(postBranchPC); ensureFixupAt(targetPC); deadCode = 1; return 0; } jmpTarget(jumpNotSmallInts, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); if (argIsIntConst) { /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, argInt, Arg0Reg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(argInt)); } } index = byte0 - ( #if MULTIPLEBYTECODESETS (bytecodeSetOffset == 256 ? AltFirstSpecialSelector + 256 : FirstSpecialSelector) #else /* MULTIPLEBYTECODESETS */ FirstSpecialSelector #endif /* MULTIPLEBYTECODESETS */ ); return genMarshalledSendnumArgssendTable((-index) - 1, 1, ordinarySendTrampolines); } /* Assumes both operands are ints */ /* StackToRegisterMappingCogit>>#genStaticallyResolvedSpecialSelectorComparison */ static sqInt genStaticallyResolvedSpecialSelectorComparison(void) { sqInt argInt; BytecodeDescriptor *primDescriptor; sqInt rcvrInt; int result; primDescriptor = generatorAt(byte0); argInt = ((ssTop())->constant); rcvrInt = ((ssValue(1))->constant); 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"); } ssPop(2); return ssPushAnnotatedConstant((result ? trueObject() : falseObject())); } /* We need a frame because the association has to be in ReceiverResultReg for the various trampolines and ReceiverResultReg holds only the receiver in frameless methods. */ /* StackToRegisterMappingCogit>>#genStorePop:LiteralVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopLiteralVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt litVarIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { AbstractInstruction *anInstruction; sqInt association; sqInt i; sqInt topReg; assert(needsFrame); /* begin genLoadLiteralVariable:in: */ association = getLiteral(litVarIndex); voidReceiverResultRegContainsSelf(); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); /* begin genMoveConstant:R: */ if (shouldAnnotateObjectReference(association)) { annotateobjRef(gMoveCwR(association, ReceiverResultReg), association); } else { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, association, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(association)); } } genEnsureObjInRegNotForwardedscratchReg(ReceiverResultReg, TempReg); /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ # if IMMUTABILITY if (needsImmCheck) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr - 1, simNativeStackPtr); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } return genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(ClassReg, ValueIndex, ReceiverResultReg, TempReg, needsStoreCheck, 0); } # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, ValueIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck); } /* The reason we need a frame here is that assigning to an inst var of a context may involve wholesale reorganization of stack pages, and the only way to preserve the execution state of an activation in that case is if it has a frame. */ /* StackToRegisterMappingCogit>>#genStorePop:MaybeContextReceiverVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopMaybeContextReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; AbstractInstruction *abstractInstruction2; AbstractInstruction *abstractInstruction3; AbstractInstruction *anInstruction; AbstractInstruction *anInstruction1; sqInt i; AbstractInstruction *immutabilityFailure; AbstractInstruction *mutableJump; immutabilityFailure = ((AbstractInstruction *) 0); assert(needsFrame); ssFlushUpThroughReceiverVariable(slotIndex); ensureReceiverResultRegContainsSelf(); /* begin genGenericStorePop:MaybeContextSlotIndex:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ assert(needsFrame); # if IMMUTABILITY if (needsImmCheck) { mutableJump = genJumpMutablescratchReg(ReceiverResultReg, TempReg); /* begin genStoreTrampolineCall: */ assert(IMMUTABILITY); if (slotIndex >= (NumStoreTrampolines - 1)) { /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperand(MoveCqR, slotIndex, TempReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction3 = genoperand(Call, ceStoreTrampolines[NumStoreTrampolines - 1]); (abstractInstruction3->annotation = IsRelativeCall); } else { /* begin CallRT: */ abstractInstruction1 = genoperand(Call, ceStoreTrampolines[slotIndex]); (abstractInstruction1->annotation = IsRelativeCall); } /* begin annotateBytecode: */ abstractInstruction2 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction2->annotation = HasBytecodePC); /* begin putSelfInReceiverResultReg */ storeToReg(simSelf(), ReceiverResultReg); /* begin Jump: */ immutabilityFailure = genoperand(Jump, ((sqInt)0)); jmpTarget(mutableJump, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } # endif /* IMMUTABILITY */ ssPop(1); /* begin ssAllocateCallReg:and: */ ssAllocateRequiredRegMaskupThroughupThroughNative(CallerSavedRegisterMask | ((1U << ClassReg) | (1U << SendNumArgsReg)), simStackPtr, simNativeStackPtr); ssPush(1); genLoadSlotsourceRegdestReg(SenderIndex, ReceiverResultReg, TempReg); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* begin checkQuickConstant:forInstruction: */ anInstruction1 = genoperandoperand(MoveCqR, slotIndex, SendNumArgsReg); if (usesOutOfLineLiteral(anInstruction1)) { (anInstruction1->dependent = locateLiteral(slotIndex)); } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceStoreContextInstVarTrampoline); (abstractInstruction->annotation = IsRelativeCall); # if IMMUTABILITY if (needsImmCheck) { jmpTarget(immutabilityFailure, genoperandoperand(Label, (labelCounter += 1), bytecodePC)); } # endif /* IMMUTABILITY */ return 0; } /* StackToRegisterMappingCogit>>#genStorePop:ReceiverVariable:needsStoreCheck:needsImmutabilityCheck: */ static sqInt NoDbgRegParms genStorePopReceiverVariableneedsStoreCheckneedsImmutabilityCheck(sqInt popBoolean, sqInt slotIndex, sqInt needsStoreCheck, sqInt needsImmCheck) { sqInt i; sqInt needsImmCheck1; sqInt needsStoreCheck1; sqInt topReg; ssFlushUpThroughReceiverVariable(slotIndex); ensureReceiverResultRegContainsSelf(); /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ needsStoreCheck1 = (!useTwoPaths) && (needsStoreCheck); needsImmCheck1 = needsImmCheck && (!useTwoPaths); # if IMMUTABILITY if (needsImmCheck1) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ClassReg, simStackPtr - 1, simNativeStackPtr); ssStoreAndReplacePoptoReg(popBoolean, ClassReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } return genStoreWithImmutabilityCheckSourceRegslotIndexdestRegscratchRegneedsStoreCheckneedRestoreRcvr(ClassReg, slotIndex, ReceiverResultReg, TempReg, needsStoreCheck1, 1); } # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, slotIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck1); } /* The only reason we assert needsFrame here is that in a frameless method ReceiverResultReg must and does contain only self, but the ceStoreCheck trampoline expects the target of the store to be in ReceiverResultReg. So in a frameless method we would have a conflict between the receiver and the temote temp store, unless we we smart enough to realise that ReceiverResultReg was unused after the literal variable store, unlikely given that methods return self by default. */ /* StackToRegisterMappingCogit>>#genStorePop:RemoteTemp:At:needsStoreCheck: */ static sqInt NoDbgRegParms genStorePopRemoteTempAtneedsStoreCheck(sqInt popBoolean, sqInt slotIndex, sqInt remoteTempIndex, sqInt needsStoreCheck) { AbstractInstruction *anInstruction; sqInt offset; sqInt topReg; assert(needsFrame); /* begin ssAllocateRequiredReg: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << ReceiverResultReg, simStackPtr, simNativeStackPtr); voidReceiverResultRegContainsSelf(); /* begin MoveMw:r:R: */ offset = frameOffsetOfTemporary(remoteTempIndex); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveMwrR, offset, FPReg, ReceiverResultReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } /* begin genGenericStorePop:slotIndex:destReg:needsStoreCheck:needsRestoreRcvr:needsImmutabilityCheck: */ # if IMMUTABILITY # endif /* IMMUTABILITY */ topReg = allocateRegForStackEntryAtnotConflictingWith(0, 1U << ReceiverResultReg); ssStorePoptoReg(popBoolean, topReg); return genStoreSourceRegslotIndexdestRegscratchReginFrameneedsStoreCheck(topReg, slotIndex, ReceiverResultReg, TempReg, needsFrame, needsStoreCheck); } /* StackToRegisterMappingCogit>>#genStorePop:TemporaryVariable: */ static sqInt NoDbgRegParms genStorePopTemporaryVariable(sqInt popBoolean, sqInt tempIndex) { AbstractInstruction *anInstruction; sqInt offset; sqInt reg; ssFlushUpThroughTemporaryVariable(tempIndex); reg = ssStorePoptoPreferredReg(popBoolean, TempReg); /* begin MoveR:Mw:r: */ offset = frameOffsetOfTemporary(tempIndex); /* begin checkQuickConstant:forInstruction: */ anInstruction = genoperandoperandoperand(MoveRMwr, reg, offset, FPReg); if (usesOutOfLineLiteral(anInstruction)) { (anInstruction->dependent = locateLiteral(offset)); } ((simStackAt(tempIndex + 1))->bcptr = bytecodePC); return 0; } /* Generate a method return from within a method or a block. Frameless method activation looks like CISCs (x86): receiver args sp-> ret pc. RISCs (ARM): receiver args ret pc in LR. A fully framed activation is described in CoInterpreter class>initializeFrameIndices. Return pops receiver and arguments off the stack. Callee pushes the result. */ /* StackToRegisterMappingCogit>>#genUpArrowReturn */ static sqInt genUpArrowReturn(void) { AbstractInstruction *abstractInstruction; AbstractInstruction *abstractInstruction1; sqInt i; sqInt offset; /* can't fall through */ deadCode = 1; if (inBlock > 0) { assert(needsFrame); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } /* begin CallRT: */ abstractInstruction = genoperand(Call, ceNonLocalReturnTrampoline); (abstractInstruction->annotation = IsRelativeCall); /* begin annotateBytecode: */ abstractInstruction1 = genoperandoperand(Label, (labelCounter += 1), bytecodePC); (abstractInstruction1->annotation = HasBytecodePC); return 0; } if ( # if IMMUTABILITY needsFrame && (!useTwoPaths) # else /* IMMUTABILITY */ needsFrame # endif /* IMMUTABILITY */ ) { /* begin MoveR:R: */ genoperandoperand(MoveRR, FPReg, SPReg); /* begin PopR: */ genoperand(PopR, FPReg); /* begin PopR: */ genoperand(PopR, LinkReg); /* begin RetN: */ genoperand(RetN, (methodOrBlockNumArgs + 1) * BytesPerWord); } else { /* begin RetN: */ offset = ((methodOrBlockNumArgs > 2 /* numRegArgs */) || (regArgsHaveBeenPushed) ? (methodOrBlockNumArgs + 1) * BytesPerWord : 0); genoperand(RetN, offset); } return 0; } /* StackToRegisterMappingCogit>>#initSimStackForFramefulMethod: */ static void NoDbgRegParms initSimStackForFramefulMethod(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; /* N.B. Includes num args */ simStackPtr = methodOrBlockNumTemps; simSpillBase = methodOrBlockNumTemps + 1; cascade0 = simSelf(); (cascade0->type = SSBaseOffset); (cascade0->spilled = 1); (cascade0->registerr = FPReg); (cascade0->offset = FoxMFReceiver); (cascade0->liveRegister = NoReg); for (i = 1; i <= methodOrBlockNumArgs; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = FPReg); (desc->offset = FoxCallerSavedIP + (((methodOrBlockNumArgs - i) + 1) * BytesPerWord)); (desc->bcptr = startpc); } for (i = (methodOrBlockNumArgs + 1); i <= simStackPtr; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = FPReg); (desc->offset = FoxMFReceiver - ((i - methodOrBlockNumArgs) * BytesPerWord)); (desc->bcptr = startpc); } } /* The register receiver (the 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 ReceiverResultReg by the block entry. */ /* StackToRegisterMappingCogit>>#initSimStackForFramelessBlock: */ static void NoDbgRegParms initSimStackForFramelessBlock(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; cascade0 = simSelf(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = ReceiverResultReg); (cascade0->liveRegister = ReceiverResultReg); assert(methodOrBlockNumTemps >= methodOrBlockNumArgs); for (i = 1; i <= methodOrBlockNumTemps; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->spilled = 1); (desc->registerr = SPReg); (desc->offset = (methodOrBlockNumArgs - i) * BytesPerWord); (desc->bcptr = startpc); } /* N.B. Includes num args */ simStackPtr = methodOrBlockNumTemps; simSpillBase = methodOrBlockNumTemps + 1; } /* StackToRegisterMappingCogit>>#initSimStackForFramelessMethod: */ static void NoDbgRegParms initSimStackForFramelessMethod(sqInt startpc) { CogSimStackEntry * cascade0; CogSimStackEntry *desc; sqInt i; cascade0 = simSelf(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = ReceiverResultReg); (cascade0->liveRegister = ReceiverResultReg); assert(methodOrBlockNumTemps == methodOrBlockNumArgs); assert((numRegArgs()) <= 2); if (((methodOrBlockNumArgs >= 1) && (methodOrBlockNumArgs <= 2 /* numRegArgs */))) { desc = simStackAt(1); (desc->type = SSRegister); (desc->spilled = 0); (desc->registerr = Arg0Reg); (desc->bcptr = startpc); if (methodOrBlockNumArgs > 1) { desc = simStackAt(2); (desc->type = SSRegister); (desc->spilled = 0); (desc->registerr = Arg1Reg); (desc->bcptr = startpc); } } else { for (i = 1; i <= methodOrBlockNumArgs; i += 1) { desc = simStackAt(i); (desc->type = SSBaseOffset); (desc->registerr = SPReg); (desc->spilled = 1); (desc->offset = (methodOrBlockNumArgs - i) * BytesPerWord); (desc->bcptr = startpc); } } simStackPtr = methodOrBlockNumArgs; simSpillBase = methodOrBlockNumArgs + 1; } /* StackToRegisterMappingCogit>>#liveRegisters */ static sqInt liveRegisters(void) { sqInt i; sqInt regsSet; if (needsFrame) { regsSet = 0; } else { /* begin registerMaskFor: */ regsSet = 1U << ReceiverResultReg; if ((methodOrBlockNumArgs <= 2 /* numRegArgs */) && (methodOrBlockNumArgs > 0)) { regsSet = regsSet | (1U << Arg0Reg); if (methodOrBlockNumArgs > 1) { regsSet = regsSet | (1U << Arg1Reg); } } } for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= simStackPtr; i += 1) { regsSet = regsSet | (registerMask(simStackAt(i))); } return regsSet; } /* insert nops for dead code that is mapped so that bc to mc mapping is not many to one */ /* StackToRegisterMappingCogit>>#mapDeadDescriptorIfNeeded: */ static sqInt NoDbgRegParms mapDeadDescriptorIfNeeded(BytecodeDescriptor *descriptor) { AbstractInstruction *abstractInstruction; flag("annotateInstruction"); if (((descriptor->isMapped)) || ((inBlock > 0) && ((descriptor->isMappedInBlock)))) { /* begin annotateBytecode: */ abstractInstruction = gen(Nop); (abstractInstruction->annotation = HasBytecodePC); } 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. */ /* StackToRegisterMappingCogit>>#marshallSendArguments: */ static void NoDbgRegParms marshallSendArguments(sqInt numArgs) { sqInt anyRefs; CogSimStackEntry * cascade0; sqInt i; sqInt i1; sqInt i2; sqInt numSpilled; /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= ((simStackPtr - numArgs) - 1)) { for (i2 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < ((simStackPtr - numArgs) - 1)) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : ((simStackPtr - numArgs) - 1))); i2 < (simStackPtr - numArgs); i2 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i2), frameOffsetOfTemporary(i2 - 1), FPReg); } simSpillBase = ((simStackPtr - numArgs) - 1) + 1; } if (numArgs > 2 /* numRegArgs */) { /* If there are no spills and no references to ReceiverResultReg the fetch of ReceiverResultReg from the stack can be avoided by assigning directly to ReceiverResultReg and pushing it. */ numSpilled = numberOfSpillsInTopNItems(numArgs + 1); anyRefs = anyReferencesToRegisterinTopNItems(ReceiverResultReg, numArgs + 1); if ((numSpilled > 0) || (anyRefs)) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } storeToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); } else { cascade0 = simStackAt(simStackPtr - numArgs); storeToReg(cascade0, ReceiverResultReg); (cascade0->type = SSRegister); (cascade0->registerr = ReceiverResultReg); /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i1 <= simStackPtr; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = simStackPtr + 1; } } } else { /* Move the args to the register arguments, being careful to do so last to first so e.g. previous contents don't get overwritten. Also check for any arg registers in use by other args. */ if (numArgs > 0) { if (numArgs > 1) { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg0Reg, simStackPtr - 2, simNativeStackPtr); /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg1Reg, simStackPtr - 1, simNativeStackPtr); } else { /* begin ssAllocateRequiredReg:upThrough: */ ssAllocateRequiredRegMaskupThroughupThroughNative(1U << Arg0Reg, simStackPtr - 1, simNativeStackPtr); } } if (numArgs > 1) { popToReg(simStackAt(simStackPtr), Arg1Reg); } if (numArgs > 0) { popToReg(simStackAt((simStackPtr - numArgs) + 1), Arg0Reg); } popToReg(simStackAt(simStackPtr - numArgs), ReceiverResultReg); } ssPop(numArgs + 1); } /* For assert checking; or rather for avoiding assert fails when dealing with the hack for block temps in the SqueakV3PlusClosures bytecode set. */ /* StackToRegisterMappingCogit>>#maybeCompilingFirstPassOfBlockWithInitialPushNil */ static sqInt maybeCompilingFirstPassOfBlockWithInitialPushNil(void) { return (inBlock == InVanillaBlock) && ((methodOrBlockNumTemps > methodOrBlockNumArgs) && (compilationPass == 1)); } /* If this bytecode has a fixup, some kind of merge needs to be done. There are 4 cases: 1) the bytecode has no fixup (fixup isNotAFixup) do nothing 2) the bytecode has a non merge fixup the fixup has needsNonMergeFixup. The code generating non merge fixup (currently only special selector code) is responsible for the merge so no need to do it. We set deadCode to false as the instruction can be reached from jumps. 3) the bytecode has a merge fixup, but execution flow *cannot* fall through to the merge point. the fixup has needsMergeFixup and deadCode = true. ignores the current simStack as it does not mean anything restores the simStack to the state the jumps to the merge point expects it to be. 4) the bytecode has a merge fixup and execution flow *can* fall through to the merge point. the fixup has needsMergeFixup and deadCode = false. flushes the stack to the stack pointer so the fall through execution path simStack is in the state the merge point expects it to be. restores the simStack to the state the jumps to the merge point expects it to be. In addition, if this is a backjump merge point, we patch the fixup to hold the current simStackPtr for later assertions. */ /* StackToRegisterMappingCogit>>#mergeWithFixupIfRequired: */ static sqInt NoDbgRegParms mergeWithFixupIfRequired(BytecodeFixup *fixup) { CogSimStackEntry * cascade0; sqInt i; sqInt i1; /* begin assertCorrectSimStackPtr */ assert((simSpillBase >= methodOrBlockNumTemps) || ((maybeCompilingFirstPassOfBlockWithInitialPushNil()) && (simSpillBase > methodOrBlockNumArgs))); if (needsFrame && (simSpillBase > 0)) { assert((((simStackAt(simSpillBase - 1))->spilled)) == 1); assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); } if (((fixup->targetInstruction)) == 0) { return 0; } if ((((usqInt)((fixup->targetInstruction)))) == NeedsNonMergeFixupFlag) { deadCode = 0; return 0; } assert(isMergeFixup(fixup)); traceMerge(fixup); if (deadCode) { /* case 3 */ /* Would like to assert fixup simStackPtr >= methodOrBlockNumTemps but can't because of the initialNils hack. */ assert((((fixup->simStackPtr)) >= methodOrBlockNumTemps) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); simStackPtr = (fixup->simStackPtr); } else { /* case 4 */ /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= simStackPtr) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < simStackPtr) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : simStackPtr)); i <= simStackPtr; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = simStackPtr + 1; } } deadCode = 0; if ((fixup->isTargetOfBackwardBranch)) { (fixup->simStackPtr = simStackPtr); } (fixup->targetInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC)); assert(simStackPtr == ((fixup->simStackPtr))); /* begin restoreSimStackAtMergePoint: */ ((simSelf())->liveRegister = NoReg); for (i1 = (methodOrBlockNumTemps + 1); i1 <= simStackPtr; i1 += 1) { cascade0 = simStackAt(i1); (cascade0->type = SSSpill); (cascade0->offset = FoxMFReceiver - ((i1 - methodOrBlockNumArgs) * BytesPerOop)); (cascade0->registerr = FPReg); (cascade0->spilled = 1); } simSpillBase = simStackPtr + 1; return 0; } /* StackToRegisterMappingCogit>>#methodAbortTrampolineFor: */ static sqInt NoDbgRegParms methodAbortTrampolineFor(sqInt numArgs) { return methodAbortTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* This is a hook for subclasses to filter out methods they can't deal with. */ /* Frameless methods with local temporaries cause problems, mostly in asserts, and yet they matter not at all for performance. Shun them. */ /* StackToRegisterMappingCogit>>#methodFoundInvalidPostScan */ static sqInt methodFoundInvalidPostScan(void) { if (!needsFrame) { return methodOrBlockNumTemps > methodOrBlockNumArgs; } return 0; } /* StackToRegisterMappingCogit>>#needsFrameIfMod16GENumArgs: */ static sqInt NoDbgRegParms needsFrameIfMod16GENumArgs(sqInt stackDelta) { return (byte0 % 16) >= methodOrBlockNumArgs; } /* As of August 2013, the code generator can't deal with spills in frameless methods (the issue is to do with the stack offset to get at an argument, which is changed when there's a spill). In e.g. TextColor>>#dominates: other ^other class == self class the second send of class needs also rto allocate a register that the first one used, but the first one's register can't be spilled. So avoid this by only allowing class to be sent if the stack contains a single element. */ /* StackToRegisterMappingCogit>>#needsFrameIfStackGreaterThanOne: */ static sqInt NoDbgRegParms needsFrameIfStackGreaterThanOne(sqInt stackDelta) { return stackDelta > 1; } /* StackToRegisterMappingCogit>>#numberOfSpillsInTopNItems: */ static sqInt NoDbgRegParms numberOfSpillsInTopNItems(sqInt n) { sqInt i; for (i = simStackPtr; i >= ((simStackPtr - n) + 1); i += -1) { if ((((simStackAt(i))->type)) == SSSpill) { return n - (simStackPtr - i); } } return 0; } /* StackToRegisterMappingCogit>>#picAbortTrampolineFor: */ static sqInt NoDbgRegParms picAbortTrampolineFor(sqInt numArgs) { return picAbortTrampolines[((numArgs < (2 /* numRegArgs */ + 1)) ? numArgs : (2 /* numRegArgs */ + 1))]; } /* StackToRegisterMappingCogit>>#prevInstIsPCAnnotated */ static sqInt prevInstIsPCAnnotated(void) { sqInt prevIndex; AbstractInstruction *prevInst; if (!(opcodeIndex > 0)) { return 0; } prevIndex = opcodeIndex - 1; while (1) { if (prevIndex <= 0) { return 0; } prevInst = abstractInstructionAt(prevIndex); if (isPCMappedAnnotation((!((prevInst->annotation)) ? 0 : (prevInst->annotation)))) { return 1; } if (!(((prevInst->opcode)) == Label)) break; prevIndex -= 1; } return 0; } /* Used to mark ReceiverResultReg as dead or not containing simSelf. Used when the simStack has already been flushed, e.g. for sends. */ /* StackToRegisterMappingCogit>>#receiverIsInReceiverResultReg */ static sqInt receiverIsInReceiverResultReg(void) { return (((simSelf())->liveRegister)) == ReceiverResultReg; } /* 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. */ /* StackToRegisterMappingCogit>>#reinitializeFixupsFrom:through: */ static void NoDbgRegParms reinitializeFixupsFromthrough(sqInt start, sqInt end) { BytecodeDescriptor *descriptor; sqInt distance; BytecodeFixup * fixup; sqInt nExts; sqInt pc; BytecodeFixup * self_in_reinitialize; sqInt targetPC; pc = start; nExts = 0; while (pc <= end) { /* begin reinitialize */ self_in_reinitialize = fixupAtIndex(pc - initialPC); (self_in_reinitialize->targetInstruction) = ((self_in_reinitialize->simStackPtr) = 0); byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((isBranch(descriptor)) && ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, pc, nExts, methodObj)) < 0))) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; /* begin initializeFixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); /* begin initializeFixup: */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); /* begin setIsBackwardBranchFixup */ (fixup->isTargetOfBackwardBranch) = 1; } if ((descriptor->isBlockCreation)) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); pc = (pc + ((descriptor->numBytes))) + distance; } else { pc += (descriptor->numBytes); } nExts = ((descriptor->isExtension) ? nExts + 1 : 0); } } /* Scan the block to determine if the block needs a frame or not */ /* StackToRegisterMappingCogit>>#scanBlock: */ static sqInt NoDbgRegParms scanBlock(BlockStart *blockStart) { BytecodeDescriptor *descriptor; sqInt end; sqInt framelessStackDelta; sqInt nExts; sqInt numPushNils; sqInt (* const numPushNilsFunction)(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt) = squeakV3orSistaV1NumPushNils; sqInt pc; sqInt pushingNils; needsFrame = 0; prevBCDescriptor = null; methodOrBlockNumArgs = (blockStart->numArgs); inBlock = InVanillaBlock; pc = (blockStart->startpc); end = ((blockStart->startpc)) + ((blockStart->span)); framelessStackDelta = (nExts = (extA = (numExtB = (extB = 0)))); pushingNils = 1; while (pc < end) { byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((descriptor->isExtension)) { loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } if (!needsFrame) { if ((((descriptor->needsFrameFunction)) == null) || (((descriptor->needsFrameFunction))(framelessStackDelta))) { needsFrame = 1; } else { framelessStackDelta += (descriptor->stackDelta); } } /* begin maybeNoteDescriptor:blockStart: */ if ((descriptor->isInstVarRef)) { (blockStart->hasInstVarRef = 1); } if (pushingNils && (!((descriptor->isExtension)))) { /* Count the initial number of pushed nils acting as temp initializers. We can't tell whether an initial pushNil is an operand reference or a temp initializer, except when the pushNil is a jump target (has a fixup), which never happens: self systemNavigation browseAllSelect: [:m| | ebc | (ebc := m embeddedBlockClosures select: [:ea| ea decompile statements first isMessage] thenCollect: [:ea| ea decompile statements first selector]) notEmpty and: [(#(whileTrue whileFalse whileTrue: whileFalse:) intersection: ebc) notEmpty]] or if the bytecode set has a push multiple nils bytecode. We simply count initial nils. Rarely we may end up over-estimating. We will correct by checking the stack depth at the end of the block in compileBlockBodies. */ if (((numPushNils = numPushNilsFunction(descriptor, pc, nExts, methodObj))) > 0) { assert((((descriptor->numBytes)) == 1) || (((descriptor->generator)) == genPushClosureTempsBytecode)); (blockStart->numInitialNils = ((blockStart->numInitialNils)) + numPushNils); } else { pushingNils = 0; } } /* begin nextBytecodePCFor:at:exts:in: */ pc = (pc + ((descriptor->numBytes))) + (((descriptor->isBlockCreation) ? ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj) : 0)); if ((descriptor->isExtension)) { nExts += 1; } else { nExts = (extA = (numExtB = (extB = 0))); } prevBCDescriptor = descriptor; } if (!needsFrame) { assert((framelessStackDelta >= 0) && (((blockStart->numInitialNils)) >= framelessStackDelta)); (blockStart->numInitialNils = ((blockStart->numInitialNils)) - framelessStackDelta); } return 0; } /* Scan the method (and all embedded blocks) to determine - what the last bytecode is; extra bytes at the end of a method are used to encode things like source pointers or temp names - if the method needs a frame or not - what are the targets of any backward branches. - how many blocks it creates Answer the block count or on error a negative error code */ /* StackToRegisterMappingCogit>>#scanMethod */ static sqInt scanMethod(void) { BytecodeDescriptor *descriptor; sqInt distance; BytecodeFixup * fixup; sqInt framelessStackDelta; sqInt latestContinuation; sqInt nExts; sqInt numBlocks; sqInt pc; sqInt seenInstVarStore; sqInt targetPC; needsFrame = (useTwoPaths = (seenInstVarStore = 0)); prevBCDescriptor = null; if ((primitiveIndex > 0) && (isQuickPrimitiveIndex(primitiveIndex))) { return 0; } pc = (latestContinuation = initialPC); numBlocks = (framelessStackDelta = (nExts = (extA = (numExtB = (extB = 0))))); while (pc <= endPC) { byte0 = (fetchByteofObject(pc, methodObj)) + bytecodeSetOffset; descriptor = generatorAt(byte0); if ((descriptor->isExtension)) { if (((descriptor->opcode)) == Nop) { /* unknown bytecode tag; see Cogit class>>#generatorTableFrom: */ return EncounteredUnknownBytecode; } loadSubsequentBytesForDescriptorat(descriptor, pc); ((descriptor->generator))(); } if (((descriptor->isReturn)) && (pc >= latestContinuation)) { endPC = pc; } if (!needsFrame) { if ((((descriptor->needsFrameFunction)) == null) || (((descriptor->needsFrameFunction))(framelessStackDelta))) { /* With immutability we win simply by avoiding a frame build if the receiver is young and not immutable. */ # if IMMUTABILITY if ((descriptor->is1ByteInstVarStore)) { useTwoPaths = 1; } else { needsFrame = 1; useTwoPaths = 0; } # else /* IMMUTABILITY */ needsFrame = 1; useTwoPaths = 0; # endif /* IMMUTABILITY */ } else { /* Without immutability we win if there are two or more stores and the receiver is new. */ framelessStackDelta += (descriptor->stackDelta); # if IMMUTABILITY # else /* IMMUTABILITY */ if ((descriptor->is1ByteInstVarStore)) { if (seenInstVarStore) { useTwoPaths = 1; } else { seenInstVarStore = 1; } } # endif /* IMMUTABILITY */ } } if (isBranch(descriptor)) { /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; if ((assert(((descriptor->spanFunction)) != null), (((descriptor->spanFunction))(descriptor, pc, nExts, methodObj)) < 0)) { /* begin initializeFixupAt: */ fixup = fixupAtIndex(targetPC - initialPC); /* begin initializeFixup: */ (fixup->targetInstruction) = ((AbstractInstruction *) NeedsMergeFixupFlag); /* begin setIsBackwardBranchFixup */ (fixup->isTargetOfBackwardBranch) = 1; } else { latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } } /* begin maybeDealWithUnsafeJumpForDescriptor:pc:latestContinuation: */ latestContinuation = latestContinuation; if ((descriptor->isBlockCreation)) { numBlocks += 1; /* begin spanFor:at:exts:in: */ distance = ((descriptor->spanFunction))(descriptor, pc, nExts, methodObj); targetPC = (pc + ((descriptor->numBytes))) + distance; latestContinuation = ((latestContinuation < targetPC) ? targetPC : latestContinuation); } pc += (descriptor->numBytes); nExts = ((descriptor->isExtension) ? nExts + 1 : (extA = (numExtB = (extB = 0)))); prevBCDescriptor = descriptor; } return numBlocks; } /* StackToRegisterMappingCogit>>#squeakV3orSistaV1PushNilSize:numInitialNils: */ static sqInt NoDbgRegParms squeakV3orSistaV1PushNilSizenumInitialNils(sqInt aMethodObj, sqInt numInitialNils) { return (methodUsesAlternateBytecodeSet(aMethodObj) ? /* begin sistaV1PushNilSize:numInitialNils: */ numInitialNils : numInitialNils); } /* StackToRegisterMappingCogit>>#squeakV3orSistaV1:Num:Push:Nils: */ static sqInt NoDbgRegParms squeakV3orSistaV1NumPushNils(BytecodeDescriptor *descriptor, sqInt pc, sqInt nExts, sqInt aMethodObj) { return (bytecodeSetOffset == 0 ? (((descriptor->generator)) == genPushConstantNilBytecode ? 1 : 0) : (/* begin sistaV1:Num:Push:Nils: */ (((descriptor->generator)) == genPushConstantNilBytecode ? 1 : 0))); } /* StackToRegisterMappingCogit>>#ssAllocateRequiredRegMask:upThrough:upThroughNative: */ static void NoDbgRegParms ssAllocateRequiredRegMaskupThroughupThroughNative(sqInt requiredRegsMask, sqInt stackPtr, sqInt nativeStackPtr) { sqInt i; sqInt i1; sqInt lastRequired; sqInt lastRequiredNative; sqInt liveRegs; lastRequired = -1; /* 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. */ lastRequiredNative = -1; /* begin registerMaskFor:and: */ liveRegs = (1U << FPReg) | (1U << SPReg); for (i = (((simSpillBase < 0) ? 0 : simSpillBase)); i <= stackPtr; i += 1) { liveRegs = liveRegs | (registerMask(simStackAt(i))); if ((registerMask(simStackAt(i))) & requiredRegsMask) { lastRequired = i; } } if (liveRegs & requiredRegsMask) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= lastRequired) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < lastRequired) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : lastRequired)); i1 <= lastRequired; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = lastRequired + 1; } assert(!(((liveRegisters()) & requiredRegsMask))); } } /* Any occurrences on the stack of the value being stored (which is the top of stack) must be flushed, and hence any values colder than them stack. */ /* StackToRegisterMappingCogit>>#ssFlushUpThroughReceiverVariable: */ static void NoDbgRegParms ssFlushUpThroughReceiverVariable(sqInt slotIndex) { sqInt i; sqInt index; /* begin ssFlushUpThrough: */ assert(simSpillBase >= 0); for (index = (simStackPtr - 1); index >= simSpillBase; index += -1) { if (((((simStackAt(index))->type)) == SSBaseOffset) && (((((simStackAt(index))->registerr)) == ReceiverResultReg) && ((((simStackAt(index))->offset)) == (slotOffsetOfInstVarIndex(slotIndex))))) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= index) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < index) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : index)); i <= index; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = index + 1; } goto l1; } } l1: /* end ssFlushUpThrough: */; } /* Any occurrences on the stack of the value being stored (which is the top of stack) must be flushed, and hence any values colder than them stack. */ /* StackToRegisterMappingCogit>>#ssFlushUpThroughTemporaryVariable: */ static void NoDbgRegParms ssFlushUpThroughTemporaryVariable(sqInt tempIndex) { sqInt i; sqInt index; sqInt offset; offset = ((simStackAt(tempIndex + 1))->offset); assert(offset == (frameOffsetOfTemporary(tempIndex))); /* begin ssFlushUpThrough: */ assert(simSpillBase >= 0); for (index = (simStackPtr - 1); index >= simSpillBase; index += -1) { if (((((simStackAt(index))->type)) == SSBaseOffset) && (((((simStackAt(index))->registerr)) == FPReg) && ((((simStackAt(index))->offset)) == offset))) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= index) { for (i = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < index) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : index)); i <= index; i += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i), frameOffsetOfTemporary(i - 1), FPReg); } simSpillBase = index + 1; } goto l1; } } l1: /* end ssFlushUpThrough: */; } /* StackToRegisterMappingCogit>>#ssPop: */ static void NoDbgRegParms ssPop(sqInt n) { sqInt i; assert(((simStackPtr - n) >= methodOrBlockNumTemps) || (((!needsFrame) && ((simStackPtr - n) >= 0)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil()))); simStackPtr -= n; /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); } /* StackToRegisterMappingCogit>>#ssPushAnnotatedConstant: */ static sqInt NoDbgRegParms ssPushAnnotatedConstant(sqInt literal) { AbstractInstruction *abstractInstruction; ssPushConstant(literal); /* begin annotateInstructionForBytecode */ if (prevInstIsPCAnnotated()) { /* begin Nop */ abstractInstruction = gen(Nop); } else { /* begin Label */ abstractInstruction = genoperandoperand(Label, (labelCounter += 1), bytecodePC); } (abstractInstruction->annotation = HasBytecodePC); return 0; } /* StackToRegisterMappingCogit>>#ssPushBase:offset: */ static sqInt NoDbgRegParms ssPushBaseoffset(sqInt reg, sqInt offset) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSBaseOffset); (cascade0->spilled = 0); (cascade0->registerr = reg); (cascade0->offset = offset); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushConstant: */ static sqInt NoDbgRegParms ssPushConstant(sqInt literal) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSConstant); (cascade0->spilled = 0); (cascade0->constant = literal); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushDesc: */ static sqInt NoDbgRegParms ssPushDesc(SimStackEntry simStackEntry) { sqInt i; if (((simStackEntry.type)) == SSSpill) { (simStackEntry.type = SSBaseOffset); } (simStackEntry.spilled = 0); (simStackEntry.bcptr = bytecodePC); simStack[(simStackPtr += 1)] = simStackEntry; /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPushRegister: */ static sqInt NoDbgRegParms ssPushRegister(sqInt reg) { CogSimStackEntry * cascade0; sqInt i; ssPush(1); cascade0 = ssTop(); (cascade0->type = SSRegister); (cascade0->spilled = 0); (cascade0->registerr = reg); (cascade0->bcptr = bytecodePC); /* begin updateSimSpillBase */ assert(((simSpillBase > methodOrBlockNumTemps) && (simStackPtr >= methodOrBlockNumTemps)) || (maybeCompilingFirstPassOfBlockWithInitialPushNil())); if (simSpillBase > simStackPtr) { simSpillBase = simStackPtr + 1; while (((simSpillBase - 1) > methodOrBlockNumTemps) && (!(((simStackAt(simSpillBase - 1))->spilled)))) { simSpillBase -= 1; } } else { while ((((simStackAt(simSpillBase))->spilled)) && (simSpillBase <= simStackPtr)) { simSpillBase += 1; } } for (i = (methodOrBlockNumTemps + 1); i <= ((((simSpillBase - 1) < simStackPtr) ? (simSpillBase - 1) : simStackPtr)); i += 1) { assert((((simStackAt(i))->spilled)) == 1); } assert((simSpillBase > simStackPtr) || ((((simStackAt(simSpillBase))->spilled)) == 0)); return 0; } /* StackToRegisterMappingCogit>>#ssPush: */ static void NoDbgRegParms ssPush(sqInt n) { simStackPtr += n; } /* StackToRegisterMappingCogit>>#ssSelfDescriptor */ static SimStackEntry ssSelfDescriptor(void) { return simStack[0]; } /* In addition to ssStorePop:toReg:, if this is a store and not a popInto I change the simulated stack to use the register for the top value */ /* StackToRegisterMappingCogit>>#ssStoreAndReplacePop:toReg: */ static void NoDbgRegParms ssStoreAndReplacePoptoReg(sqInt popBoolean, sqInt reg) { char topSpilled; topSpilled = ((ssTop())->spilled); ssStorePoptoReg(popBoolean || (topSpilled), reg); if (!popBoolean) { if (!topSpilled) { ssPop(1); } ssPushRegister(reg); } } /* Store or pop the top simulated stack entry to a register. Use preferredReg if the entry is not itself a register. Answer the actual register the result ends up in. */ /* StackToRegisterMappingCogit>>#ssStorePop:toPreferredReg: */ static sqInt NoDbgRegParms ssStorePoptoPreferredReg(sqInt popBoolean, sqInt preferredReg) { sqInt actualReg; actualReg = preferredReg; if ((((ssTop())->type)) == SSRegister) { assert(!(((ssTop())->spilled))); actualReg = ((ssTop())->registerr); } ssStorePoptoReg(popBoolean, actualReg); return actualReg; } /* Store or pop the top simulated stack entry to a register. N.B.: popToReg: and storeToReg: does not generate anything if it moves a register to the same register. */ /* StackToRegisterMappingCogit>>#ssStorePop:toReg: */ static void NoDbgRegParms ssStorePoptoReg(sqInt popBoolean, sqInt reg) { if (popBoolean) { popToReg(ssTop(), reg); ssPop(1); } else { storeToReg(ssTop(), reg); } } /* StackToRegisterMappingCogit>>#ssTop */ static CogSimStackEntry * ssTop(void) { return simStackAt(simStackPtr); } /* StackToRegisterMappingCogit>>#ssValue: */ static CogSimStackEntry * NoDbgRegParms ssValue(sqInt n) { return simStackAt(simStackPtr - n); } /* StackToRegisterMappingCogit>>#stackEntryIsBoolean: */ static sqInt NoDbgRegParms stackEntryIsBoolean(CogSimStackEntry *simStackEntry) { return (((simStackEntry->type)) == SSConstant) && ((((simStackEntry->constant)) == (trueObject())) || (((simStackEntry->constant)) == (falseObject()))); } /* Answer if the stack is valid up to, but not including, simSpillBase. */ /* StackToRegisterMappingCogit>>#tempsValidAndVolatileEntriesSpilled */ static sqInt tempsValidAndVolatileEntriesSpilled(void) { sqInt culprit; sqInt i; culprit = 0; for (i = 1; i <= methodOrBlockNumTemps; i += 1) { if (!(((((simStackAt(i))->type)) == SSBaseOffset) || (maybeCompilingFirstPassOfBlockWithInitialPushNil()))) { if (!(culprit)) { culprit = i; } return 0; } } for (i = (methodOrBlockNumTemps + 1); i < simSpillBase; i += 1) { if (!(((simStackAt(i))->spilled))) { if (!(culprit)) { culprit = i; } return 0; } } return 1; } /* If the sequence of bytecodes is push: (Array new: 1) popIntoTemp: tempIndex pushConstant: const or pushTemp: n popIntoTemp: 0 inVectorAt: tempIndex collapse this into tempAt: tempIndex put: {const or temp} and answer true, otherwise answer false. One might think that we should look for a sequence of more than one pushes and pops but this is extremely rare. Exclude pushRcvr: n to avoid potential complications with context inst vars. */ /* StackToRegisterMappingCogit>>#tryCollapseTempVectorInitializationOfSize: */ static sqInt NoDbgRegParms tryCollapseTempVectorInitializationOfSize(sqInt slots) { sqInt pc; sqInt pc1; sqInt pc2; BytecodeDescriptor *pushArrayDesc; BytecodeDescriptor *pushValueDesc; sqInt reg; sqInt remoteTempIndex; BytecodeDescriptor *storeArrayDesc; BytecodeDescriptor *storeValueDesc; sqInt tempIndex; if (slots != 1) { return 0; } /* begin generatorForPC: */ pushArrayDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(bytecodePC, methodObj))); assert(((pushArrayDesc->generator)) == genPushNewArrayBytecode); /* begin generatorForPC: */ pc = bytecodePC + ((pushArrayDesc->numBytes)); storeArrayDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc, methodObj))); if (((storeArrayDesc->generator)) == genStoreAndPopTemporaryVariableBytecode) { tempIndex = (fetchByteofObject(bytecodePC + ((pushArrayDesc->numBytes)), methodObj)) & 7; } else { if (!(((storeArrayDesc->generator)) == genLongStoreAndPopTemporaryVariableBytecode)) { return 0; } tempIndex = fetchByteofObject((bytecodePC + ((pushArrayDesc->numBytes))) + 1, methodObj); } /* begin generatorForPC: */ pc1 = (bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes)); pushValueDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc1, methodObj))); if (!((((pushValueDesc->generator)) == genPushLiteralConstantBytecode) || ((((pushValueDesc->generator)) == genPushQuickIntegerConstantBytecode) || (((pushValueDesc->generator)) == genPushTemporaryVariableBytecode)))) { return 0; } /* begin generatorForPC: */ pc2 = ((bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes)); storeValueDesc = generatorAt(bytecodeSetOffset + (fetchByteofObject(pc2, methodObj))); remoteTempIndex = fetchByteofObject((((bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes))) + 2, methodObj); if (!((((storeValueDesc->generator)) == genStoreAndPopRemoteTempLongBytecode) && (tempIndex == remoteTempIndex))) { return 0; } genNewArrayOfSizeinitialized(1, 0); evaluateat(pushValueDesc, (bytecodePC + ((pushArrayDesc->numBytes))) + ((storeArrayDesc->numBytes))); reg = ssStorePoptoPreferredReg(1, TempReg); genStoreSourceRegslotIndexintoNewObjectInDestReg(reg, 0, ReceiverResultReg); ssPushRegister(ReceiverResultReg); evaluateat(storeArrayDesc, bytecodePC + ((pushArrayDesc->numBytes))); /* + pushArrayDesc numBytes this gets added by nextBytecodePCFor:at:exts:in: */ bytecodePC = ((bytecodePC + ((storeArrayDesc->numBytes))) + ((pushValueDesc->numBytes))) + ((storeValueDesc->numBytes)); return 1; } /* StackToRegisterMappingCogit>>#violatesEnsureSpilledSpillAssert */ static sqInt violatesEnsureSpilledSpillAssert(void) { return 1; } /* Used when ReceiverResultReg is allocated for other than simSelf, and there may be references to ReceiverResultReg which need to be spilled. */ /* StackToRegisterMappingCogit>>#voidReceiverResultRegContainsSelf */ static void voidReceiverResultRegContainsSelf(void) { sqInt i; sqInt i1; sqInt spillIndex; /* begin voidReceiverOptStatus */ ((simSelf())->liveRegister = NoReg); spillIndex = 0; for (i = ((((methodOrBlockNumTemps + 1) < simSpillBase) ? simSpillBase : (methodOrBlockNumTemps + 1))); i <= simStackPtr; i += 1) { if ((registerOrNone(simStackAt(i))) == ReceiverResultReg) { spillIndex = i; } } if (spillIndex > 0) { /* begin ssFlushTo: */ assert(tempsValidAndVolatileEntriesSpilled()); if (simSpillBase <= spillIndex) { for (i1 = (((((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) < spillIndex) ? ((((((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) < simStackPtr) ? (((simSpillBase < (methodOrBlockNumTemps + 1)) ? (methodOrBlockNumTemps + 1) : simSpillBase)) : simStackPtr)) : spillIndex)); i1 <= spillIndex; i1 += 1) { assert(needsFrame); ensureSpilledAtfrom(simStackAt(i1), frameOffsetOfTemporary(i1 - 1), FPReg); } simSpillBase = spillIndex + 1; } } }
違いを見つける