· 9 years ago · Dec 14, 2016, 02:54 AM
1#ifndef COOKEE_VM
2#define COOKEE_VM
3
4///////////////////////////////////////////////////////////////////////
5// CONFIGURATION
6///////////////////////////////////////////////////////////////////////
7
8// Uses a label-as-value extension of some C compilers(GCC, LLVM).
9// Disable this if the compiler does not support the extension. Disabling this will considerably increate the build time of
10// the VM, but the interpreter will be fully standards compilant.
11#define COOKEE_INLINE_THREADING
12
13// Enables asserts and some information printing for debugging the VM.
14#define COOKEE_DEBUG
15
16// Prints out execution information(every executed instruction, frame entering/leaving, etc.).
17// If you enable this you alse have to enable COOKEE_DEBUG.
18#define COOKEE_DEBUG_PRINT_EXEC
19
20// Prints out allocation information(every performed allocation, heap resize info, etc.).
21// If you enable this you alse have to enable COOKEE_DEBUG.
22//#define COOKEE_DEBUG_PRINT_ALLOC
23
24// Prints out data information(all loaded methods and their code, classes, etc.).
25// If you enable this you alse have to enable COOKEE_DEBUG.
26//#define COOKEE_DEBUG_PRINT_DATA
27
28// Prints out optimizer information(all optimized method code, optimization events, etc.).
29// If you enable this you alse have to enable COOKEE_DEBUG.
30#define COOKEE_DEBUG_PRINT_OPTIMIZER
31
32///////////////////////////////////////////////////////////////////////
33// COOKEE DEFS
34///////////////////////////////////////////////////////////////////////
35
36#define COOKEE_INSTANCE_HEADER_SIZE (sizeof(int) * 2)
37#define COOKEE_INSTANCE_PARTITION_SIZE (sizeof(int) * 2)
38
39///////////////////////////////////////////////////////////////////////
40// COOKEE TYPES
41///////////////////////////////////////////////////////////////////////
42
43typedef unsigned int CookeeBool;
44typedef unsigned int CookeeChar;
45typedef signed int CookeeInt;
46typedef signed long long int CookeeLong;
47typedef float CookeeFloat;
48typedef double CookeeDouble;
49typedef unsigned long long int CookeeObject;
50
51// List of cookee language types.
52typedef enum CookeeType CookeeType;
53enum CookeeType {
54 $COOKEE_TYPE_BOOL,
55 $COOKEE_TYPE_CHAR,
56 $COOKEE_TYPE_INT,
57 $COOKEE_TYPE_LONG,
58 $COOKEE_TYPE_FLOAT,
59 $COOKEE_TYPE_DOUBLE,
60 $COOKEE_TYPE_OBJECT
61};
62
63#define COOKEE_TYPE_N 7
64
65static inline CookeeInt CookeeTypeSize(const CookeeType type) {
66 static const CookeeInt SIZES[COOKEE_TYPE_N] = {
67 sizeof(CookeeBool),
68 sizeof(CookeeChar),
69 sizeof(CookeeInt),
70 sizeof(CookeeLong),
71 sizeof(CookeeFloat),
72 sizeof(CookeeDouble),
73 sizeof(CookeeObject)
74 };
75
76 #ifdef COOKEE_DEBUG
77 if(type > COOKEE_TYPE_N) {
78 return 0;
79 }
80 #endif
81
82 return SIZES[type];
83}
84
85static inline const char* CookeeTypeName(const CookeeType type) {
86 static const char* const NAMES[COOKEE_TYPE_N] = {
87 "bool", "char", "int", "long", "float", "double", "Object"
88 };
89
90 if(type > COOKEE_TYPE_N) {
91 return "INVALID";
92 }
93 return NAMES[type];
94}
95
96// All allocation types of objects.
97typedef enum CookeeAllocationType CookeeAllocationType;
98enum CookeeAllocationType {
99 $COOKEE_ALLOCATION_TYPE_NEW,
100 $COOKEE_ALLOCATION_TYPE_OLD,
101 $COOKEE_ALLOCATION_TYPE_TMP,
102 $COOKEE_ALLOCATION_TYPE_UNMANAGED
103 // TODO: global type
104};
105
106#define COOKEE_ALLOCATION_TYPE_N 4
107
108// Represents a handle to data context containing loaded class, field, method and literal data.
109typedef void CookeeData;
110
111// Represents a handle to garbage collection context in which all allocations happen.
112typedef void CookeeGc;
113
114// Represents a handle to cookee code execution context.
115typedef void CookeeContext;
116
117// Represents a cookee class handle.
118typedef void CookeeClass;
119
120// Represents a cookee field handle.
121typedef void CookeeField;
122
123// Represents a cookee method handle.
124typedef void CookeeMethod;
125
126// Represents a cookee parameter variable handle.
127typedef void CookeeParameter;
128
129// Represents a cookee stack frame crawler handle.
130typedef void CookeeStackCrawler;
131
132// Represents a signed value within cookee code.
133typedef signed int CookeeCodeValue;
134
135// Function which should create and return an instance of text class based on the data provided.
136typedef CookeeObject(*CookeeCreateTextFunction)(CookeeContext* contextHandle,
137 CookeeChar* chars,
138 CookeeInt length);
139
140// Function which should compare two objects of the same class for equality.
141typedef CookeeBool(*CookeeEqualsFunction)(CookeeContext* contextHandle,
142 CookeeObject object1,
143 CookeeObject object2);
144
145// Function which receives a callback from the GC when the cycle starts and when it ends with information about the GC cycle.
146typedef void(*CookeeGcCycleFunction)(CookeeInt allocatedByteCount);
147
148// Function which executes a crumb's code.
149typedef void(*CookeeCrumbFunction)(CookeeContext* contextHandle,
150 char* locals,
151 const CookeeLong* longs,
152 const CookeeDouble* doubles);
153
154// List of cookee method binding function declarations.
155// Sequence index, sequence length, this
156
157typedef void(*CookeeMethodBinding)();
158
159typedef CookeeBool(*CookeeBoolMethodBinding)(CookeeContext* contextHandle,
160 const CookeeMethod* methodHandle,
161 CookeeObject thisHandle,
162 const CookeeInt* paramOffsets,
163 char* args);
164
165typedef CookeeChar(*CookeeCharMethodBinding)(CookeeContext* contextHandle,
166 const CookeeMethod* methodHandle,
167 CookeeObject thisHandle,
168 const CookeeInt* paramOffsets,
169 char* args);
170
171typedef CookeeInt(*CookeeIntMethodBinding)(CookeeContext* contextHandle,
172 const CookeeMethod* methodHandle,
173 CookeeObject thisHandle,
174 const CookeeInt* paramOffsets,
175 char* args);
176
177typedef CookeeLong(*CookeeLongMethodBinding)(CookeeContext* contextHandle,
178 const CookeeMethod* methodHandle,
179 CookeeObject thisHandle,
180 const CookeeInt* paramOffsets,
181 char* args);
182
183typedef CookeeFloat(*CookeeFloatMethodBinding)(CookeeContext* contextHandle,
184 const CookeeMethod* methodHandle,
185 CookeeObject thisHandle,
186 const CookeeInt* paramOffsets,
187 char* args);
188
189typedef CookeeDouble(*CookeeDoubleMethodBinding)(CookeeContext* contextHandle,
190 const CookeeMethod* methodHandle,
191 CookeeObject thisHandle,
192 const CookeeInt* paramOffsets,
193 char* args);
194
195typedef CookeeObject(*CookeeObjectMethodBinding)(CookeeContext* contextHandle,
196 const CookeeMethod* methodHandle,
197 CookeeObject thisHandle,
198 const CookeeInt* paramOffsets,
199 char* args);
200
201typedef CookeeObject(*CookeeSequentialMethodBinding)(CookeeContext* contextHandle,
202 const CookeeMethod* methodHandle,
203 CookeeObject thisHandle,
204 const CookeeInt* paramOffsets,
205 char* args,
206 CookeeInt sqi,
207 CookeeInt sql);
208
209///////////////////////////////////////////////////////////////////////
210// COOKEE LITERALS
211///////////////////////////////////////////////////////////////////////
212
213#define COOKEE_NULL ((CookeeObject) 0)
214#define COOKEE_FALSE ((CookeeBool) 0)
215#define COOKEE_TRUE ((CookeeBool) 1)
216
217///////////////////////////////////////////////////////////////////////
218// DATA INTERFACE
219///////////////////////////////////////////////////////////////////////
220
221// Load cookee data from the given bytes.
222extern CookeeData* CookeeLoad(const char* bytes, const char* endPtr);
223
224// Returns true if the data is in use by any of created cookee contexts.
225extern CookeeBool CookeeIsDataInUse(CookeeData* dataHandle);
226
227// Unload the cookee data.
228// Note that the data can only be unloaded when it is no longer in use by any cookee context.
229extern void CookeeUnload(CookeeData* dataHandle);
230
231// Returns a class with specified signature or NULL if not found.
232extern CookeeClass* CookeeFindClass(CookeeData* dataHandle, const char* signature);
233
234// Returns a field with specified signature or NULL if not found.
235extern CookeeField* CookeeFindField(CookeeData* dataHandle, const char* signature);
236
237// Returns a method with specified signature or NULL if not found.
238extern CookeeMethod* CookeeFindMethod(CookeeData* dataHandle, const char* signature);
239
240// Returns a field with specified name or NULL if not found.
241extern CookeeField* CookeeFindClassFieldByName(CookeeData* dataHandle, CookeeClass* classHandle, const char* name);
242
243// Returns a field with specified signature or NULL if not found.
244extern CookeeField* CookeeFindClassField(CookeeData* dataHandle, CookeeClass* classHandle, const char* signature);
245
246// Returns a method with specified signature or NULL if not found.
247extern CookeeMethod* CookeeFindClassMethod(CookeeData* dataHandle, CookeeClass* classHandle, const char* signature);
248
249// Returns the number of classes that has been loaded.
250extern CookeeInt CookeeClassCount(CookeeData* dataHandle);
251
252// Returns the class at specified index.
253extern CookeeClass* CookeeClassAtIndex(CookeeData* dataHandle, CookeeInt index);
254
255// Returns the number of fields that has been loaded.
256extern CookeeInt CookeeFieldCount(CookeeData* dataHandle);
257
258// Returns the field at specified index.
259extern CookeeField* CookeeFieldAtIndex(CookeeData* dataHandle, CookeeInt index);
260
261// Returns the number of methods that has been loaded.
262extern CookeeInt CookeeMethodCount(CookeeData* dataHandle);
263
264// Returns the method at specified index.
265extern CookeeMethod* CookeeMethodAtIndex(CookeeData* dataHandle, CookeeInt index);
266
267
268// Returns the index of the class inside data handle.
269extern CookeeInt CookeeClassIndex(CookeeData* dataHandle, CookeeClass* classHandle);
270
271// Returns the signature of the specified class.
272extern const char* CookeeClassSignature(CookeeData* dataHandle, CookeeClass* classHandle);
273
274// Returns the name of the specified class.
275extern const char* CookeeClassName(CookeeData* dataHandle, CookeeClass* classHandle);
276
277// Returns the super class which this class extends. Might be NULL.
278extern CookeeClass* CookeeClassSuper(CookeeData* dataHandle, CookeeClass* classHandle);
279
280// Returns the method which is used as implicit initializer of the given class' instances. Might be NULL.
281extern CookeeMethod* CookeeClassInitializer(CookeeData* dataHandle, CookeeClass* classHandle);
282
283// Returns the number of fields which are declared within the class.
284extern CookeeInt CookeeClassFieldCount(CookeeData* dataHandle, CookeeClass* classHandle);
285
286// Returns the field at specified index declared within the class.
287extern CookeeField* CookeeClassFieldAtIndex(CookeeData* dataHandle, CookeeClass* classHandle, CookeeInt index);
288
289// Returns the number of methods which are declared within the class.
290extern CookeeInt CookeeClassMethodCount(CookeeData* dataHandle, CookeeClass* classHandle);
291
292// Returns the method at specified index declared within the class.
293extern CookeeMethod* CookeeClassMethodAtIndex(CookeeData* dataHandle, CookeeClass* classHandle, CookeeInt index);
294
295// Returns the total number of temporary instances the specified class has, though they are not neccessarily allocated.
296extern CookeeInt CookeeClassTmpInstanceCount(CookeeData* dataHandle, CookeeClass* classHandle);
297
298// Returns COOKEE_TRUE if checkedClassHandle is part of specified class' hierarchy, COOKEE_FALSE otherwise.
299extern CookeeBool CookeeIsClassCompatible(CookeeClass* dataHandle, CookeeClass* classHandle, CookeeClass* checkedClassHandle);
300
301// Returns the index of the field inside data handle.
302extern CookeeInt CookeeFieldIndex(CookeeData* dataHandle, CookeeField* fieldHandle);
303
304// Returns the class in which this field is declared.
305extern CookeeClass* CookeeFieldParent(CookeeData* dataHandle, CookeeField* fieldHandle);
306
307// Returns the signature of the field.
308extern const char* CookeeFieldSignature(CookeeData* dataHandle, CookeeField* fieldHandle);
309
310// Returns the name of the field.
311extern const char* CookeeFieldName(CookeeData* dataHandle, CookeeField* fieldHandle);
312
313// Returns the base type of the field.
314extern CookeeType CookeeFieldType(CookeeData* dataHandle, CookeeField* fieldHandle);
315
316// Returns the class of the field's type. UB if the type is not an object.
317extern CookeeClass* CookeeFieldTypeClass(CookeeData* dataHandle, CookeeField* fieldHandle);
318
319// Returns the offset in bytes of the field in the parent class instances.
320extern CookeeInt CookeeFieldOffset(CookeeData* dataHandle, CookeeField* fieldHandle);
321
322
323// Returns the index of the method inside data handle.
324extern CookeeInt CookeeMethodIndex(CookeeData* dataHandle, CookeeMethod* methodHandle);
325
326// Returns the class in which this method is declared.
327extern CookeeClass* CookeeMethodParent(CookeeData* dataHandle, CookeeMethod* methodHandle);
328
329// Returns the signature of the method.
330extern const char* CookeeMethodSignature(CookeeData* dataHandle, CookeeMethod* methodHandle);
331
332// Returns the name of the method.
333extern const char* CookeeMethodName(CookeeData* dataHandle, CookeeMethod* methodHandle);
334
335// Returns the base return type of the method.
336extern CookeeType CookeeMethodReturnType(CookeeData* dataHandle, CookeeMethod* methodHandle);
337
338// Returns the class of the method's return type. UB if the type is not an object.
339extern CookeeClass* CookeeMethodReturnTypeClass(CookeeData* dataHandle, CookeeMethod* methodHandle);
340
341// Returns COOKEE_TRUE if the return type of the method is self, COOKEE_FALSE otherwise.
342extern CookeeBool CookeeMethodReturnsSelf(CookeeData* dataHandle, CookeeMethod* methodHandle);
343
344// Returns the binded function of the method. Might be NULL.
345extern CookeeMethodBinding CookeeMethodBindedFunction(CookeeData* dataHandle, CookeeMethod* methodHandle);
346
347// Returns the binded function's attachment. Might be NULL.
348extern void* CookeeMethodBindedAttachment(CookeeData* dataHandle, CookeeMethod* methodHandle);
349
350// Returns the method which this method overrides. Might be NULL.
351extern CookeeMethod* CookeeMethodSuper(CookeeData* dataHandle, CookeeMethod* methodHandle);
352
353// Returns the method's parameter with specified name or NULL if not found.
354extern CookeeParameter* CookeeMethodFindParameter(CookeeData* dataHandle, CookeeMethod* methodHandle, const char* name);
355
356// Returns the number of parameters the specified method has.
357extern CookeeInt CookeeMethodParameterCount(CookeeData* dataHandle, CookeeMethod* methodHandle);
358
359// Returns the method's parameter at specified index.
360extern CookeeParameter* CookeeMethodParameterAtIndex(CookeeData* dataHandle, CookeeMethod* methodHandle, CookeeInt index);
361
362
363// Returns the variable's name.
364extern const char* CookeeParameterName(CookeeData* dataHandle, CookeeParameter* variableHandle);
365
366// Returns the variable's base type.
367extern CookeeType CookeeParameterType(CookeeData* dataHandle, CookeeParameter* variableHandle);
368
369// Returns the class of the variable's type. UB if the type is not an object.
370extern CookeeClass* CookeeParameterTypeClass(CookeeData* dataHandle, CookeeParameter* variableHandle);
371
372// Returns the variable's offset within it's stack frame.
373extern CookeeInt CookeeParameterOffset(CookeeData* dataHandle, CookeeParameter* variableHandle);
374
375
376///////////////////////////////////////////////////////////////////////
377// GARBAGE COLLECTOR INTERFACE
378///////////////////////////////////////////////////////////////////////
379
380// Create an instance of cookee GC that can be used across multiple contexts on the same thread.
381extern CookeeGc* CookeeCreateGc(CookeeInt minHeapSize,
382 CookeeInt maxHeapSize,
383 CookeeInt expectedHeapSize,
384 CookeeInt maxLocalReferences);
385
386// Returns true if the GC is in use by any of created cookee contexts.
387extern CookeeBool CookeeIsGcInUse(CookeeGc* gcHandle);
388
389// Destroy the cookee GC instance.
390// Note that the GC can only be destroyed when it is no longed in use by any cookee context.
391extern void CookeeDestroyGc(CookeeGc* gcHandle);
392
393// Set the function to be called after each GC cycle receiving some information about the cycle.
394extern void CookeeSetGcCycleFunction(CookeeGc* gcHandle, CookeeGcCycleFunction cycleFunction);
395
396// Returns the number of currently live objects allocated in the given GC.
397extern CookeeInt CookeeGetAllocatedObjects(CookeeContext* contextHandle);
398
399// Returns the number of bytes currently allocated in the given GC.
400extern CookeeInt CookeeGetAllocatedBytes(CookeeContext* contextHandle);
401
402// Returns the number of free bytes that can be used for allocations.
403extern CookeeInt CookeeGetFreeBytes(CookeeContext* contextHandle);
404
405// Returns the current heap size.
406// Note that if the GC is a copying collector, this value will only represent half of actually allocated heap space.
407extern CookeeInt CookeeGetHeapSize(CookeeContext* contextHandle);
408
409// Triggers a garbage collection cycle.
410extern void CookeeTriggerGc(CookeeContext* contextHandle);
411
412// Shrinks the heap of the garbage collector if there's any unused space.
413extern void CookeeShrinkHeap(CookeeContext* contextHandle);
414
415// Locks the GC from performing garbage collection cycles or heap resizing.
416// This is useful if you want to be sure that no references will get invalidated.
417// Each lock call must be matched with unlock call or else the GC will stay locked.
418extern void CookeeLockGc(CookeeContext* contextHandle);
419
420// Potentially unlocks the GC allowing garbage collection cycles and heap resizing.
421extern void CookeeUnlockGc(CookeeContext* contextHandle);
422
423// Returns COOKEE_TRUE if the gc is currently locked, COOKEE_FALSE otherwise.
424extern CookeeBool CookeeIsGcLocked(CookeeContext* contextHandle);
425
426// Push a local reference to the GC automatically updating it's reference during garbage collection cycle and heap resizing.
427extern void CookeePushLocalRef(CookeeContext* contextHandle, CookeeObject* slot);
428
429// Pop the last pushed local reference from the GC.
430extern void CookeePopLocalRef(CookeeContext* contextHandle);
431
432// Pop the specified amount of local reference from the end of the GC's list.
433extern void CookeePopLocalRefs(CookeeContext* contextHandle, CookeeInt amount);
434
435///////////////////////////////////////////////////////////////////////
436// CONTEXT INTERFACE
437///////////////////////////////////////////////////////////////////////
438
439// Creates a new cookee execution context.
440extern CookeeContext* CookeeCreateContext(CookeeData* dataHandle,
441 CookeeGc* gcHandle,
442 const char* starterClassSignature,
443 CookeeInt stackSize);
444
445// Triggers the execution of the context's starter class.
446extern CookeeBool CookeeExecuteContext(CookeeContext* contextHandle);
447
448// TODO: callback execution or switch interpreters(callback before executing each opcode)
449
450// Crashes the context with specified description message.
451// If the context is already crashed this call is ignored.
452extern void CookeePanic(CookeeContext* contextHandle, const char* message, ...);
453
454// Returns true if the context is currently crashed, false otherwise.
455extern CookeeBool CookeeIsContextCrashed(CookeeContext* contextHandle);
456
457// Returns the crash message of context. If the context is not crashed returns NULL.
458extern const char* CookeeGetCrashMessage(CookeeContext* contextHandle);
459
460// Returns the cookee data that is used by the context.
461extern CookeeData* CookeeContextData(CookeeContext* contextHandle);
462
463// Returns the GC that is used by the context.
464extern CookeeGc* CookeeContextGc(CookeeContext* contextHandle);
465
466// Destroys the execution context.
467extern void CookeeDestroyContext(CookeeContext* contextHandle);
468
469// TODO: is executing
470
471///////////////////////////////////////////////////////////////////////
472// BINDING INTERFACE
473///////////////////////////////////////////////////////////////////////
474
475// Binds text creation function to data.
476extern void CookeeBindCreateTextFunction(CookeeData* dataHandle,
477 CookeeCreateTextFunction createTextFunction,
478 void* attachment);
479
480// Binds equality comparison function to specific class.
481extern void CookeeBindEqualsFunction(CookeeData* dataHandle,
482 CookeeClass* class,
483 CookeeEqualsFunction equalityFunction,
484 void* attachment);
485
486// Removes create text function from data.
487extern void CookeeUnbindCreateTextFunction(CookeeData* dataHandle);
488
489// Removes equality comparison function binding from a class.
490extern void CookeeUnbindEqualsFunction(CookeeData* dataHandle, CookeeClass* class);
491
492// Binds a native implementation to the method.
493extern void CookeeBindMethod(CookeeData* dataHandle,
494 CookeeMethod* methodHandle,
495 CookeeMethodBinding binding,
496 void* attachment);
497
498extern void CookeeBindBoolMethod(CookeeData* dataHandle,
499 CookeeMethod* methodHandle,
500 CookeeBoolMethodBinding binding,
501 void* attachment);
502
503extern void CookeeBindCharMethod(CookeeData* dataHandle,
504 CookeeMethod* methodHandle,
505 CookeeCharMethodBinding binding,
506 void* attachment);
507
508extern void CookeeBindIntMethod(CookeeData* dataHandle,
509 CookeeMethod* methodHandle,
510 CookeeIntMethodBinding binding,
511 void* attachment);
512
513extern void CookeeBindLongMethod(CookeeData* dataHandle,
514 CookeeMethod* methodHandle,
515 CookeeLongMethodBinding binding,
516 void* attachment);
517
518extern void CookeeBindFloatMethod(CookeeData* dataHandle,
519 CookeeMethod* methodHandle,
520 CookeeFloatMethodBinding binding,
521 void* attachment);
522
523extern void CookeeBindDoubleMethod(CookeeData* dataHandle,
524 CookeeMethod* methodHandle,
525 CookeeDoubleMethodBinding binding,
526 void* attachment);
527
528extern void CookeeBindObjectMethod(CookeeData* dataHandle,
529 CookeeMethod* methodHandle,
530 CookeeObjectMethodBinding binding,
531 void* attachment);
532
533extern void CookeeBindSequentialMethod(CookeeData* dataHandle,
534 CookeeMethod* methodHandle,
535 CookeeSequentialMethodBinding binding,
536 void* attachment);
537
538// Removes a native implementation from the method.
539extern void CookeeUnbindMethod(CookeeData* dataHandle, CookeeMethod* methodHandle);
540
541// Returns the offset within args array of a parameter.
542static inline CookeeBool CookeeBoolArg(const CookeeMethod* const method,
543 const CookeeInt* const paramOffsets,
544 char* const args,
545 const CookeeInt paramIndex) {
546
547 return *((CookeeBool*)(args + paramOffsets[paramIndex]));
548}
549
550static inline CookeeChar CookeeCharArg(const CookeeMethod* const method,
551 const CookeeInt* const paramOffsets,
552 char* const args,
553 const CookeeInt paramIndex) {
554
555 return *((CookeeChar*)(args + paramOffsets[paramIndex]));
556}
557
558static inline CookeeInt CookeeIntArg(const CookeeMethod* const method,
559 const CookeeInt* const paramOffsets,
560 char* const args,
561 const CookeeInt paramIndex) {
562
563 return *((CookeeInt*)(args + paramOffsets[paramIndex]));
564}
565
566static inline CookeeLong CookeeLongArg(const CookeeMethod* const method,
567 const CookeeInt* const paramOffsets,
568 char* const args,
569 const CookeeInt paramIndex) {
570
571 return *((CookeeLong*)(args + paramOffsets[paramIndex]));
572}
573
574static inline CookeeFloat CookeeFloatArg(const CookeeMethod* const method,
575 const CookeeInt* const paramOffsets,
576 char* const args,
577 const CookeeInt paramIndex) {
578
579 return *((CookeeFloat*)(args + paramOffsets[paramIndex]));
580}
581
582static inline CookeeDouble CookeeDoubleArg(const CookeeMethod* const method,
583 const CookeeInt* const paramOffsets,
584 char* const args,
585 const CookeeInt paramIndex) {
586
587 return *((CookeeDouble*)(args + paramOffsets[paramIndex]));
588}
589
590static inline CookeeObject CookeeObjectArg(const CookeeMethod* const method,
591 const CookeeInt* const paramOffsets,
592 char* const args,
593 const CookeeInt paramIndex) {
594
595 return *((CookeeObject*)(args + paramOffsets[paramIndex]));
596}
597
598// Returns the binding attachment of the native frame function.
599extern void* CookeeAttachment(CookeeContext* contextHandle);
600
601extern void CookeePushNativeFrame(CookeeContext* contextHandle,
602 const CookeeMethod* methodHandle,
603 CookeeObject thisHandle);
604
605extern void CookeePushNativeSequentialFrame(CookeeContext* contextHandle,
606 const CookeeMethod* methodHandle,
607 CookeeObject thisHandle,
608 CookeeInt sqi,
609 CookeeInt sql);
610
611extern void CookeePopNativeFrame(CookeeContext* contextHandle);
612
613///////////////////////////////////////////////////////////////////////
614// STACK FRAME INTERFACE
615///////////////////////////////////////////////////////////////////////
616
617// Creates a new instance of cookee stack crawler.
618extern CookeeStackCrawler* CookeeNewStackCrawler(CookeeContext* contextHandle);
619
620// Deletes an instance of cookee stack crawler.
621extern void CookeeDeleteStackCrawler(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
622
623// Moves the stack crawler one frame up the stack.
624extern CookeeBool CookeeCrawlUp(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
625
626// Returns the frame's method.
627extern CookeeMethod* CookeeFrameMethod(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
628
629// Returns the frame's location in source code.
630extern CookeeInt CookeeFrameLocation(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
631
632// Returns the frame's sequence index.
633extern CookeeInt CookeeFrameSequenceIndex(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
634
635// Returns the frame's sequence length.
636extern CookeeInt CookeeFrameSequenceLength(CookeeContext* contextHandle, CookeeStackCrawler* crawlerHandle);
637
638// Returns the current frame's sequence index.
639extern CookeeInt CookeeSequenceIndex(CookeeContext* contextHandle);
640
641// Returns the current frame's sequence length.
642extern CookeeInt CookeeSequenceLength(CookeeContext* contextHandle);
643
644///////////////////////////////////////////////////////////////////////
645// FIELD INTERFACE
646///////////////////////////////////////////////////////////////////////
647
648// Get direct field ptr
649
650// Sets the value of given field in the object.
651extern void CookeeSetBoolFieldValue(CookeeContext* contextHandle,
652 CookeeField* fieldHandle,
653 CookeeObject object,
654 CookeeBool value);
655
656extern void CookeeSetCharFieldValue(CookeeContext* contextHandle,
657 CookeeField* fieldHandle,
658 CookeeObject object,
659 CookeeChar value);
660
661extern void CookeeSetIntFieldValue(CookeeContext* contextHandle,
662 CookeeField* fieldHandle,
663 CookeeObject object,
664 CookeeInt value);
665
666extern void CookeeSetLongFieldValue(CookeeContext* contextHandle,
667 CookeeField* fieldHandle,
668 CookeeObject object,
669 CookeeLong value);
670
671extern void CookeeSetFloatFieldValue(CookeeContext* contextHandle,
672 CookeeField* fieldHandle,
673 CookeeObject object,
674 CookeeFloat value);
675
676extern void CookeeSetDoubleFieldValue(CookeeContext* contextHandle,
677 CookeeField* fieldHandle,
678 CookeeObject object,
679 CookeeDouble value);
680
681extern void CookeeSetObjectFieldValue(CookeeContext* contextHandle,
682 CookeeField* fieldHandle,
683 CookeeObject object,
684 CookeeObject value);
685
686// Gets a value of given field in the object.
687extern CookeeBool CookeeGetBoolFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
688extern CookeeChar CookeeGetCharFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
689extern CookeeInt CookeeGetIntFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
690extern CookeeLong CookeeGetLongFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
691extern CookeeFloat CookeeGetFloatFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
692extern CookeeDouble CookeeGetDoubleFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
693extern CookeeObject CookeeGetObjectFieldValue(CookeeContext* contextHandle, CookeeField* fieldHandle, CookeeObject object);
694
695///////////////////////////////////////////////////////////////////////
696// METHOD INTERFACE
697///////////////////////////////////////////////////////////////////////
698
699extern char* CookeeGenerateCrumbCode(CookeeContext* contextHandle,
700 CookeeMethod* methodHandle,
701 const char* bindFunctionName,
702 const char* executeFunctionName,
703 CookeeBool generateTypedefs,
704 CookeeBool includeCalls);
705
706extern void CookeeBindCrumb(CookeeContext* contextHandle,
707 CookeeMethod* methodHandle,
708 void(*crumbBindFunc)(),
709 CookeeCrumbFunction crumbExecuteFunction);
710
711///////////////////////////////////////////////////////////////////////
712// CLASS INTERFACE
713///////////////////////////////////////////////////////////////////////
714
715// Returns the global instance of specified class.
716extern CookeeObject CookeeGlobalVariable(CookeeContext* contextHandle, CookeeClass* classHandle);
717
718// Checks if the specified object is instance of specified class.
719extern CookeeBool CookeeIsInstanceOf(CookeeContext* contextHandle, CookeeClass* classHandle, CookeeObject object);
720
721// TODO: clear old pool
722// TODO: clear tmp list
723// TODO: get instance size
724// TODO: get allocated tmp instance count
725// TODO: get free list size
726
727// Returns the binded equality function of a specific class or NULL if no function is binded.
728extern CookeeEqualsFunction CookeeClassEqualsFunction(CookeeContext* contextHandle, CookeeClass* classHandle);
729
730// Return the attachment of the equality function of specific class.
731extern void* CookeeClassEqualsFunctionAttachment(CookeeContext* contextHandle, CookeeClass* classHandle);
732
733///////////////////////////////////////////////////////////////////////
734// OBJECT INTERFACE
735///////////////////////////////////////////////////////////////////////
736
737// Returns the class of specified object.
738extern CookeeClass* CookeeObjectClass(CookeeContext* contextHandle, CookeeObject object);
739
740// Allocates a new instance of specified class and returns it.
741extern CookeeObject CookeeNewObject(CookeeContext* contextHandle, CookeeClass* classHandle);
742extern CookeeObject CookeeOldObject(CookeeContext* contextHandle, CookeeClass* classHandle);
743
744extern CookeeInt CookeeUnmanagedObjectSize(CookeeClass* classHandle);
745extern CookeeObject CookeeInitUnmanagedObject(CookeeClass* classHandle, void* ptr);
746
747extern CookeeObject CookeeMallocObject(CookeeClass* classHandle);
748extern CookeeObject CookeeCallocObject(CookeeClass* classHandle);
749extern CookeeBool CookeeFreeObject(CookeeContext* contextHandle, CookeeObject object);
750extern CookeeBool CookeeFreeUnmanaged(CookeeObject instance);
751
752static inline CookeeObject CookeePtrToObject(void* const ptr) {
753 return ptr == (void*) 0 ? COOKEE_NULL : (CookeeObject)((char*) ptr + COOKEE_INSTANCE_HEADER_SIZE);
754}
755
756static inline void* CookeeObjectToPtr(const CookeeObject object) {
757 return object == COOKEE_NULL ? (void*) 0 : (void*)((char*) object - COOKEE_INSTANCE_HEADER_SIZE);
758}
759
760// Returns COOKEE_TRUE if both objects are equal COOKEE_FALSE otherwise.
761// If both objects are instances of the same class and there's an equality function provided for that class,
762// then uses that function to compare the objects.
763extern CookeeBool CookeeObjectIs(CookeeContext* contextHandle, CookeeObject object1, CookeeObject object2);
764
765// Returns COOKEE_TRUE if objects are not equal to each other COOKEE_FALSE otherwise.
766// If both objects are instances of the same class and there's an equality function provided for that class,
767// then uses that function to compare the objects.
768extern CookeeBool CookeeObjectIsnt(CookeeContext* contextHandle, CookeeObject object1, CookeeObject object2);
769
770///////////////////////////////////////////////////////////////////////
771// ARRAY INTERFACE
772///////////////////////////////////////////////////////////////////////
773
774// Creates a new array instance of given type and length.
775// Note that garbage collection can happen while allocating the array.
776extern CookeeObject CookeeNewArray(CookeeContext* contextHandle, CookeeType itemType, CookeeInt length);
777
778extern CookeeInt CookeeUnmanagedArraySize(CookeeType itemType, CookeeInt length);
779extern CookeeObject CookeeInitUnmanagedArray(CookeeType itemType, CookeeInt length, void* ptr);
780
781extern CookeeObject CookeeMallocArray(CookeeType itemType, CookeeInt length);
782extern CookeeObject CookeeCallocArray(CookeeType itemType, CookeeInt length);
783extern CookeeBool CookeeFreeArray(CookeeObject array);
784
785static inline CookeeObject CookeePtrToArray(void* const ptr) {
786 return ptr == (void*) 0 ? COOKEE_NULL : (CookeeObject)((char*) ptr + COOKEE_INSTANCE_HEADER_SIZE);
787}
788
789static inline void* CookeeArrayToPtr(const CookeeObject array) {
790 return array == COOKEE_NULL ? (void*) 0 : (void*)((char*) array - COOKEE_INSTANCE_HEADER_SIZE);
791}
792
793// Returns true if the specified instance is an array, false otherwise.
794extern CookeeBool CookeeIsArray(CookeeContext* contextHandle, CookeeObject instance);
795
796// Returns the CookeeType that was used to create the array.
797extern CookeeType CookeeArrayType(CookeeContext* contextHandle, CookeeObject array);
798
799// Returns the length of the given array object.
800extern CookeeInt CookeeArrayLength(CookeeContext* contextHandle, CookeeObject array);
801
802// Marks the array with an indicator which indicates that the contents of the array should not be changed.
803// Note that this actually does nothing without you respecting the indicator.
804extern void CookeeArrayLock(CookeeContext* contextHandle, CookeeObject array);
805
806// Returns COOKEE_TRUE if array was marked with lock indicator, COOKEE_FALSE otherwise.
807extern CookeeBool CookeeArrayLocked(CookeeContext* contextHandle, CookeeObject array);
808
809// Returns a generic pointer to the contents of the given array.
810// It's not enough to just cast the CookeeObject to a pointer since the contents
811// could be padded by COOKEE_INSTANCE_PARTITION_SIZE.
812extern char* CookeeArrayContent(CookeeContext* contextHandle, CookeeObject array);
813
814// Returns the pointer to the contents of the given array of specific type.
815static inline CookeeBool* CookeeBoolArrayContent(const CookeeObject array) {
816 return (CookeeBool*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
817}
818
819static inline CookeeChar* CookeeCharArrayContent(const CookeeObject array) {
820 return (CookeeChar*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
821}
822
823static inline CookeeInt* CookeeIntArrayContent(const CookeeObject array) {
824 return (CookeeInt*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
825}
826
827static inline CookeeLong* CookeeLongArrayContent(const CookeeObject array) {
828 return (CookeeLong*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
829}
830
831static inline CookeeFloat* CookeeFloatArrayContent(const CookeeObject array) {
832 return (CookeeFloat*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
833}
834
835static inline CookeeDouble* CookeeDoubleArrayContent(const CookeeObject array) {
836 return (CookeeDouble*)((char*) array + COOKEE_INSTANCE_PARTITION_SIZE);
837}
838
839static inline CookeeObject* CookeeObjectArrayContent(const CookeeObject array) {
840 return (CookeeObject*) array;
841}
842
843#endif
844
845// C standard includes.
846#include <stddef.h>
847#include <string.h>
848#include <stdlib.h>
849#include <stdio.h>
850#include <stdarg.h>
851#include <stdbool.h>
852#include <setjmp.h>
853#include <math.h>
854#include <limits.h>
855
856// If the VM is not being debugged then there's no need for assets.
857#ifndef COOKEE_DEBUG
858 #define NDEBUG 1
859#endif
860
861#include <assert.h>
862
863///////////////////////////////////////////////////////////////////////
864// HELPERS
865///////////////////////////////////////////////////////////////////////
866
867// Typedefs for C types so that the writing style would match.
868typedef void Void;
869typedef bool Bool;
870typedef char Char;
871typedef signed char Int8;
872typedef unsigned char Uint8;
873typedef signed short Int16;
874typedef unsigned short Uint16;
875typedef signed int Int32;
876typedef unsigned int Uint32;
877typedef signed long long Int64;
878typedef unsigned long long Uint64;
879typedef intptr_t IntX;
880typedef uintptr_t UintX;
881typedef float Float;
882typedef double Double;
883typedef va_list VaList;
884
885// Aligns given size to the given aligner size. Zero sizes are still aligned.
886// So for example if you pass 4 and try to align to 8 it will return
887// 8, or if you pass 9 and try to align to 8 it will return 16.
888//
889// @param size - the size to be aligned.
890// @param align - the size to which align to.
891//
892// @return the aligned size.
893//
894static inline Uint32 alignSize(const Uint32 size, const Uint32 align) {
895 assert(align != 0);
896 return ((size / align) * align) + align * (size == 0 || size % align != 0);
897}
898
899// Converts 32-bit IEEE-754 floating point bits represented as int to a float value.
900//
901// @param intBits - the float bits to be converted.
902// @return the float value of given float bits.
903//
904static inline Float intBitsToFloat(const Uint32 intBits) {
905 union { Uint32 i; Float f; } conv = { .i = intBits };
906 return conv.f;
907}
908
909// Calculates the number of digits in an unsigned integer value.
910//
911// @param value - the value whose digits should be counted.
912// @return the number of digits given value has.
913//
914static Uint32 uintDigits(const Uint32 value) {
915 if(value == 0) {
916 return 1;
917 }
918
919 Uint32 digits = 0;
920 Uint32 currentValue = value;
921
922 while(currentValue > 0) {
923 digits += 1;
924 currentValue /= 10;
925 }
926
927 return digits;
928}
929
930// Structure for pooled memory allocation.
931typedef struct Pool Pool;
932struct Pool {
933
934 // Pointer to the first obtained page in current pages list(it will always be the last one in the list).
935 Uint8* firstPage;
936
937 // Linked list of free pages that can be reused.
938 Uint8* free;
939
940 // Linked list of pages currently in use.
941 Uint8* pages;
942
943 // The offset in the current page which will get returned when obtaining objects.
944 Uint8* offset;
945
946 // The default page size.
947 Uint32 objectSize;
948
949 // The number of objects in each page.
950 Uint32 objectsPerPage;
951
952 // The heap size of a single page.
953 Uint32 pageSize;
954
955};
956
957// The offset in bytes where objects are allocated in a page. The space between this offset is used to store a pointer to the
958// next page in the linked list of pages.
959#define PAGE_HEAP_OFFSET 8
960
961// Initialize a pool to start allocating objects inside of it.
962//
963// @param pool - the pool to initialize.
964// @param objectSize - the size of each individual object that will be allocated in the pool. Must be > 0.
965// @param objectsPerPage - the number of objects to allocate in a single memory page.
966//
967// @return true if initial page was successfully allocated, false otherwise.
968//
969static Bool initializePool(Pool* const pool, const Uint32 objectSize, const Uint32 objectsPerPage) {
970 assert(pool != NULL);
971 assert(objectSize > 0);
972 assert(objectsPerPage > 0);
973
974 pool->free = NULL;
975 pool->objectSize = objectSize;
976 pool->objectsPerPage = objectsPerPage;
977 pool->pageSize = objectSize * objectsPerPage + PAGE_HEAP_OFFSET;
978
979 Uint8* initialPage;
980
981 if((initialPage = malloc(pool->pageSize)) == NULL) {
982 return false;
983 }
984
985 pool->pages = initialPage;
986 pool->firstPage = pool->pages;
987 pool->offset = pool->pages + PAGE_HEAP_OFFSET;
988
989 *((Uint8**) initialPage) = NULL;
990
991 return true;
992}
993
994// Internal function to free a linked list of pages.
995// @param pages - the linked list of pages.
996//
997static Void freePageList(Uint8* const pages) {
998 if(pages != NULL) {
999 Uint8* page = pages;
1000
1001 do {
1002 Uint8* const next = *((Uint8**) page);
1003 free(page);
1004 page = next;
1005 } while(page != NULL);
1006 }
1007}
1008
1009// Frees all memory allocated by a pool. To continue using the same pool handle you will need to re-initialize it.
1010// @param pool - the pool to purge.
1011//
1012static Void purgePool(Pool* const pool) {
1013 assert(pool != NULL);
1014 freePageList(pool->pages);
1015 freePageList(pool->free);
1016}
1017
1018// Resets the pool to initial state without freeing the current pages in use. Instead the pages will get reused when obtaining
1019// objects later.
1020//
1021// @param pool - the pool to reuse.
1022//
1023static Void reusePool(Pool* const pool) {
1024 assert(pool != NULL);
1025
1026 *((Uint8**) pool->firstPage) = pool->free;
1027
1028 Uint8* const initialPage = pool->pages;
1029
1030 pool->free = *((Uint8**) initialPage);
1031 *((Uint8**) initialPage) = NULL;
1032
1033 pool->firstPage = initialPage;
1034 pool->pages = initialPage;
1035 pool->offset = initialPage + PAGE_HEAP_OFFSET;
1036}
1037
1038// Obtains a new object from the pool. Note that the object is not zeroed out.
1039//
1040// @param pool - the pool from which to obtain the object.
1041// @return pointer to the obtained object or NULL if a new page had to be allocated and the allocation failed.
1042//
1043static Void* poolObtain(Pool* const pool) {
1044 assert(pool != NULL);
1045
1046 Uint8* const pages = pool->pages;
1047 Uint8* ptr = pool->offset;
1048
1049 if(ptr == pages + pool->pageSize) {
1050 Uint8* page;
1051
1052 if(pool->free != NULL) {
1053 page = pool->free;
1054 pool->free = *((Uint8**) page);
1055 }
1056 else {
1057 page = malloc(pool->pageSize);
1058
1059 if(page == NULL) {
1060 return NULL;
1061 }
1062 }
1063
1064 *((Uint8**) page) = pages;
1065 pool->pages = page;
1066
1067 ptr = page + PAGE_HEAP_OFFSET;
1068 pool->offset = ptr + pool->objectSize;
1069
1070 return ptr;
1071 }
1072 else {
1073 pool->offset += pool->objectSize;
1074 return ptr;
1075 }
1076}
1077
1078
1079///////////////////////////////////////////////////////////////////////
1080// VALUES
1081///////////////////////////////////////////////////////////////////////
1082
1083// Limits.
1084
1085
1086// The maximum number of parameters a method can have.
1087#define MAX_METHOD_PARAMETERS (256)
1088
1089// The maximum size of method code.
1090#define MAX_METHOD_CODE_SIZE (65536)
1091
1092// The maximum stack size in bytes that a single method can require.
1093#define MAX_METHOD_STACK_SIZE (65536)
1094
1095
1096// Optimization.
1097
1098
1099// The maximum size of method code for it to be inlined in level 1 optimization pass.
1100#define MAX_LEVEL_1_INLINE_METHOD_LENGTH (256)
1101
1102// The maximum number of crumbles that can be binded per context.
1103#define MAX_CRUMBLES (1000)
1104
1105// The class which indicates that standard library is used.
1106#define LIB_ID "Cookee.Lib Lib"
1107
1108// Signature of the builtins class.
1109#define LIB_CLASS_BUILTINS_SIGNATURE "Cookee.Lib Builtins"
1110
1111// Signature of the Array.rawArray field.
1112#define LIB_FIELD_ARRAY_RAW_ARRAY_SIGNATURE "Cookee.Lib Array.rawArray"
1113
1114// Signature of the Array.offset field.
1115#define LIB_FIELD_ARRAY_OFFSET_SIGNATURE "Cookee.Lib Array.offset"
1116
1117// Signature of the Array.length field.
1118#define LIB_FIELD_ARRAY_LENGTH_SIGNATURE "Cookee.Lib Array.length"
1119
1120// Offset of Array.rawArray field.
1121#define LIB_ARRAY_FIELD_RAW_ARRAY (8)
1122
1123// Offset of Array.offset field.
1124#define LIB_ARRAY_FIELD_OFFSET (LIB_ARRAY_FIELD_RAW_ARRAY + sizeof(CookeeObject) + COOKEE_INSTANCE_PARTITION_SIZE)
1125
1126// Offset of Array.length field.
1127#define LIB_ARRAY_FIELD_LENGTH (LIB_ARRAY_FIELD_OFFSET + sizeof(CookeeInt))
1128
1129
1130// Instructions.
1131
1132
1133// LAYOUT:
1134// $OPCODE ($OPERAND [0; n))
1135
1136// Typedef of a single value in a method's executable code.
1137typedef Uint32 Code;
1138
1139// Typedef of a single signed value in a method's executable code.
1140// We need this to correctly cast signed values within the code(so that the sign bit would be treated correctly).
1141typedef Int32 CodeValue;
1142
1143// List of operation codes identifying the instruction to be performed by the interpreter.
1144// There are brief descriptions of the opcodes below but for more specific info lookup the
1145// reflection function or the interpreter.
1146//
1147typedef enum Opcode Opcode;
1148enum Opcode {
1149
1150
1151 /////////////////////////////////////////
1152 // BASE SET OPCODES(KNOWN BY COMPILER)
1153 /////////////////////////////////////////
1154
1155
1156 // Do nothing. Used for padding or fast instruction elimination.
1157 $OPCODE_NOOP,
1158
1159
1160 // Set program counter to some position.
1161 $OPCODE_GOTO,
1162
1163 // Set program counter to some position only if local int is non zero.
1164 $OPCODE_GOTOIF,
1165
1166 // Set program counter to some position only if local int is zero.
1167 $OPCODE_GOTOIFNOT,
1168
1169
1170 // Add two local ints without overflow/underflow checks and store the result in a local.
1171 $OPCODE_IADD,
1172
1173 // Add two local longs without overflow/underflow checks and store the result in a local.
1174 $OPCODE_LADD,
1175
1176 // Add two local floats and store the result in a local.
1177 $OPCODE_FADD,
1178
1179 // Add two local doubles and store the result in a local.
1180 $OPCODE_DADD,
1181
1182
1183 // Subtract one local int from another without overflow/underflow checks and store the result in a local.
1184 $OPCODE_ISUB,
1185
1186 // Subtract one local long from another without overflow/underflow checks and store the result in a local.
1187 $OPCODE_LSUB,
1188
1189 // Subtract one local float from another and store the result in a local.
1190 $OPCODE_FSUB,
1191
1192 // Subtract one local double from another and store the result in a local.
1193 $OPCODE_DSUB,
1194
1195
1196 // Multiply two local ints without overflow/underflow checks and store the result in a local.
1197 $OPCODE_IMUL,
1198
1199 // Multiply two local longs without overflow/underflow checks and store the result in a local.
1200 $OPCODE_LMUL,
1201
1202 // Multiply two local floats and store the result in a local.
1203 $OPCODE_FMUL,
1204
1205 // Multiply two local doubles and store the result in a local.
1206 $OPCODE_DMUL,
1207
1208
1209 // Divide one local int by another (also handling negative zero case) and store the result in a local.
1210 // If the right operand is value zero this instruction crashes the context.
1211 $OPCODE_IDIV,
1212
1213 // Divide one local long by another (also handling negative zero case) and store the result in a local.
1214 // If the right operand is value zero this instruction crashes the context.
1215 $OPCODE_LDIV,
1216
1217 // Divide one local float by another and store the result in a local.
1218 $OPCODE_FDIV,
1219
1220 // Divide one local double by another and store the result in a local.
1221 $OPCODE_DDIV,
1222
1223
1224 // Convert local int to int value 1 if the local value is not 0 and store the result in a local.
1225 // If the local is 0 the value is still written to result local but the value remains unchanged.
1226 $OPCODE_I2B,
1227
1228 // Cast local int to a long value and store the result in a local.
1229 $OPCODE_I2L,
1230
1231 // Cast local int to a float value and store the result in a local.
1232 $OPCODE_I2F,
1233
1234 // Cast local int to a double value and store the result in a local.
1235 $OPCODE_I2D,
1236
1237
1238 // Convert local long to int value 1 if the local value is not 0 and store the result in a local.
1239 // If the local is 0 the value is still written to result local but the value remains unchanged.
1240 $OPCODE_L2B,
1241
1242 // Cast local long to a int value and store the result in a local.
1243 $OPCODE_L2I,
1244
1245 // Cast local long to a float value and store the result in a local.
1246 $OPCODE_L2F,
1247
1248 // Cast local long to a double value and store the result in a local.
1249 $OPCODE_L2D,
1250
1251
1252 // Convert local float to int value 1 if the local value is not 0 and store the result in a local.
1253 // If the local is 0 the value is still written to result local but the value remains unchanged.
1254 $OPCODE_F2B,
1255
1256 // Cast local float to a int value and store the result in a local.
1257 $OPCODE_F2I,
1258
1259 // Cast local float to a long value and store the result in a local.
1260 $OPCODE_F2L,
1261
1262 // Cast local float to a double value and store the result in a local.
1263 $OPCODE_F2D,
1264
1265
1266 // Convert local double to int value 1 if the local value is not 0 and store the result in a local.
1267 // If the local is 0 the value is still written to result local but the value remains unchanged.
1268 $OPCODE_D2B,
1269
1270 // Cast local double to a int value and store the result in a local.
1271 $OPCODE_D2I,
1272
1273 // Cast local double to a long value and store the result in a local.
1274 $OPCODE_D2L,
1275
1276 // Cast local double to a float value and store the result in a local.
1277 $OPCODE_D2F,
1278
1279
1280 // Allocate a new instance of a class and store it in a local.
1281 // If the instance could not be allocated crashes the context.
1282 $OPCODE_NEW,
1283
1284 // Obtain an old instance of a class and store it in a local.
1285 // If there's no more free old instances and a new one could not be allocated crashes the context.
1286 $OPCODE_OLD,
1287
1288 // Fetch a tmp instance of a class and store it in a local.
1289 // If there was no tmp instance allocated at given index and it could not be initialized crashes the context.
1290 $OPCODE_TMP,
1291
1292
1293 // Move local int to another local.
1294 $OPCODE_IMOVE,
1295
1296 // Move local long to another local.
1297 $OPCODE_LMOVE,
1298
1299 // Move local float to another local.
1300 $OPCODE_FMOVE,
1301
1302 // Move local double to another local.
1303 $OPCODE_DMOVE,
1304
1305 // Move local object to another local
1306 $OPCODE_OMOVE,
1307
1308
1309 // Compare if one local int is equal to another and store 0(no) or 1(yes) result in a local int.
1310 $OPCODE_IIS,
1311
1312 // Compare if one local long is equal to another and store 0(no) or 1(yes) result in a local int.
1313 $OPCODE_LIS,
1314
1315 // Compare if one local float is equal to another and store 0(no) or 1(yes) result in a local int.
1316 $OPCODE_FIS,
1317
1318 // Compare if one local double is equal to another and store 0(no) or 1(yes) result in a local int.
1319 $OPCODE_DIS,
1320
1321 // Compare if one local object is equal to another and store 0(no) or 1(yes) result in a local int.
1322 // If the class of the objects have equality function provided it will be used to perform the comparison.
1323 $OPCODE_OIS,
1324
1325
1326 // Compare if one local int isnt equal to another and store 0(no) or 1(yes) result in a local int.
1327 $OPCODE_IISNT,
1328
1329 // Compare if one local long isnt equal to another and store 0(no) or 1(yes) result in a local int.
1330 $OPCODE_LISNT,
1331
1332 // Compare if one local float isnt equal to another and store 0(no) or 1(yes) result in a local int.
1333 $OPCODE_FISNT,
1334
1335 // Compare if one local double isnt equal to another and store 0(no) or 1(yes) result in a local int.
1336 $OPCODE_DISNT,
1337
1338 // Compare if one local object isnt equal to another and store 0(no) or 1(yes) result in a local int.
1339 // If the class of the objects have equality function provided it will be used to perform the comparison.
1340 $OPCODE_OISNT,
1341
1342
1343 // Check if either of two int locals are non zero and store 0(no) or 1(yes) result in a local.
1344 $OPCODE_OR,
1345
1346 // Check if both of two int locals are non zero and store 0(no) or 1(yes) result in a local.
1347 $OPCODE_AND,
1348
1349
1350 // Check if one local int is less than another and store 0(no) or 1(yes) result in a local int.
1351 $OPCODE_ILT,
1352
1353 // Check if one local long is less than another and store 0(no) or 1(yes) result in a local int.
1354 $OPCODE_LLT,
1355
1356 // Check if one local float is less than another and store 0(no) or 1(yes) result in a local int.
1357 $OPCODE_FLT,
1358
1359 // Check if one local double is less than another and store 0(no) or 1(yes) result in a local int.
1360 $OPCODE_DLT,
1361
1362
1363 // Check if one local int is less than or equal to another and store 0(no) or 1(yes) result in a local int.
1364 $OPCODE_ILTE,
1365
1366 // Check if one local long is less than or equal to another and store 0(no) or 1(yes) result in a local int.
1367 $OPCODE_LLTE,
1368
1369 // Check if one local float is less than or equal to another and store 0(no) or 1(yes) result in a local int.
1370 $OPCODE_FLTE,
1371
1372 // Check if one local double is less than or equal to another and store 0(no) or 1(yes) result in a local int.
1373 $OPCODE_DLTE,
1374
1375
1376 // Check if one local int is greater than another and store 0(no) or 1(yes) result in a local int.
1377 $OPCODE_IGT,
1378
1379 // Check if one local long is greater than another and store 0(no) or 1(yes) result in a local int.
1380 $OPCODE_LGT,
1381
1382 // Check if one local float is greater than another and store 0(no) or 1(yes) result in a local int.
1383 $OPCODE_FGT,
1384
1385 // Check if one local double is greater than another and store 0(no) or 1(yes) result in a local int.
1386 $OPCODE_DGT,
1387
1388
1389 // Check if one local int is greater than or equal to another and store 0(no) or 1(yes) result in a local int.
1390 $OPCODE_IGTE,
1391
1392 // Check if one local long is greater than or equal to another and store 0(no) or 1(yes) result in a local int.
1393 $OPCODE_LGTE,
1394
1395 // Check if one local float is greater than or equal to another and store 0(no) or 1(yes) result in a local int.
1396 $OPCODE_FGTE,
1397
1398 // Check if one local double is greater than or equal to another and store 0(no) or 1(yes) result in a local int.
1399 $OPCODE_DGTE,
1400
1401
1402 // Crash the context if a local object is not an instance of specified class or move the object to another local.
1403 $OPCODE_CHKTYPE,
1404
1405
1406 // Retrieve a global instance of a specified class in a local object while performing default initialization if needed.
1407 // In case the global instance could not be allocated crashes the context.
1408 $OPCODE_GLOBAL,
1409
1410
1411 // Retrieve a text literal from the text literal table and store it in a local.
1412 $OPCODE_TEXT,
1413
1414
1415 // Store a 0 object in a local.
1416 $OPCODE_NULL,
1417
1418
1419 // Store value 0 in an int local.
1420 $OPCODE_FALSE,
1421
1422 // Store value 1 in an int local.
1423 $OPCODE_TRUE,
1424
1425
1426 // Load character value from code and store it in local int.
1427 $OPCODE_CHAR,
1428
1429 // Load int value from code and store it in a local.
1430 $OPCODE_INT,
1431
1432 // Load long value from long value table and store it in a local.
1433 $OPCODE_LONG,
1434
1435 // Load int value from code casting it to long and store in a local.
1436 $OPCODE_DIRLONG,
1437
1438 // Load float value from code and store it in a local.
1439 $OPCODE_FLOAT,
1440
1441 // Load double value from double value table and store it in a local.
1442 $OPCODE_DOUBLE,
1443
1444 // Load float value from code casting it to double and store it in a local.
1445 $OPCODE_DIRDOUBLE,
1446
1447
1448 // Negate local int and store the result in another local.
1449 $OPCODE_INEG,
1450
1451 // Negate local long and store the result in another local.
1452 $OPCODE_LNEG,
1453
1454 // Negate local float and store the result in another local.
1455 $OPCODE_FNEG,
1456
1457 // Negate local double and store the result in another local.
1458 $OPCODE_DNEG,
1459
1460
1461 // Perform logical not on a local int and store the result in another local.
1462 $OPCODE_NOT,
1463
1464
1465 // Get int value from local object's field and store the value in a local.
1466 // If the local object is null crashes the context.
1467 $OPCODE_IGETFIELD,
1468
1469 // Get long value from local object's field and store the value in a local.
1470 // If the local object is null crashes the context.
1471 $OPCODE_LGETFIELD,
1472
1473 // Get float value from local object's field and store the value in a local.
1474 // If the local object is null crashes the context.
1475 $OPCODE_FGETFIELD,
1476
1477 // Get double value from local object's field and store the value in a local.
1478 // If the local object is null crashes the context.
1479 $OPCODE_DGETFIELD,
1480
1481 // Get object value from local object's field and store the value in a local.
1482 // If the local object is null crashes the context.
1483 $OPCODE_OGETFIELD,
1484
1485
1486 // Get local int value and store it in local object's field.
1487 // If the local object is null crashes the context.
1488 $OPCODE_ISETFIELD,
1489
1490 // Get local long value and store it in local object's field.
1491 // If the local object is null crashes the context.
1492 $OPCODE_LSETFIELD,
1493
1494 // Get local float value and store it in local object's field.
1495 // If the local object is null crashes the context.
1496 $OPCODE_FSETFIELD,
1497
1498 // Get local double value and store it in local object's field.
1499 // If the local object is null crashes the context.
1500 $OPCODE_DSETFIELD,
1501
1502 // Get local object value and store it in local object's field.
1503 // If the local object is null crashes the context.
1504 $OPCODE_OSETFIELD,
1505
1506
1507 // Invoke a method using local object as this.
1508 // If the local object is null or there's not enough stack space available crashes the context.
1509 $OPCODE_INVOKE,
1510
1511 // Invoke an abstract method using local object as this.
1512 // If the local object is null or there's not enough stack space available crashes the context.
1513 $OPCODE_AINVOKE,
1514
1515 // Invoke a sequential method using local object as this.
1516 // If the local object is null or there's not enough stack space available crashes the context.
1517 $OPCODE_INVOKESEQ,
1518
1519 // Invoke an abstract sequential method using local object as this.
1520 // If the local object is null or there's not enough stack space available crashes the context.
1521 $OPCODE_AINVOKESEQ,
1522
1523
1524 // Return int local value from current method returning to the previous method or ending execution.
1525 $OPCODE_IRETURN,
1526
1527 // Return long local value from current method returning to the previous method or ending execution.
1528 $OPCODE_LRETURN,
1529
1530 // Return float local value from current method returning to the previous method or ending execution.
1531 $OPCODE_FRETURN,
1532
1533 // Return double local value from current method returning to the previous method or ending execution.
1534 $OPCODE_DRETURN,
1535
1536 // Return object local value from current method returning to the previous method or ending execution.
1537 $OPCODE_ORETURN,
1538
1539 // Return this from method.
1540 $OPCODE_RETURN,
1541
1542
1543 // Execute native binding function of current method which returns int.
1544 $OPCODE_INATIVE,
1545
1546 // Execute native binding function of current method which returns long.
1547 $OPCODE_LNATIVE,
1548
1549 // Execute native binding function of current method which returns float.
1550 $OPCODE_FNATIVE,
1551
1552 // Execute native binding function of current method which returns double.
1553 $OPCODE_DNATIVE,
1554
1555 // Execute native binding function of current method which returns object.
1556 $OPCODE_ONATIVE,
1557
1558 // Execute sequential native binding function of current method which returns this.
1559 $OPCODE_NATIVESEQ,
1560
1561
1562 // Panic because the executed method is unimplemented.
1563 $OPCODE_UNIMPLEMENTED,
1564
1565
1566 /////////////////////////////////////////
1567 // GENERAL OPTIMIZATION OPCODES
1568 /////////////////////////////////////////
1569
1570
1571 // Opcode used to wrap execution of instruction so that the interpreter would not need to check if it needs to exit the
1572 // function on every native call and return.
1573 $OPCODE_EXIT_EXECUTE,
1574
1575
1576 // Accesses the global instance while knowing that it's initialized.
1577 $OPCODE_GLOBAL_INITIALIZED,
1578
1579
1580 // Invoke a method on a local object while knowing that it's prepared.
1581 $OPCODE_INVOKE_INITIALIZED,
1582
1583 // Invoke a sequential method while knowing that it's prepared.
1584 $OPCODE_INVOKESEQ_INITIALIZED,
1585
1586
1587 // Execute binded native function directly which returns int.
1588 $OPCODE_INVOKE_INATIVE,
1589
1590 // Execute binded native function directly which returns long.
1591 $OPCODE_INVOKE_LNATIVE,
1592
1593 // Execute binded native function directly which returns float.
1594 $OPCODE_INVOKE_FNATIVE,
1595
1596 // Execute binded native function directly which returns double.
1597 $OPCODE_INVOKE_DNATIVE,
1598
1599 // Execute binded native function directly which returns object.
1600 $OPCODE_INVOKE_ONATIVE,
1601
1602 // Execute binded sequential native function directly which returns this.
1603 $OPCODE_INVOKE_NATIVESEQ,
1604
1605
1606 // Panic if local object is null. Used when inlining methods.
1607 $OPCODE_CHKNULL_INLINE_INVOKE,
1608
1609 // Store the position of inlined frame. Used when inlining methods.
1610 $OPCODE_INLINE_INVOKE,
1611
1612
1613 // Execute a crumb at specified index.
1614 $OPCODE_EXECUTE_CRUMB,
1615
1616
1617 /////////////////////////////////////////
1618 // LIBRARY CALL OPTIMIZATION OPCODES
1619 /////////////////////////////////////////
1620
1621
1622 // Replaces calls to unsafeDiv(var a int, var b int).
1623 $OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT,
1624
1625 // Replaces calls to unsafeDiv(var a long, var b long).
1626 $OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG,
1627
1628
1629 // Replaces calls to rangeCheck(var value int, var min int, var max int).
1630 $OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX,
1631
1632 // Replaces calls to rangeCheck(var value int, var max int).
1633 $OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX,
1634
1635
1636 // Replaces calls to bitwiseNot(var value int).
1637 $OPCODE_LIB_BUILTINS_BITWISE_NOT_INT,
1638
1639 // Replaces calls to bitwiseNot(var value long).
1640 $OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG,
1641
1642
1643 // Replaces calls to bitwiseAnd(var value1 int, var value2 int).
1644 $OPCODE_LIB_BUILTINS_BITWISE_AND_INT,
1645
1646 // Replaces calls to bitwiseAnd(var value1 long, var value2 long).
1647 $OPCODE_LIB_BUILTINS_BITWISE_AND_LONG,
1648
1649
1650 // Replaces calls to bitwiseOr(var value1 int, var value2 int).
1651 $OPCODE_LIB_BUILTINS_BITWISE_OR_INT,
1652
1653 // Replaces calls to bitwiseOr(var value1 long, var value2 long).
1654 $OPCODE_LIB_BUILTINS_BITWISE_OR_LONG,
1655
1656
1657 // Replaces calls to bitwiseXor(var value1 int, var value2 int).
1658 $OPCODE_LIB_BUILTINS_BITWISE_XOR_INT,
1659
1660 // Replaces calls to bitwiseXor(var value1 long, var value2 long).
1661 $OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG,
1662
1663
1664 // Replaces calls to lshift(var value int, var shift int).
1665 $OPCODE_LIB_BUILTINS_LSHIFT_INT,
1666
1667 // Replaces calls to lshift(var value long, var shift int).
1668 $OPCODE_LIB_BUILTINS_LSHIFT_LONG,
1669
1670
1671 // Replaces calls to rshift(var value int, var shift int).
1672 $OPCODE_LIB_BUILTINS_RSHIFT_INT,
1673
1674 // Replaces calls to rshift(var value long, var shift int).
1675 $OPCODE_LIB_BUILTINS_RSHIFT_LONG,
1676
1677
1678 // Replaces calls to urshift(var value int, var shift int).
1679 $OPCODE_LIB_BUILTINS_URSHIFT_INT,
1680
1681 // Replaces calls to urshift(var value long, var shift int).
1682 $OPCODE_LIB_BUILTINS_URSHIFT_LONG,
1683
1684
1685 // Replaces calls to abs(var value int).
1686 $OPCODE_LIB_BUILTINS_ABS_INT,
1687
1688 // Replaces calls to abs(var value long).
1689 $OPCODE_LIB_BUILTINS_ABS_LONG,
1690
1691 // Replaces calls to abs(var value float).
1692 $OPCODE_LIB_BUILTINS_ABS_FLOAT,
1693
1694 // Replaces calls to abs(var value double).
1695 $OPCODE_LIB_BUILTINS_ABS_DOUBLE,
1696
1697
1698 // Replaces calls to min(var a int, var b int).
1699 $OPCODE_LIB_BUILTINS_MIN_INT,
1700
1701 // Replaces calls to min(var a long, var b long).
1702 $OPCODE_LIB_BUILTINS_MIN_LONG,
1703
1704 // Replaces calls to min(var a float, var b float).
1705 $OPCODE_LIB_BUILTINS_MIN_FLOAT,
1706
1707 // Replaces calls to min(var a double, var b double).
1708 $OPCODE_LIB_BUILTINS_MIN_DOUBLE,
1709
1710
1711 // Replaces calls to max(var a int, var b int).
1712 $OPCODE_LIB_BUILTINS_MAX_INT,
1713
1714 // Replaces calls to max(var a long, var b long).
1715 $OPCODE_LIB_BUILTINS_MAX_LONG,
1716
1717 // Replaces calls to max(var a float, var b float).
1718 $OPCODE_LIB_BUILTINS_MAX_FLOAT,
1719
1720 // Replaces calls to max(var a double, var b double).
1721 $OPCODE_LIB_BUILTINS_MAX_DOUBLE,
1722
1723
1724 // Replaces calls to remainer(var a int, var b int).
1725 $OPCODE_LIB_BUILTINS_REMAINER_INT,
1726
1727 // Replaces calls to remainer(var a long, var b long).
1728 $OPCODE_LIB_BUILTINS_REMAINER_LONG,
1729
1730 // Replaces calls to remainer(var a float, var b float).
1731 $OPCODE_LIB_BUILTINS_REMAINER_FLOAT,
1732
1733 // Replaces calls to remainer(var a double, var b double).
1734 $OPCODE_LIB_BUILTINS_REMAINER_DOUBLE,
1735
1736
1737 // Replaces calls to arrayAtGet[int](var array Array[int], var index int).
1738 $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT,
1739
1740 // Replaces calls to arrayAtGet[long] long(var array Array[long], var index int).
1741 $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG,
1742
1743 // Replaces calls to arrayAtGet[float] float(var array Array[float], var index int).
1744 $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT,
1745
1746 // Replaces calls to arrayAtGet[double] double(var array Array[double], var index int).
1747 $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE,
1748
1749 // Replaces calls to arrayAtGet[Object] Object(var array Array[Object], var index int).
1750 $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT,
1751
1752
1753 // Replaces calls to arrayAtSet[int](var array Array[int], var index int, var value int).
1754 $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT,
1755
1756 // Replaces calls to arrayAtSet[long](var array Array[long], var index int, var value long).
1757 $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG,
1758
1759 // Replaces calls to arrayAtSet[float](var array Array[float], var index int, var value float).
1760 $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT,
1761
1762 // Replaces calls to arrayAtSet[double](var array Array[double], var index int, var value double).
1763 $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE,
1764
1765 // Replaces calls to arrayAtSet[Object](var array Array[Object], var index int, var value Object).
1766 $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT,
1767
1768
1769 // Replaces calls to arrayInc[int](var array Array[int], var index int, var amount int).
1770 $OPCODE_LIB_BUILTINS_ARRAY_INC_INT,
1771
1772 // Replaces calls to arrayInc[long](var array Array[long], var index int, var amount long).
1773 $OPCODE_LIB_BUILTINS_ARRAY_INC_LONG,
1774
1775 // Replaces calls to arrayInc[float](var array Array[float], var index int, var amount float).
1776 $OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT,
1777
1778 // Replaces calls to arrayInc[double](var array Array[double], var index int, var amount double).
1779 $OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE,
1780
1781
1782 // Replaces calls to arrayDec[int](var array Array[int], var index int, var amount int).
1783 $OPCODE_LIB_BUILTINS_ARRAY_DEC_INT,
1784
1785 // Replaces calls to arrayDec[long](var array Array[long], var index int, var amount long).
1786 $OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG,
1787
1788 // Replaces calls to arrayDec[float](var array Array[float], var index int, var amount float).
1789 $OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT,
1790
1791 // Replaces calls to arrayDec[double](var array Array[double], var index int, var amount double).
1792 $OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE,
1793
1794
1795 // This opcode does not indicate an actual instruction and is never used apart for getting the number of defined opcodes.
1796 $OPCODE_LAST
1797
1798
1799};
1800
1801// Constant holding the total number of instructions.
1802#define INSTRUCTION_N $OPCODE_LAST
1803
1804
1805// List of possible categories of instruction behaviour.
1806typedef enum InstructionCategory InstructionCategory;
1807enum InstructionCategory {
1808
1809 // Binary operation which reads two values, performs some operation on them and then writes the result.
1810 $INSTRUCTION_CATEGORY_BINARY,
1811
1812 // Unary operation which reads one value, performs some operation on it and then writes the result.
1813 $INSTRUCTION_CATEGORY_UNARY,
1814
1815 // Cast operation which reads one value, converts or checks it's type and writes the result.
1816 $INSTRUCTION_CATEGORY_CAST,
1817
1818 // Move operation which read a value and writes it at a different offset.
1819 $INSTRUCTION_CATEGORY_MOVE,
1820
1821 // Value operation which fetches a value from somewhere and writes the result.
1822 $INSTRUCTION_CATEGORY_VALUE,
1823
1824 // Allocation operation which creates or reuses an instance and writes the result.
1825 $INSTRUCTION_CATEGORY_ALLOCATION,
1826
1827 // Jump operation which can change program counter's position.
1828 $INSTRUCTION_CATEGORY_JUMP,
1829
1830 // Field access operation which can read from or write to a field offset in an object.
1831 $INSTRUCTION_CATEGORY_FIELD_ACCESS,
1832
1833 // Invoke operation which invokes a method pushing a new stack frame.
1834 $INSTRUCTION_CATEGORY_INVOKE,
1835
1836 // Return operation which returns from a methods poping it's stack frame.
1837 $INSTRUCTION_CATEGORY_RETURN,
1838
1839 // Native operation which calls a binded native function.
1840 $INSTRUCTION_CATEGORY_NATIVE,
1841
1842 // Library operation which performs some functionality provided by the standard library.
1843 $INSTRUCTION_CATEGORY_LIB,
1844
1845 // The instruction is some other operation which cannot be categorized because of it's specificity.
1846 $INSTRUCTION_CATEGORY_OTHER
1847
1848};
1849
1850// List of possible instruction operand types.
1851typedef enum InstructionOperand InstructionOperand;
1852enum InstructionOperand {
1853
1854 // Indicates a code offset relative the currently executed methods code start.
1855 $INSTRUCTION_OPERAND_CODE_OFFSET,
1856
1857 // Indicates a read offset of an int value in the stack.
1858 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
1859
1860 // Indicates a read offset of an long value in the stack.
1861 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
1862
1863 // Indicates a read offset of an float value in the stack.
1864 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
1865
1866 // Indicates a read offset of an double value in the stack.
1867 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
1868
1869 // Indicates a read offset of an object value in the stack.
1870 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
1871
1872 // Indicates a write offset of an int value in the stack.
1873 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT,
1874
1875 // Indicates a write offset of an long value in the stack.
1876 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG,
1877
1878 // Indicates a write offset of an float value in the stack.
1879 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT,
1880
1881 // Indicates a write offset of an double value in the stack.
1882 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE,
1883
1884 // Indicates a write offset of an object value in the stack.
1885 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
1886
1887 // Indicates an offset of a field within an object.
1888 $INSTRUCTION_OPERAND_FIELD_OFFSET,
1889
1890 // Indicates an index of a class.
1891 $INSTRUCTION_OPERAND_CLASS_INDEX,
1892
1893 // Indicates an index of a method.
1894 $INSTRUCTION_OPERAND_METHOD_INDEX,
1895
1896 // Indicates an index of a surface method in an object class' surface method table.
1897 $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX,
1898
1899 // Indicates an index of a text literal in the text literal table.
1900 $INSTRUCTION_OPERAND_TEXT_INDEX,
1901
1902 // Indicates an index of a long literal in the long literal table.
1903 $INSTRUCTION_OPERAND_LONG_INDEX,
1904
1905 // Indicates an index of a double literal in the double literal table.
1906 $INSTRUCTION_OPERAND_DOUBLE_INDEX,
1907
1908 // Indicates an index of a temporary instance in a class' temporary instance table.
1909 $INSTRUCTION_OPERAND_TMP_INDEX,
1910
1911 // Indicates an index of a crumb.
1912 $INSTRUCTION_OPERAND_CRUMB_INDEX,
1913
1914 // Indicates a literal int value.
1915 $INSTRUCTION_OPERAND_INT_VALUE,
1916
1917 // Indicates a literal int value of float bits which should be converted to float.
1918 $INSTRUCTION_OPERAND_FLOAT_BITS,
1919
1920 // Indicates a literal int value which consists of two packed 16-bit int values.
1921 $INSTRUCTION_OPERAND_SEQUENCE_DATA,
1922
1923 // Indicates a location value of the instruction in the source code.
1924 $INSTRUCTION_OPERAND_LOCATION
1925
1926};
1927
1928// Packs the sequence index and length into a single unsigned 32-bit integer value.
1929//
1930// @param sequenceIndex - the sequence index to be packed.
1931// @param sequenceLength - the sequence length to be packed.
1932//
1933// @return the packed sequence data value.
1934//
1935static inline Uint32 instructionSequenceData(const Uint32 sequenceIndex, const Uint32 sequenceLength) {
1936 return ((sequenceIndex & 0xFFFF) << 16) | (sequenceLength & 0xFFFF);
1937}
1938
1939// Fetches the packed sequence index value from sequence data.
1940//
1941// @param sequenceData - the sequence data value containing packed sequence information.
1942// @return the unpacked sequence index value.
1943//
1944static inline Uint32 instructionSequenceDataIndex(const Uint32 sequenceData) {
1945 return (sequenceData >> 16) & 0xFFFF;
1946}
1947
1948// Fetches the packed sequence length value from sequence data.
1949//
1950// @param sequenceData - the sequence data value containing packed sequence information.
1951// @return the unpacked sequence length value.
1952//
1953static inline Uint32 instructionSequenceDataLength(const Uint32 sequenceData) {
1954 return sequenceData & 0xFFFF;
1955}
1956
1957// Contains useful information about an instruction.
1958typedef struct Instruction Instruction;
1959struct Instruction {
1960
1961 // The instruction's opcode.
1962 Opcode opcode;
1963
1964 // The name of this instruction.
1965 const char* name;
1966
1967 // The length of the instruction which is all it's operands plus the opcode.
1968 Uint32 length;
1969
1970 // Indicates if the instruction can cause context panic.
1971 Bool canCausePanic;
1972
1973 // Indicates if the instruction has a potential to cause a gc cycle.
1974 Bool canCauseGc;
1975
1976 // Indicates if the instruction can potentially modify the argument space.
1977 // (not including instructions which can write to arguments but the argument offset is visible. Such as add, move etc.).
1978 Bool canCauseFrame;
1979
1980 // The category of this opcode.
1981 InstructionCategory category;
1982
1983 // List of instruction operand types.
1984 // There's currently no instruction which has more than 6 operands so that's a good number for now.
1985 // In case a new instruction is added with more operands this number needs to be incremented.
1986 InstructionOperand operands[6];
1987
1988};
1989
1990// Required indexes of operands in instructions.
1991// It is important to follow these numbers when adding a new instruction.
1992// Without this the optimizer could receive a considerable slowdown having to identify the operands.
1993//
1994#define INVOCATION_INSTRUCTION_SOURCE_OFFSET_OPERAND (0)
1995#define INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND (1)
1996#define INVOCATION_INSTRUCTION_SEQUENCE_DATA_OPERAND (2)
1997#define RETURN_INSTRUCTION_SOURCE_OFFSET_OPERAND (0)
1998#define MOVE_INSTRUCTION_SRC_OFFSET_OPERAND (0)
1999#define MOVE_INSTRUCTION_DST_OFFSET_OPERAND (1)
2000#define FIELD_ACCESS_INSTRUCTION_SOURCE_OFFSET_OPERAND (0)
2001#define GLOBAL_INSTRUCTION_CLASS_INDEX_OPERAND (0)
2002#define TEXT_INSTRUCTION_TEXT_INDEX_OPERAND (0)
2003#define TMP_INSTRUCTION_CLASS_INDEX_OPERAND (0)
2004#define OLD_INSTRUCTION_CLASS_INDEX_OPERAND (0)
2005
2006#define FIRST_BUILTIN_OPCODE $OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TODO: DOCS
2007
2008// The maximum number of code offsets an instruction can have.
2009#define MAX_INSTRUCTION_CODE_OFFSETS (1)
2010
2011// The maximum length of an invocation instruction.
2012#define MAX_INVOCATION_INSTRUCTION_LENGTH (6)
2013
2014// Finds the index of an operand in instruction.
2015//
2016// @param instruction - the instruction to search in.
2017// @param operand - the operand to search for.
2018//
2019// @return the index of the operand in the instruction or -1 if not found.
2020//
2021static Int32 indexOfInstructionOperand(const Instruction* const instruction,
2022 const InstructionOperand operand) {
2023
2024 const Uint32 operandCount = instruction->length - 1;
2025 const InstructionOperand* const operands = instruction->operands;
2026
2027 for(Uint32 i = 0; i < operandCount; i += 1) {
2028 const InstructionOperand cmpOperand = operands[i];
2029
2030 if(cmpOperand == operand) {
2031 return i;
2032 }
2033 }
2034
2035 return -1;
2036}
2037
2038// Checks if instruction contains a specific operand.
2039//
2040// @param instruction - the instruction to be checked.
2041// @param operand - the operand to search for.
2042//
2043// @return true if the instruction contains the given operand, false otherwise.
2044//
2045static inline Bool instructionContainsOperand(const Instruction* const instruction,
2046 const InstructionOperand operand) {
2047
2048 return indexOfInstructionOperand(instruction, operand) != -1;
2049}
2050
2051// Checks if invoke category instruction invokes an abstract method.
2052//
2053// @param instruction - the invoke instruction to be checked.
2054// @return true if the invoke instruction invokes an abstract method, false otherwise.
2055//
2056static inline Bool isInvocationInstructionAbstract(const Instruction* const instruction) {
2057 assert(instruction->category == $INSTRUCTION_CATEGORY_INVOKE);
2058 return instruction->operands[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND] == $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX;
2059}
2060
2061// Checks if invoke category instruction invokes a native method.
2062//
2063// @param instruction - the invoke instruction to be checked.
2064// @return true if the invoke instruction invokes a native method, false otherwise.
2065//
2066static inline Bool isInvocationInstructionNative(const Instruction* const instruction) {
2067 assert(instruction->category == $INSTRUCTION_CATEGORY_INVOKE);
2068 const Opcode opcode = instruction->opcode;
2069 return opcode >= $OPCODE_INVOKE_INATIVE && opcode <= $OPCODE_INVOKE_NATIVESEQ;
2070}
2071
2072// Checks if invoke category instruction is sequential.
2073//
2074// @param instruction - the invoke instruction to be checked.
2075// @return true if the invoke instruction is sequential, false otherwise.
2076//
2077static inline Bool isInvocationInstructionSequential(const Instruction* const instruction) {
2078 assert(instruction->category == $INSTRUCTION_CATEGORY_INVOKE);
2079 return indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_SEQUENCE_DATA) != -1;
2080}
2081
2082// Checks if native category instruction is sequential.
2083//
2084// @param instruction - the native instruction to be checked.
2085// @return true if the native instruction is sequential, false otherwise.
2086//
2087static inline Bool isNativeInstructionSequential(const Instruction* const instruction) {
2088 assert(instruction->category == $INSTRUCTION_CATEGORY_NATIVE);
2089 return instruction->opcode == $OPCODE_NATIVESEQ;
2090}
2091
2092// Checks if an instruction with a code offset performs a jump to that code offset.
2093//
2094// @param instruction - the instruction to be checked.
2095// @return true if the instruction is performing a jump to a code offset, false otherwise.
2096static inline Bool isInstructionJumpingToCodeOffset(const Instruction* const instruction) {
2097 assert(indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_CODE_OFFSET) != -1);
2098
2099 // If the crumb would be interpreted as jumping, all code in between it would
2100 // get optimized out which would make the crumb undebuggable.
2101 return instruction->opcode != $OPCODE_EXECUTE_CRUMB;
2102}
2103
2104// Checks if an instruction performing a jump is conditional.
2105//
2106// @param instruction - the instruction to be checked.
2107// @return true if the instruction performing a jump is condition, false otherwise.
2108//
2109static inline Bool isJumpInstructionConditional(const Instruction* const instruction) {
2110 assert(indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_CODE_OFFSET) != -1);
2111 assert(instruction->opcode != $OPCODE_EXECUTE_CRUMB);
2112 return instruction->opcode != $OPCODE_GOTO;
2113}
2114
2115// Fetches an instruction reflection based on opcode.
2116//
2117// @param opcode - the opcode whose instruction reflection should be fetched.
2118// @return the opcode's instruction reflection.
2119//
2120static inline const Instruction* reflectInstruction(const Opcode opcode) {
2121 static const Instruction REFLECTIONS[INSTRUCTION_N] = {
2122 {
2123 .opcode = $OPCODE_NOOP, .name = "NOOP", .length = 1, .category = $INSTRUCTION_CATEGORY_OTHER
2124 },
2125 {
2126 .opcode = $OPCODE_GOTO, .name = "GOTO", .length = 2, .category = $INSTRUCTION_CATEGORY_JUMP,
2127 .operands = { $INSTRUCTION_OPERAND_CODE_OFFSET }
2128 },
2129 {
2130 .opcode = $OPCODE_GOTOIF, .name = "GOTOIF", .length = 3, .category = $INSTRUCTION_CATEGORY_JUMP,
2131 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_CODE_OFFSET }
2132 },
2133 {
2134 .opcode = $OPCODE_GOTOIFNOT, .name = "GOTOIFNOT", .length = 3, .category = $INSTRUCTION_CATEGORY_JUMP,
2135 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_CODE_OFFSET }
2136 },
2137 {
2138 .opcode = $OPCODE_IADD, .name = "IADD", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2139 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2140 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2141 },
2142 {
2143 .opcode = $OPCODE_LADD, .name = "LADD", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2144 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2145 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2146 },
2147 {
2148 .opcode = $OPCODE_FADD, .name = "FADD", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2149 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2150 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2151 },
2152 {
2153 .opcode = $OPCODE_DADD, .name = "DADD", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2154 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2155 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2156 },
2157 {
2158 .opcode = $OPCODE_ISUB, .name = "ISUB", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2159 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2160 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2161 },
2162 {
2163 .opcode = $OPCODE_LSUB, .name = "LSUB", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2164 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2165 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2166 },
2167 {
2168 .opcode = $OPCODE_FSUB, .name = "FSUB", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2169 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2170 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2171 },
2172 {
2173 .opcode = $OPCODE_DSUB, .name = "DSUB", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2174 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2175 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2176 },
2177 {
2178 .opcode = $OPCODE_IMUL, .name = "IMUL", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2179 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2180 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2181 },
2182 {
2183 .opcode = $OPCODE_LMUL, .name = "LMUL", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2184 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2185 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2186 },
2187 {
2188 .opcode = $OPCODE_FMUL, .name = "FMUL", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2189 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2190 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2191 },
2192 {
2193 .opcode = $OPCODE_DMUL, .name = "DMUL", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2194 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2195 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2196 },
2197 {
2198 .opcode = $OPCODE_IDIV, .name = "IDIV", .length = 5, .category = $INSTRUCTION_CATEGORY_BINARY,
2199 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2200 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2201 .canCausePanic = true,
2202 },
2203 {
2204 .opcode = $OPCODE_LDIV, .name = "LDIV", .length = 5, .category = $INSTRUCTION_CATEGORY_BINARY,
2205 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2206 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2207 .canCausePanic = true
2208 },
2209 {
2210 .opcode = $OPCODE_FDIV, .name = "FDIV", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2211 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2212 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2213 },
2214 {
2215 .opcode = $OPCODE_DDIV, .name = "DDIV", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2216 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2217 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2218 },
2219 {
2220 .opcode = $OPCODE_I2B, .name = "I2B", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2221 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2222 },
2223 {
2224 .opcode = $OPCODE_I2L, .name = "I2L", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2225 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2226 },
2227 {
2228 .opcode = $OPCODE_I2F, .name = "I2F", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2229 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2230 },
2231 {
2232 .opcode = $OPCODE_I2D, .name = "I2D", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2233 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2234 },
2235 {
2236 .opcode = $OPCODE_L2B, .name = "L2B", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2237 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2238 },
2239 {
2240 .opcode = $OPCODE_L2I, .name = "L2I", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2241 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2242 },
2243 {
2244 .opcode = $OPCODE_L2F, .name = "L2F", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2245 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2246 },
2247 {
2248 .opcode = $OPCODE_L2D, .name = "L2D", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2249 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2250 },
2251 {
2252 .opcode = $OPCODE_F2B, .name = "F2B", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2253 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2254 },
2255 {
2256 .opcode = $OPCODE_F2I, .name = "F2I", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2257 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2258 },
2259 {
2260 .opcode = $OPCODE_F2L, .name = "F2L", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2261 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2262 },
2263 {
2264 .opcode = $OPCODE_F2D, .name = "F2D", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2265 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2266 },
2267 {
2268 .opcode = $OPCODE_D2B, .name = "D2B", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2269 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2270 },
2271 {
2272 .opcode = $OPCODE_D2I, .name = "D2I", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2273 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2274 },
2275 {
2276 .opcode = $OPCODE_D2L, .name = "D2L", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2277 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2278 },
2279 {
2280 .opcode = $OPCODE_D2F, .name = "D2F", .length = 3, .category = $INSTRUCTION_CATEGORY_CAST,
2281 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2282 },
2283 {
2284 .opcode = $OPCODE_NEW, .name = "NEW", .length = 4, .category = $INSTRUCTION_CATEGORY_ALLOCATION,
2285 .operands = { $INSTRUCTION_OPERAND_CLASS_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
2286 $INSTRUCTION_OPERAND_LOCATION },
2287 .canCausePanic = true, .canCauseGc = true
2288 },
2289 {
2290 .opcode = $OPCODE_OLD, .name = "OLD", .length = 4, .category = $INSTRUCTION_CATEGORY_ALLOCATION,
2291 .operands = { $INSTRUCTION_OPERAND_CLASS_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
2292 $INSTRUCTION_OPERAND_LOCATION },
2293 .canCausePanic = true, .canCauseGc = true
2294 },
2295 {
2296 .opcode = $OPCODE_TMP, .name = "TMP", .length = 5, .category = $INSTRUCTION_CATEGORY_ALLOCATION,
2297 .operands = { $INSTRUCTION_OPERAND_CLASS_INDEX, $INSTRUCTION_OPERAND_TMP_INDEX,
2298 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2299 .canCausePanic = true, .canCauseGc = true
2300 },
2301 {
2302 .opcode = $OPCODE_IMOVE, .name = "IMOVE", .length = 3, .category = $INSTRUCTION_CATEGORY_MOVE,
2303 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2304 },
2305 {
2306 .opcode = $OPCODE_LMOVE, .name = "LMOVE", .length = 3, .category = $INSTRUCTION_CATEGORY_MOVE,
2307 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2308 },
2309 {
2310 .opcode = $OPCODE_FMOVE, .name = "FMOVE", .length = 3, .category = $INSTRUCTION_CATEGORY_MOVE,
2311 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2312 },
2313 {
2314 .opcode = $OPCODE_DMOVE, .name = "DMOVE", .length = 3, .category = $INSTRUCTION_CATEGORY_MOVE,
2315 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2316 },
2317 {
2318 .opcode = $OPCODE_OMOVE, .name = "OMOVE", .length = 3, .category = $INSTRUCTION_CATEGORY_MOVE,
2319 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT }
2320 },
2321 {
2322 .opcode = $OPCODE_IIS, .name = "IIS", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2323 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2324 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2325 },
2326 {
2327 .opcode = $OPCODE_LIS, .name = "LIS", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2328 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2329 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2330 },
2331 {
2332 .opcode = $OPCODE_FIS, .name = "FIS", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2333 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2334 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2335 },
2336 {
2337 .opcode = $OPCODE_DIS, .name = "DIS", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2338 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2339 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2340 },
2341 {
2342 .opcode = $OPCODE_OIS, .name = "OIS", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2343 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
2344 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2345 },
2346 {
2347 .opcode = $OPCODE_IISNT, .name = "IISNT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2348 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2349 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2350 },
2351 {
2352 .opcode = $OPCODE_LISNT, .name = "LISNT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2353 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2354 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2355 },
2356 {
2357 .opcode = $OPCODE_FISNT, .name = "FISNT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2358 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2359 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2360 },
2361 {
2362 .opcode = $OPCODE_DISNT, .name = "DISNT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2363 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2364 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2365 },
2366 {
2367 .opcode = $OPCODE_OISNT, .name = "OISNT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2368 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
2369 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2370 },
2371 {
2372 .opcode = $OPCODE_OR, .name = "OR", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2373 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2374 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2375 },
2376 {
2377 .opcode = $OPCODE_AND, .name = "AND", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2378 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2379 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2380 },
2381 {
2382 .opcode = $OPCODE_ILT, .name = "ILT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2383 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2384 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2385 },
2386 {
2387 .opcode = $OPCODE_LLT, .name = "LLT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2388 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2389 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2390 },
2391 {
2392 .opcode = $OPCODE_FLT, .name = "FLT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2393 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2394 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2395 },
2396 {
2397 .opcode = $OPCODE_DLT, .name = "DLT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2398 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2399 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2400 },
2401 {
2402 .opcode = $OPCODE_ILTE, .name = "ILTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2403 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2404 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2405 },
2406 {
2407 .opcode = $OPCODE_LLTE, .name = "LLTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2408 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2409 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2410 },
2411 {
2412 .opcode = $OPCODE_FLTE, .name = "FLTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2413 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2414 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2415 },
2416 {
2417 .opcode = $OPCODE_DLTE, .name = "DLTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2418 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2419 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2420 },
2421 {
2422 .opcode = $OPCODE_IGT, .name = "IGT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2423 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2424 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2425 },
2426 {
2427 .opcode = $OPCODE_LGT, .name = "LGT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2428 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2429 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2430 },
2431 {
2432 .opcode = $OPCODE_FGT, .name = "FGT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2433 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2434 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2435 },
2436 {
2437 .opcode = $OPCODE_DGT, .name = "DGT", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2438 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2439 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2440 },
2441 {
2442 .opcode = $OPCODE_IGTE, .name = "IGTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2443 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2444 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2445 },
2446 {
2447 .opcode = $OPCODE_LGTE, .name = "LGTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2448 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2449 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2450 },
2451 {
2452 .opcode = $OPCODE_FGTE, .name = "FGTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2453 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2454 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2455 },
2456 {
2457 .opcode = $OPCODE_DGTE, .name = "DGTE", .length = 4, .category = $INSTRUCTION_CATEGORY_BINARY,
2458 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2459 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2460 },
2461 {
2462 .opcode = $OPCODE_CHKTYPE, .name = "CHKTYPE", .length = 5, .category = $INSTRUCTION_CATEGORY_CAST,
2463 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_CLASS_INDEX,
2464 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2465 .canCausePanic = true
2466 },
2467 {
2468 .opcode = $OPCODE_GLOBAL, .name = "GLOBAL", .length = 4, .category = $INSTRUCTION_CATEGORY_VALUE,
2469 .operands = { $INSTRUCTION_OPERAND_CLASS_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
2470 $INSTRUCTION_OPERAND_LOCATION },
2471 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true,
2472 },
2473 {
2474 .opcode = $OPCODE_TEXT, .name = "TEXT", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2475 .operands = { $INSTRUCTION_OPERAND_TEXT_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT }
2476 },
2477 {
2478 .opcode = $OPCODE_NULL, .name = "NULL", .length = 2, .category = $INSTRUCTION_CATEGORY_VALUE,
2479 .operands = { $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT }
2480 },
2481 {
2482 .opcode = $OPCODE_FALSE, .name = "FALSE", .length = 2, .category = $INSTRUCTION_CATEGORY_VALUE,
2483 .operands = { $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2484 },
2485 {
2486 .opcode = $OPCODE_TRUE, .name = "TRUE", .length = 2, .category = $INSTRUCTION_CATEGORY_VALUE,
2487 .operands = { $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2488 },
2489 {
2490 .opcode = $OPCODE_CHAR, .name = "CHAR", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2491 .operands = { $INSTRUCTION_OPERAND_INT_VALUE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2492 },
2493 {
2494 .opcode = $OPCODE_INT, .name = "INT", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2495 .operands = { $INSTRUCTION_OPERAND_INT_VALUE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2496 },
2497 {
2498 .opcode = $OPCODE_LONG, .name = "LONG", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2499 .operands = { $INSTRUCTION_OPERAND_LONG_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2500 },
2501 {
2502 .opcode = $OPCODE_DIRLONG, .name = "DIRLONG", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2503 .operands = { $INSTRUCTION_OPERAND_INT_VALUE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2504 },
2505 {
2506 .opcode = $OPCODE_FLOAT, .name = "FLOAT", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2507 .operands = { $INSTRUCTION_OPERAND_FLOAT_BITS, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2508 },
2509 {
2510 .opcode = $OPCODE_DOUBLE, .name = "DOUBLE", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2511 .operands = { $INSTRUCTION_OPERAND_DOUBLE_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2512 },
2513 {
2514 .opcode = $OPCODE_DIRDOUBLE, .name = "DIRDOUBLE", .length = 3, .category = $INSTRUCTION_CATEGORY_VALUE,
2515 .operands = { $INSTRUCTION_OPERAND_FLOAT_BITS, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2516 },
2517 {
2518 .opcode = $OPCODE_INEG, .name = "INEG", .length = 3, .category = $INSTRUCTION_CATEGORY_UNARY,
2519 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2520 },
2521 {
2522 .opcode = $OPCODE_LNEG, .name = "LNEG", .length = 3, .category = $INSTRUCTION_CATEGORY_UNARY,
2523 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2524 },
2525 {
2526 .opcode = $OPCODE_FNEG, .name = "FNEG", .length = 3, .category = $INSTRUCTION_CATEGORY_UNARY,
2527 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2528 },
2529 {
2530 .opcode = $OPCODE_DNEG, .name = "DNEG", .length = 3, .category = $INSTRUCTION_CATEGORY_UNARY,
2531 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2532 },
2533 {
2534 .opcode = $OPCODE_NOT, .name = "NOT", .length = 3, .category = $INSTRUCTION_CATEGORY_UNARY,
2535 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2536 },
2537 {
2538 .opcode = $OPCODE_IGETFIELD, .name = "IGETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2539 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_FIELD_OFFSET,
2540 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2541 .canCausePanic = true
2542 },
2543 {
2544 .opcode = $OPCODE_LGETFIELD, .name = "LGETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2545 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_FIELD_OFFSET,
2546 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2547 .canCausePanic = true
2548 },
2549 {
2550 .opcode = $OPCODE_FGETFIELD, .name = "FGETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2551 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_FIELD_OFFSET,
2552 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
2553 .canCausePanic = true
2554 },
2555 {
2556 .opcode = $OPCODE_DGETFIELD, .name = "DGETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2557 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_FIELD_OFFSET,
2558 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
2559 .canCausePanic = true
2560 },
2561 {
2562 .opcode = $OPCODE_OGETFIELD, .name = "OGETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2563 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_FIELD_OFFSET,
2564 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2565 .canCausePanic = true
2566 },
2567 {
2568 .opcode = $OPCODE_ISETFIELD, .name = "ISETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2569 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2570 $INSTRUCTION_OPERAND_FIELD_OFFSET, $INSTRUCTION_OPERAND_LOCATION },
2571 .canCausePanic = true
2572 },
2573 {
2574 .opcode = $OPCODE_LSETFIELD, .name = "LSETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2575 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2576 $INSTRUCTION_OPERAND_FIELD_OFFSET, $INSTRUCTION_OPERAND_LOCATION },
2577 .canCausePanic = true
2578 },
2579 {
2580 .opcode = $OPCODE_FSETFIELD, .name = "FSETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2581 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2582 $INSTRUCTION_OPERAND_FIELD_OFFSET, $INSTRUCTION_OPERAND_LOCATION },
2583 .canCausePanic = true,
2584 },
2585 {
2586 .opcode = $OPCODE_DSETFIELD, .name = "DSETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2587 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2588 $INSTRUCTION_OPERAND_FIELD_OFFSET, $INSTRUCTION_OPERAND_LOCATION },
2589 .canCausePanic = true
2590 },
2591 {
2592 .opcode = $OPCODE_OSETFIELD, .name = "OSETFIELD", .length = 5, .category = $INSTRUCTION_CATEGORY_FIELD_ACCESS,
2593 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
2594 $INSTRUCTION_OPERAND_FIELD_OFFSET, $INSTRUCTION_OPERAND_LOCATION },
2595 .canCausePanic = true
2596 },
2597 {
2598 .opcode = $OPCODE_INVOKE, .name = "INVOKE", .length = 4, .category = $INSTRUCTION_CATEGORY_INVOKE,
2599 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2600 $INSTRUCTION_OPERAND_LOCATION },
2601 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2602 },
2603 {
2604 .opcode = $OPCODE_AINVOKE, .name = "AINVOKE", .length = 4, .category = $INSTRUCTION_CATEGORY_INVOKE,
2605 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX,
2606 $INSTRUCTION_OPERAND_LOCATION },
2607 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2608 },
2609 {
2610 .opcode = $OPCODE_INVOKESEQ, .name = "INVOKESEQ", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2611 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2612 $INSTRUCTION_OPERAND_SEQUENCE_DATA, $INSTRUCTION_OPERAND_LOCATION },
2613 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2614 },
2615 {
2616 .opcode = $OPCODE_AINVOKESEQ, .name = "AINVOKESEQ", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2617 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX,
2618 $INSTRUCTION_OPERAND_SEQUENCE_DATA, $INSTRUCTION_OPERAND_LOCATION },
2619 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2620 },
2621 {
2622 .opcode = $OPCODE_IRETURN, .name = "IRETURN", .length = 2, .category = $INSTRUCTION_CATEGORY_RETURN,
2623 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT }
2624 },
2625 {
2626 .opcode = $OPCODE_LRETURN, .name = "LRETURN", .length = 2, .category = $INSTRUCTION_CATEGORY_RETURN,
2627 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG }
2628 },
2629 {
2630 .opcode = $OPCODE_FRETURN, .name = "FRETURN", .length = 2, .category = $INSTRUCTION_CATEGORY_RETURN,
2631 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT }
2632 },
2633 {
2634 .opcode = $OPCODE_DRETURN, .name = "DRETURN", .length = 2, .category = $INSTRUCTION_CATEGORY_RETURN,
2635 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE }
2636 },
2637 {
2638 .opcode = $OPCODE_ORETURN, .name = "ORETURN", .length = 2, .category = $INSTRUCTION_CATEGORY_RETURN,
2639 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT }
2640 },
2641 {
2642 .opcode = $OPCODE_RETURN, .name = "RETURN", .length = 1, .category = $INSTRUCTION_CATEGORY_RETURN
2643 },
2644 {
2645 .opcode = $OPCODE_INATIVE, .name = "INATIVE", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2646 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2647 },
2648 {
2649 .opcode = $OPCODE_LNATIVE, .name = "LNATIVE", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2650 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2651 },
2652 {
2653 .opcode = $OPCODE_FNATIVE, .name = "FNATIVE", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2654 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2655 },
2656 {
2657 .opcode = $OPCODE_DNATIVE, .name = "DNATIVE", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2658 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2659 },
2660 {
2661 .opcode = $OPCODE_ONATIVE, .name = "ONATIVE", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2662 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2663 },
2664 {
2665 .opcode = $OPCODE_NATIVESEQ, .name = "NATIVESEQ", .length = 1, .category = $INSTRUCTION_CATEGORY_NATIVE,
2666 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2667 },
2668 {
2669 .opcode = $OPCODE_UNIMPLEMENTED, .name = "UNIMPLEMENTED", .length = 1, .category = $INSTRUCTION_CATEGORY_OTHER,
2670 .canCausePanic = true
2671 },
2672 {
2673 .opcode = $OPCODE_EXIT_EXECUTE, .name = "EXIT_EXECUTE", .length = 1, .category = $INSTRUCTION_CATEGORY_OTHER
2674 },
2675 {
2676 .opcode = $OPCODE_GLOBAL_INITIALIZED, .name = "GLOBAL_INITIALIZED", .length = 4,
2677 .category = $INSTRUCTION_CATEGORY_VALUE,
2678 .operands = { $INSTRUCTION_OPERAND_CLASS_INDEX, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
2679 $INSTRUCTION_OPERAND_LOCATION }
2680 },
2681 {
2682 .opcode = $OPCODE_INVOKE_INITIALIZED, .name = "INVOKE_INITIALIZED", .length = 4,
2683 .category = $INSTRUCTION_CATEGORY_INVOKE,
2684 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2685 $INSTRUCTION_OPERAND_LOCATION },
2686 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2687 },
2688 {
2689 .opcode = $OPCODE_INVOKESEQ_INITIALIZED, .name = "INVOKESEQ_INITIALIZED", .length = 5,
2690 .category = $INSTRUCTION_CATEGORY_INVOKE,
2691 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2692 $INSTRUCTION_OPERAND_SEQUENCE_DATA, $INSTRUCTION_OPERAND_LOCATION },
2693 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2694 },
2695 {
2696 .opcode = $OPCODE_INVOKE_INATIVE, .name = "INVOKE_INATIVE", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2697 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2698 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2699 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2700 },
2701 {
2702 .opcode = $OPCODE_INVOKE_LNATIVE, .name = "INVOKE_LNATIVE", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2703 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2704 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2705 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2706 },
2707 {
2708 .opcode = $OPCODE_INVOKE_FNATIVE, .name = "INVOKE_FNATIVE", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2709 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2710 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
2711 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2712 },
2713 {
2714 .opcode = $OPCODE_INVOKE_DNATIVE, .name = "INVOKE_DNATIVE", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2715 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2716 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
2717 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2718 },
2719 {
2720 .opcode = $OPCODE_INVOKE_ONATIVE, .name = "INVOKE_ONATIVE", .length = 5, .category = $INSTRUCTION_CATEGORY_INVOKE,
2721 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2722 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2723 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2724 },
2725 {
2726 .opcode = $OPCODE_INVOKE_NATIVESEQ, .name = "INVOKE_NATIVESEQ", .length = 6,
2727 .category = $INSTRUCTION_CATEGORY_INVOKE,
2728 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_METHOD_INDEX,
2729 $INSTRUCTION_OPERAND_SEQUENCE_DATA, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT,
2730 $INSTRUCTION_OPERAND_LOCATION },
2731 .canCausePanic = true, .canCauseGc = true, .canCauseFrame = true
2732 },
2733 {
2734 .opcode = $OPCODE_CHKNULL_INLINE_INVOKE, .name = "CHKNULL_INLINE_INVOKE", .length = 3,
2735 .category = $INSTRUCTION_CATEGORY_OTHER,
2736 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2737 .canCausePanic = true
2738 },
2739 {
2740 .opcode = $OPCODE_INLINE_INVOKE, .name = "INLINE_INVOKE", .length = 2, .category = $INSTRUCTION_CATEGORY_OTHER,
2741 .operands = { $INSTRUCTION_OPERAND_LOCATION }
2742 },
2743 {
2744 .opcode = $OPCODE_EXECUTE_CRUMB, .name = "EXECUTE_CRUMB", .length = 4, .category = $INSTRUCTION_CATEGORY_OTHER,
2745 .operands = { $INSTRUCTION_OPERAND_CRUMB_INDEX, $INSTRUCTION_OPERAND_CODE_OFFSET, $INSTRUCTION_OPERAND_LOCATION }
2746 },
2747 {
2748 .opcode = $OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT, .name = "LIB_BUILTINS_UNSAFE_DIV_INT", .length = 4,
2749 .category = $INSTRUCTION_CATEGORY_LIB,
2750 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2751 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2752 },
2753 {
2754 .opcode = $OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG, .name = "LIB_BUILTINS_UNSAFE_DIV_LONG", .length = 4,
2755 .category = $INSTRUCTION_CATEGORY_LIB,
2756 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2757 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2758 },
2759 {
2760 .opcode = $OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX, .name = "LIB_BUILTINS_RANGE_CHECK_MIN_MAX", .length = 5,
2761 .category = $INSTRUCTION_CATEGORY_LIB,
2762 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2763 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2764 },
2765 {
2766 .opcode = $OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX, .name = "LIB_BUILTINS_RANGE_CHECK_0_MAX", .length = 3,
2767 .category = $INSTRUCTION_CATEGORY_LIB,
2768 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2769 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2770 },
2771 {
2772 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_NOT_INT, .name = "LIB_BUILTINS_BITWISE_NOT_INT", .length = 3,
2773 .category = $INSTRUCTION_CATEGORY_LIB,
2774 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2775 },
2776 {
2777 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG, .name = "LIB_BUILTINS_BITWISE_NOT_LONG", .length = 3,
2778 .category = $INSTRUCTION_CATEGORY_LIB,
2779 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2780 },
2781 {
2782 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_AND_INT, .name = "LIB_BUILTINS_BITWISE_AND_INT", .length = 4,
2783 .category = $INSTRUCTION_CATEGORY_LIB,
2784 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2785 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2786 },
2787 {
2788 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_AND_LONG, .name = "LIB_BUILTINS_BITWISE_AND_LONG", .length = 4,
2789 .category = $INSTRUCTION_CATEGORY_LIB,
2790 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2791 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2792 },
2793 {
2794 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_OR_INT, .name = "LIB_BUILTINS_BITWISE_OR_INT", .length = 4,
2795 .category = $INSTRUCTION_CATEGORY_LIB,
2796 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2797 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2798 },
2799 {
2800 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_OR_LONG, .name = "LIB_BUILTINS_BITWISE_OR_LONG", .length = 4,
2801 .category = $INSTRUCTION_CATEGORY_LIB,
2802 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2803 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2804 },
2805 {
2806 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_XOR_INT, .name = "LIB_BUILTINS_BITWISE_XOR_INT", .length = 4,
2807 .category = $INSTRUCTION_CATEGORY_LIB,
2808 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2809 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2810 },
2811 {
2812 .opcode = $OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG, .name = "LIB_BUILTINS_BITWISE_XOR_LONG", .length = 4,
2813 .category = $INSTRUCTION_CATEGORY_LIB,
2814 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2815 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2816 },
2817 {
2818 .opcode = $OPCODE_LIB_BUILTINS_LSHIFT_INT, .name = "LIB_BUILTINS_LSHIFT_INT", .length = 4,
2819 .category = $INSTRUCTION_CATEGORY_LIB,
2820 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2821 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2822 },
2823 {
2824 .opcode = $OPCODE_LIB_BUILTINS_LSHIFT_LONG, .name = "LIB_BUILTINS_LSHIFT_LONG", .length = 4,
2825 .category = $INSTRUCTION_CATEGORY_LIB,
2826 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2827 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2828 },
2829 {
2830 .opcode = $OPCODE_LIB_BUILTINS_RSHIFT_INT, .name = "LIB_BUILTINS_RSHIFT_INT", .length = 4,
2831 .category = $INSTRUCTION_CATEGORY_LIB,
2832 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2833 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2834 },
2835 {
2836 .opcode = $OPCODE_LIB_BUILTINS_RSHIFT_LONG, .name = "LIB_BUILTINS_RSHIFT_LONG", .length = 4,
2837 .category = $INSTRUCTION_CATEGORY_LIB,
2838 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2839 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2840 },
2841 {
2842 .opcode = $OPCODE_LIB_BUILTINS_URSHIFT_INT, .name = "LIB_BUILTINS_URSHIFT_INT", .length = 4,
2843 .category = $INSTRUCTION_CATEGORY_LIB,
2844 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2845 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2846 },
2847 {
2848 .opcode = $OPCODE_LIB_BUILTINS_URSHIFT_LONG, .name = "LIB_BUILTINS_URSHIFT_LONG", .length = 4,
2849 .category = $INSTRUCTION_CATEGORY_LIB,
2850 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2851 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2852 },
2853 {
2854 .opcode = $OPCODE_LIB_BUILTINS_ABS_INT, .name = "LIB_BUILTINS_ABS_INT", .length = 3,
2855 .category = $INSTRUCTION_CATEGORY_LIB,
2856 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2857 },
2858 {
2859 .opcode = $OPCODE_LIB_BUILTINS_ABS_LONG, .name = "LIB_BUILTINS_ABS_LONG", .length = 3,
2860 .category = $INSTRUCTION_CATEGORY_LIB,
2861 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2862 },
2863 {
2864 .opcode = $OPCODE_LIB_BUILTINS_ABS_FLOAT, .name = "LIB_BUILTINS_ABS_FLOAT", .length = 3,
2865 .category = $INSTRUCTION_CATEGORY_LIB,
2866 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2867 },
2868 {
2869 .opcode = $OPCODE_LIB_BUILTINS_ABS_DOUBLE, .name = "LIB_BUILTINS_ABS_DOUBLE", .length = 3,
2870 .category = $INSTRUCTION_CATEGORY_LIB,
2871 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2872 },
2873 {
2874 .opcode = $OPCODE_LIB_BUILTINS_MIN_INT, .name = "LIB_BUILTINS_MIN_INT", .length = 4,
2875 .category = $INSTRUCTION_CATEGORY_LIB,
2876 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2877 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2878 },
2879 {
2880 .opcode = $OPCODE_LIB_BUILTINS_MIN_LONG, .name = "LIB_BUILTINS_MIN_LONG", .length = 4,
2881 .category = $INSTRUCTION_CATEGORY_LIB,
2882 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2883 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2884 },
2885 {
2886 .opcode = $OPCODE_LIB_BUILTINS_MIN_FLOAT, .name = "LIB_BUILTINS_MIN_FLOAT", .length = 4,
2887 .category = $INSTRUCTION_CATEGORY_LIB,
2888 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2889 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2890 },
2891 {
2892 .opcode = $OPCODE_LIB_BUILTINS_MIN_DOUBLE, .name = "LIB_BUILTINS_MIN_DOUBLE", .length = 4,
2893 .category = $INSTRUCTION_CATEGORY_LIB,
2894 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2895 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2896 },
2897 {
2898 .opcode = $OPCODE_LIB_BUILTINS_MAX_INT, .name = "LIB_BUILTINS_MAX_INT", .length = 4,
2899 .category = $INSTRUCTION_CATEGORY_LIB,
2900 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2901 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT }
2902 },
2903 {
2904 .opcode = $OPCODE_LIB_BUILTINS_MAX_LONG, .name = "LIB_BUILTINS_MAX_LONG", .length = 4,
2905 .category = $INSTRUCTION_CATEGORY_LIB,
2906 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2907 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG }
2908 },
2909 {
2910 .opcode = $OPCODE_LIB_BUILTINS_MAX_FLOAT, .name = "LIB_BUILTINS_MAX_FLOAT", .length = 4,
2911 .category = $INSTRUCTION_CATEGORY_LIB,
2912 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2913 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2914 },
2915 {
2916 .opcode = $OPCODE_LIB_BUILTINS_MAX_DOUBLE, .name = "LIB_BUILTINS_MAX_DOUBLE", .length = 4,
2917 .category = $INSTRUCTION_CATEGORY_LIB,
2918 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2919 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2920 },
2921 {
2922 .opcode = $OPCODE_LIB_BUILTINS_REMAINER_INT, .name = "LIB_BUILTINS_REMAINER_INT", .length = 5,
2923 .category = $INSTRUCTION_CATEGORY_LIB,
2924 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2925 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2926 .canCausePanic = true
2927 },
2928 {
2929 .opcode = $OPCODE_LIB_BUILTINS_REMAINER_LONG, .name = "LIB_BUILTINS_REMAINER_LONG", .length = 5,
2930 .category = $INSTRUCTION_CATEGORY_LIB,
2931 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG,
2932 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2933 .canCausePanic = true
2934 },
2935 {
2936 .opcode = $OPCODE_LIB_BUILTINS_REMAINER_FLOAT, .name = "LIB_BUILTINS_REMAINER_FLOAT", .length = 4,
2937 .category = $INSTRUCTION_CATEGORY_LIB,
2938 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT,
2939 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT }
2940 },
2941 {
2942 .opcode = $OPCODE_LIB_BUILTINS_REMAINER_DOUBLE, .name = "LIB_BUILTINS_REMAINER_DOUBLE", .length = 4,
2943 .category = $INSTRUCTION_CATEGORY_LIB,
2944 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE,
2945 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE }
2946 },
2947 {
2948 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT, .name = "LIB_BUILTINS_ARRAY_AT_GET_INT", .length = 5,
2949 .category = $INSTRUCTION_CATEGORY_LIB,
2950 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2951 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2952 .canCausePanic = true
2953 },
2954 {
2955 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG, .name = "LIB_BUILTINS_ARRAY_AT_GET_LONG", .length = 5,
2956 .category = $INSTRUCTION_CATEGORY_LIB,
2957 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2958 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2959 .canCausePanic = true
2960 },
2961 {
2962 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT, .name = "LIB_BUILTINS_ARRAY_AT_GET_FLOAT", .length = 5,
2963 .category = $INSTRUCTION_CATEGORY_LIB,
2964 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2965 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
2966 .canCausePanic = true
2967 },
2968 {
2969 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE, .name = "LIB_BUILTINS_ARRAY_AT_GET_DOUBLE", .length = 5,
2970 .category = $INSTRUCTION_CATEGORY_LIB,
2971 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2972 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
2973 .canCausePanic = true
2974 },
2975 {
2976 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT, .name = "LIB_BUILTINS_ARRAY_AT_GET_OBJECT", .length = 5,
2977 .category = $INSTRUCTION_CATEGORY_LIB,
2978 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2979 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
2980 .canCausePanic = true
2981 },
2982 {
2983 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT, .name = "LIB_BUILTINS_ARRAY_AT_SET_INT", .length = 5,
2984 .category = $INSTRUCTION_CATEGORY_LIB,
2985 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2986 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
2987 .canCausePanic = true
2988 },
2989 {
2990 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG, .name = "LIB_BUILTINS_ARRAY_AT_SET_LONG", .length = 5,
2991 .category = $INSTRUCTION_CATEGORY_LIB,
2992 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
2993 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
2994 .canCausePanic = true
2995 },
2996 {
2997 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT, .name = "LIB_BUILTINS_ARRAY_AT_SET_FLOAT", .length = 5,
2998 .category = $INSTRUCTION_CATEGORY_LIB,
2999 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3000 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
3001 .canCausePanic = true
3002 },
3003 {
3004 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE, .name = "LIB_BUILTINS_ARRAY_AT_SET_DOUBLE", .length = 5,
3005 .category = $INSTRUCTION_CATEGORY_LIB,
3006 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3007 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
3008 .canCausePanic = true
3009 },
3010 {
3011 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT, .name = "LIB_BUILTINS_ARRAY_AT_SET_OBJECT", .length = 5,
3012 .category = $INSTRUCTION_CATEGORY_LIB,
3013 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3014 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_LOCATION },
3015 .canCausePanic = true
3016 },
3017 {
3018 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_INC_INT, .name = "LIB_BUILTINS_ARRAY_INC_INT", .length = 5,
3019 .category = $INSTRUCTION_CATEGORY_LIB,
3020 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3021 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
3022 .canCausePanic = true
3023 },
3024 {
3025 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_INC_LONG, .name = "LIB_BUILTINS_ARRAY_INC_LONG", .length = 5,
3026 .category = $INSTRUCTION_CATEGORY_LIB,
3027 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3028 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
3029 .canCausePanic = true
3030 },
3031 {
3032 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT, .name = "LIB_BUILTINS_ARRAY_INC_FLOAT", .length = 5,
3033 .category = $INSTRUCTION_CATEGORY_LIB,
3034 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3035 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
3036 .canCausePanic = true
3037 },
3038 {
3039 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE, .name = "LIB_BUILTINS_ARRAY_INC_DOUBLE", .length = 5,
3040 .category = $INSTRUCTION_CATEGORY_LIB,
3041 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3042 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
3043 .canCausePanic = true
3044 },
3045 {
3046 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_DEC_INT, .name = "LIB_BUILTINS_ARRAY_DEC_INT", .length = 5,
3047 .category = $INSTRUCTION_CATEGORY_LIB,
3048 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3049 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT, $INSTRUCTION_OPERAND_LOCATION },
3050 .canCausePanic = true
3051 },
3052 {
3053 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG, .name = "LIB_BUILTINS_ARRAY_DEC_LONG", .length = 5,
3054 .category = $INSTRUCTION_CATEGORY_LIB,
3055 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3056 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG, $INSTRUCTION_OPERAND_LOCATION },
3057 .canCausePanic = true
3058 },
3059 {
3060 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT, .name = "LIB_BUILTINS_ARRAY_DEC_FLOAT", .length = 5,
3061 .category = $INSTRUCTION_CATEGORY_LIB,
3062 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3063 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT, $INSTRUCTION_OPERAND_LOCATION },
3064 .canCausePanic = true
3065 },
3066 {
3067 .opcode = $OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE, .name = "LIB_BUILTINS_ARRAY_DEC_DOUBLE", .length = 5,
3068 .category = $INSTRUCTION_CATEGORY_LIB,
3069 .operands = { $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT,
3070 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE, $INSTRUCTION_OPERAND_LOCATION },
3071 .canCausePanic = true
3072 }
3073 };
3074
3075 #ifdef COOKEE_DEBUG
3076
3077 static Bool reflectionValidated = false;
3078
3079 #define CHK_REQ_OPERAND(_instruction_, _operand_, _index_) { \
3080 const Instruction* const _locInstruction_ = _instruction_; \
3081 assert(_locInstruction_->length - 1 > _index_); \
3082 assert(_locInstruction_->operands[_index_] == _operand_); \
3083 }
3084
3085 if(!reflectionValidated) {
3086 printf("Validating instruction reflections...\n");
3087
3088 for(Uint32 i = 0; i < INSTRUCTION_N; i += 1) {
3089 const Instruction* const instruction = &REFLECTIONS[i];
3090
3091 // Instructions have to be correctly ordered inside the reflection array.
3092 assert(instruction->opcode == i);
3093
3094 if(instruction->category == $INSTRUCTION_CATEGORY_INVOKE) {
3095 CHK_REQ_OPERAND(instruction,
3096 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
3097 INVOCATION_INSTRUCTION_SOURCE_OFFSET_OPERAND);
3098
3099 assert(instruction->length - 1 > INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND);
3100 const InstructionOperand indexOperand = instruction->operands[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND];
3101
3102 assert(indexOperand == $INSTRUCTION_OPERAND_METHOD_INDEX ||
3103 indexOperand == $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX);
3104
3105 const Uint32 sequenceDataIndex = indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_SEQUENCE_DATA);
3106 if(sequenceDataIndex != -1) {
3107 assert(sequenceDataIndex == INVOCATION_INSTRUCTION_SEQUENCE_DATA_OPERAND);
3108 }
3109
3110 assert(instruction->length <= MAX_INVOCATION_INSTRUCTION_LENGTH);
3111 }
3112 else if(instruction->category == $INSTRUCTION_CATEGORY_RETURN) {
3113 if(instructionContainsOperand(instruction, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT) ||
3114 instructionContainsOperand(instruction, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG) ||
3115 instructionContainsOperand(instruction, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT) ||
3116 instructionContainsOperand(instruction, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE) ||
3117 instructionContainsOperand(instruction, $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT)){
3118
3119 const InstructionOperand srcOperand = instruction->operands[RETURN_INSTRUCTION_SOURCE_OFFSET_OPERAND];
3120
3121 assert(srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT ||
3122 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG ||
3123 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT ||
3124 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE ||
3125 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT);
3126 }
3127 }
3128 else if(instruction->category == $INSTRUCTION_CATEGORY_MOVE) {
3129 assert(instruction->length - 1 > MOVE_INSTRUCTION_SRC_OFFSET_OPERAND);
3130 assert(instruction->length - 1 > MOVE_INSTRUCTION_DST_OFFSET_OPERAND);
3131
3132 const InstructionOperand srcOperand = instruction->operands[MOVE_INSTRUCTION_SRC_OFFSET_OPERAND];
3133 const InstructionOperand dstOperand = instruction->operands[MOVE_INSTRUCTION_DST_OFFSET_OPERAND];
3134
3135 assert(srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT ||
3136 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG ||
3137 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT ||
3138 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE ||
3139 srcOperand == $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT);
3140
3141 assert(dstOperand == $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT ||
3142 dstOperand == $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG ||
3143 dstOperand == $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT ||
3144 dstOperand == $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE ||
3145 dstOperand == $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT);
3146 }
3147 else if(instruction->category == $INSTRUCTION_CATEGORY_FIELD_ACCESS) {
3148 CHK_REQ_OPERAND(instruction,
3149 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT,
3150 FIELD_ACCESS_INSTRUCTION_SOURCE_OFFSET_OPERAND);
3151 }
3152
3153 Uint32 dstOffsets = 0;
3154 Uint32 codeOffsets = 0;
3155
3156 const InstructionOperand* const operand = instruction->operands;
3157
3158 for(Uint32 ii = 0; ii < instruction->length - 1; ii += 1) {
3159 switch(operand[ii]) {
3160 case $INSTRUCTION_OPERAND_CODE_OFFSET:
3161 codeOffsets += 1;
3162 break;
3163
3164 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT:
3165 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG:
3166 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT:
3167 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE:
3168 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT:
3169 dstOffsets += 1;
3170 break;
3171
3172 default: break;
3173 }
3174 }
3175
3176 assert(codeOffsets <= MAX_INSTRUCTION_CODE_OFFSETS);
3177
3178 const Int32 locationOperandIndex = indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_LOCATION);
3179
3180 if(locationOperandIndex != -1) {
3181 assert(locationOperandIndex == instruction->length - 2);
3182 }
3183 }
3184
3185 // Validate other operand placement.
3186 CHK_REQ_OPERAND(&REFLECTIONS[$OPCODE_GLOBAL], $INSTRUCTION_OPERAND_CLASS_INDEX, GLOBAL_INSTRUCTION_CLASS_INDEX_OPERAND);
3187 CHK_REQ_OPERAND(&REFLECTIONS[$OPCODE_TEXT], $INSTRUCTION_OPERAND_TEXT_INDEX, TEXT_INSTRUCTION_TEXT_INDEX_OPERAND);
3188 CHK_REQ_OPERAND(&REFLECTIONS[$OPCODE_TMP], $INSTRUCTION_OPERAND_CLASS_INDEX, TMP_INSTRUCTION_CLASS_INDEX_OPERAND);
3189 CHK_REQ_OPERAND(&REFLECTIONS[$OPCODE_OLD], $INSTRUCTION_OPERAND_CLASS_INDEX, OLD_INSTRUCTION_CLASS_INDEX_OPERAND);
3190
3191 // Validate opcode ordering.
3192 assert($OPCODE_INVOKE_INATIVE == $OPCODE_INVOKE_LNATIVE - 1);
3193 assert($OPCODE_INVOKE_LNATIVE == $OPCODE_INVOKE_FNATIVE - 1);
3194 assert($OPCODE_INVOKE_FNATIVE == $OPCODE_INVOKE_DNATIVE - 1);
3195 assert($OPCODE_INVOKE_DNATIVE == $OPCODE_INVOKE_ONATIVE - 1);
3196 assert($OPCODE_INATIVE == $OPCODE_LNATIVE - 1);
3197 assert($OPCODE_LNATIVE == $OPCODE_FNATIVE - 1);
3198 assert($OPCODE_FNATIVE == $OPCODE_DNATIVE - 1);
3199 assert($OPCODE_DNATIVE == $OPCODE_ONATIVE - 1);
3200 assert($OPCODE_IRETURN == $OPCODE_LRETURN - 1);
3201 assert($OPCODE_LRETURN == $OPCODE_FRETURN - 1);
3202 assert($OPCODE_FRETURN == $OPCODE_DRETURN - 1);
3203 assert($OPCODE_DRETURN == $OPCODE_ORETURN - 1);
3204 assert($OPCODE_IMOVE == $OPCODE_LMOVE - 1);
3205 assert($OPCODE_LMOVE == $OPCODE_FMOVE - 1);
3206 assert($OPCODE_FMOVE == $OPCODE_DMOVE - 1);
3207 assert($OPCODE_DMOVE == $OPCODE_OMOVE - 1);
3208 assert($OPCODE_GOTO == $OPCODE_GOTOIF - 1);
3209 assert($OPCODE_GOTOIF == $OPCODE_GOTOIFNOT - 1);
3210
3211 reflectionValidated = true;
3212 }
3213
3214 #undef CHK_REQ_OPERAND
3215
3216 #endif
3217
3218 assert(opcode >= 0 && opcode < INSTRUCTION_N);
3219 return &REFLECTIONS[opcode];
3220}
3221
3222// Prints an instruction's opcode and it's operand data.
3223//
3224// @param instruction - pointer to an instruction in a code array.
3225// @return the length of the instruction.
3226//
3227static Uint32 printInstruction(const Code* const instruction) {
3228 const Opcode opcode = (Opcode) *instruction;
3229
3230 if(opcode >= INSTRUCTION_N) {
3231 printf("INVALID ");
3232 return 1;
3233 }
3234
3235 const Instruction* const reflection = reflectInstruction(opcode);
3236 printf("%s ", reflection->name);
3237
3238 const Uint32 numOperands = reflection->length - 1;
3239 for(Uint32 i = 0; i < numOperands; i += 1) {
3240 const InstructionOperand operandType = reflection->operands[i];
3241 const Uint32 operandIndex = i + 1;
3242
3243 switch(operandType) {
3244 case $INSTRUCTION_OPERAND_CODE_OFFSET:
3245 printf("$CODE: %u", instruction[operandIndex]);
3246 break;
3247
3248 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT:
3249 printf("$ISRC: %u", instruction[operandIndex]);
3250 break;
3251
3252 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG:
3253 printf("$LSRC: %u", instruction[operandIndex]);
3254 break;
3255
3256 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT:
3257 printf("$FSRC: %u", instruction[operandIndex]);
3258 break;
3259
3260 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE:
3261 printf("$DSRC: %u", instruction[operandIndex]);
3262 break;
3263
3264 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT:
3265 printf("$OSRC: %u", instruction[operandIndex]);
3266 break;
3267
3268 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT:
3269 printf("$IDST: %u", instruction[operandIndex]);
3270 break;
3271
3272 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG:
3273 printf("$LDST: %u", instruction[operandIndex]);
3274 break;
3275
3276 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT:
3277 printf("$FDST: %u", instruction[operandIndex]);
3278 break;
3279
3280 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE:
3281 printf("$DDST: %u", instruction[operandIndex]);
3282 break;
3283
3284 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT:
3285 printf("$ODST: %u", instruction[operandIndex]);
3286 break;
3287
3288 case $INSTRUCTION_OPERAND_FIELD_OFFSET:
3289 printf("$FOFT: %u", instruction[operandIndex]);
3290 break;
3291
3292 case $INSTRUCTION_OPERAND_CLASS_INDEX:
3293 printf("$CIDX: %u", instruction[operandIndex]);
3294 break;
3295
3296 case $INSTRUCTION_OPERAND_METHOD_INDEX:
3297 printf("$MIDX: %u", instruction[operandIndex]);
3298 break;
3299
3300 case $INSTRUCTION_OPERAND_SURFACE_METHOD_INDEX:
3301 printf("$SIDX: %u", instruction[operandIndex]);
3302 break;
3303
3304 case $INSTRUCTION_OPERAND_TEXT_INDEX:
3305 printf("$TIDX: %u", instruction[operandIndex]);
3306 break;
3307
3308 case $INSTRUCTION_OPERAND_LONG_INDEX:
3309 printf("$LIDX: %u", instruction[operandIndex]);
3310 break;
3311
3312 case $INSTRUCTION_OPERAND_DOUBLE_INDEX:
3313 printf("$DIDX: %u", instruction[operandIndex]);
3314 break;
3315
3316 case $INSTRUCTION_OPERAND_TMP_INDEX:
3317 printf("$TMPI: %u", instruction[operandIndex]);
3318 break;
3319
3320 case $INSTRUCTION_OPERAND_CRUMB_INDEX:
3321 printf("$CRBI: %u", instruction[operandIndex]);
3322 break;
3323
3324 case $INSTRUCTION_OPERAND_INT_VALUE:
3325 printf("$IVAL: %u", (CookeeInt)((CodeValue) instruction[operandIndex]));
3326 break;
3327
3328 case $INSTRUCTION_OPERAND_FLOAT_BITS:
3329 printf("$FVAL: %f", (CookeeFloat)(intBitsToFloat(instruction[operandIndex])));
3330 break;
3331
3332 case $INSTRUCTION_OPERAND_SEQUENCE_DATA:
3333 printf("$SIDX: %u ", instructionSequenceDataIndex(instruction[operandIndex]));
3334 printf("$SLEN: %u", instructionSequenceDataLength(instruction[operandIndex]));
3335 break;
3336
3337 case $INSTRUCTION_OPERAND_LOCATION:
3338 printf("$LOCI: %u", instruction[operandIndex]);
3339 break;
3340 }
3341
3342 printf(" ");
3343 }
3344
3345 return reflection->length;
3346}
3347
3348// Prints the instruction inside a code array.
3349//
3350// @param code - the array containing instruction to be printed.
3351// @param codeSize - the number of items in the array.
3352//
3353static Void printCode(const Code* const code, const Uint32 codeSize) {
3354 const Uint32 maxOffsetDigits = uintDigits(MAX_METHOD_CODE_SIZE);
3355 printf("Code:\n\n");
3356
3357 for(Uint32 i = 0; i < codeSize;) {
3358 printf("\t#");
3359
3360 // Calculate needed offset padding.
3361 const Uint32 currentOffsetDigits = uintDigits(i);
3362 const Uint32 padding = maxOffsetDigits - currentOffsetDigits;
3363
3364 for(Uint32 ii = 0; ii < padding; ii += 1) {
3365 printf("0");
3366 }
3367
3368 printf("%d ", i);
3369
3370 i += printInstruction(code + i);
3371 printf("\n");
3372 }
3373
3374 printf("\n");
3375}
3376
3377#ifdef COOKEE_DEBUG
3378
3379///////////////////////////////////////////////////////////////////////
3380// DEBUG
3381///////////////////////////////////////////////////////////////////////
3382
3383 #ifdef COOKEE_DEBUG_PRINT_ALLOC
3384 #define PRINT_DEBUG_MEM(message, ...) printf(message, ##__VA_ARGS__)
3385 #else
3386 #define PRINT_DEBUG_MEM(message, ...)
3387 #endif
3388
3389 #ifdef COOKEE_DEBUG_PRINT_DATA
3390 #define PRINT_DEBUG_DATA(message, ...) printf(message, ##__VA_ARGS__)
3391 #define PRINT_DATA_CODE(code, codeLength) printCode(code, codeLength)
3392 #else
3393 #define PRINT_DEBUG_DATA(message, ...)
3394 #define PRINT_DATA_CODE(code, codeLength)
3395 #endif
3396
3397 #ifdef COOKEE_DEBUG_PRINT_OPTIMIZER
3398 #define PRINT_DEBUG_OPTS(message, ...) printf(message, ##__VA_ARGS__)
3399 #define PRINT_OPTS_CODE(code, codeLength) printCode(code, codeLength)
3400 #else
3401 #define PRINT_DEBUG_OPTS(message, ...)
3402 #define PRINT_OPTS_CODE(code, codeLength)
3403 #endif
3404
3405 #ifdef COOKEE_DEBUG_PRINT_EXEC
3406 #define PRINT_DEBUG_EXEC(message, ...) printf(message, ##__VA_ARGS__)
3407 #define PRINT_EXEC_INSTRUCTION(instruction, start) { \
3408 const Uint32 currentOffsetDigits = uintDigits((Uint32)(instruction - start)); \
3409 const Uint32 padding = uintDigits(MAX_METHOD_CODE_SIZE) - currentOffsetDigits; \
3410 printf("#"); \
3411 \
3412 for(Uint32 ii = 0; ii < padding; ii += 1) { \
3413 printf("0"); \
3414 } \
3415 \
3416 printf("%u ", (Uint32)(instruction - start)); \
3417 printInstruction(instruction); \
3418 }
3419 #else
3420 #define PRINT_DEBUG_EXEC(message, ...)
3421 #define PRINT_EXEC_INSTRUCTION(instruction, start)
3422 #endif
3423
3424 #define PRINT_DEBUG(message, ...) printf(message, ##__VA_ARGS__)
3425
3426#else
3427
3428 #define PRINT_EXEC_INSTRUCTION(instruction, start)
3429 #define PRINT_OPTS_CODE(code, codeLength)
3430 #define PRINT_DATA_CODE(code, codeLength)
3431
3432 #define PRINT_DEBUG_MEM(message, ...)
3433 #define PRINT_DEBUG_DATA(message, ...)
3434 #define PRINT_DEBUG_OPTS(message, ...)
3435 #define PRINT_DEBUG_EXEC(message, ...)
3436 #define PRINT_DEBUG(message, ...)
3437
3438#endif // ifdef COOKEE_DEBUG
3439
3440///////////////////////////////////////////////////////////////////////
3441// INSTANCE HEADER
3442///////////////////////////////////////////////////////////////////////
3443
3444// LAYOUT:
3445// ----------------------------
3446// HEADER: 31-bits(refsN) 1-bit(forward indicator) 31-bit bytes(size) 1-bit(heap indicator)
3447// PARTITION: 4 bytes(size) 4 bytes(refsN)
3448
3449static inline Uint8* objectToHeader(const CookeeObject object) {
3450 assert(object != COOKEE_NULL);
3451 return (Uint8*) object - COOKEE_INSTANCE_HEADER_SIZE;
3452}
3453
3454static inline CookeeObject headerToObject(Uint8* const header) {
3455 assert(header != NULL);
3456 return (CookeeObject)(header + COOKEE_INSTANCE_HEADER_SIZE);
3457}
3458
3459static inline Uint8* headerToPtr(Uint8* const header) {
3460 assert(header != NULL);
3461 return header + COOKEE_INSTANCE_HEADER_SIZE;
3462}
3463
3464static inline Void initHeader(Uint8* const header, const Uint32 refCount, const Uint32 size) {
3465 assert(header != NULL);
3466 *((Uint32*) header) = refCount << 1;
3467 *((Uint32*) header + 1) = size;
3468}
3469
3470static inline Uint32 getHeaderRefCount(Uint8* const header) {
3471 assert(header != NULL);
3472 return *((Uint32*) header) >> 1;
3473}
3474
3475static inline Uint32 getHeaderSize(Uint8* const header) {
3476 assert(header != NULL);
3477 return *((Uint32*) header + 1);
3478}
3479
3480// Check if header was marked as forwarding.
3481static inline Bool isHeaderMarkedForward(Uint8* const header) {
3482 assert(header != NULL);
3483 return *((Uint32*) header) == 1;
3484}
3485
3486// Mark header as forwaring. Note that this will override the reference count value.
3487static inline Void markHeaderForward(Uint8* const header) {
3488 assert(header != NULL);
3489 *((Uint32*) header) = 1;
3490}
3491
3492// Check if header was marked as unmanaged.
3493static inline Bool isHeaderMarkedUnmanaged(Uint8* const header) {
3494 assert(header != NULL);
3495 return *((Uint32*) header + 1) == 1;
3496}
3497
3498// Mark header as unmanaged. Note that this will override the size value.
3499static inline Void markHeaderUnmanaged(Uint8* const header) {
3500 assert(header != NULL);
3501 *((Uint32*) header + 1) = 1;
3502}
3503
3504static inline Void setHeaderPartitionJump(Uint8* const partition, const Uint32 amount) {
3505 assert(partition != NULL);
3506 *((Uint32*) partition) = amount;
3507}
3508
3509static inline Uint32 getHeaderPartitionJump(Uint8* const partition) {
3510 assert(partition != NULL);
3511 return *((Uint32*) partition);
3512}
3513
3514static inline Void setHeaderPartitionRefCount(Uint8* const partition, const Uint32 refCount) {
3515 assert(partition != NULL);
3516 *((Uint32*) partition + 1) = refCount;
3517}
3518
3519static inline Uint32 getHeaderPartitionRefCount(Uint8* const partition) {
3520 assert(partition != NULL);
3521 return *((Uint32*) partition + 1);
3522}
3523
3524///////////////////////////////////////////////////////////////////////
3525// GARBAGE COLLECTOR
3526///////////////////////////////////////////////////////////////////////
3527
3528// Forward declaration since we need to refer to GC in extension structure.
3529typedef struct Gc Gc;
3530
3531typedef struct GcExtension GcExtension;
3532struct GcExtension {
3533
3534 GcExtension* next;
3535
3536 // The context on which this extension works.
3537 Void* context;
3538
3539 // Marker function pointer. Should mark any externally managed pointers.
3540 Void(*markFunction)(Gc* gc, Void* context);
3541
3542 // Move function pointer. Should move any externally managed pointers with the given amount.
3543 Void(*moveFunction)(Gc* gc, Void* context, IntX amount);
3544
3545};
3546
3547struct Gc {
3548
3549 // Pointer to the start of the heap.
3550 Uint8* heap;
3551
3552 // Pointer to the start of toSpace.
3553 Uint8* toSpaceStart;
3554
3555 // Pointer to the current position in toSpace.
3556 Uint8* toSpace;
3557
3558 // Pointer to the start of fromSpace.
3559 Uint8* fromSpaceStart;
3560
3561 // Pointer to the current position in fromSpace.
3562 Uint8* fromSpace;
3563
3564 // Pointer to the location in toSpace, which when passed will trigger the collection.
3565 Uint8* barrier;
3566
3567 // Pointer to current local reference slot. Local references will be marked to prevent them from being collected.
3568 CookeeObject** localRefs;
3569
3570 // Pointer to first local reference.
3571 CookeeObject** localRefsMin;
3572
3573 // Pointer to the end of local reference list.
3574 CookeeObject** localRefsMax;
3575
3576 // List of collection extensions.
3577 GcExtension* extensions;
3578
3579 // Performance tracking callback function.
3580 CookeeGcCycleFunction cycleFunction;
3581
3582 // Current heap size.
3583 Uint32 heapSize;
3584
3585 // Min heap size.
3586 Uint32 minHeapSize;
3587
3588 // Max heap size.
3589 Uint32 maxHeapSize;
3590
3591 // Expected heap size by the user. The GC will prefer to grow the heap until this heap size is reached.
3592 Uint32 expectedHeapSize;
3593
3594 // Current locks in gc which prevent garbage collector.
3595 Uint32 locks;
3596
3597 // The number of contexts using this GC instance.
3598 Uint32 contexts;
3599
3600};
3601
3602// Format the allocated size to make the size aligned.
3603// The resulting size will also get bigger to fit the object header.
3604// This function should be called before allocating memory from the GC.
3605//
3606static inline Uint32 formatAllocSize(const Uint32 size) {
3607 return alignSize(size, 8) + COOKEE_INSTANCE_HEADER_SIZE + COOKEE_INSTANCE_PARTITION_SIZE;
3608}
3609
3610// Returns the number of currently allocated bytes.
3611static inline Uint32 getAllocatedBytes(Gc* const gc) {
3612 assert(gc != NULL);
3613 return (Uint32)(gc->fromSpace - gc->fromSpaceStart);
3614}
3615
3616// Return the number of free bytes in the current heap.
3617static inline Uint32 getFreeBytes(Gc* const gc) {
3618 assert(gc != NULL);
3619 return gc->heapSize / 2 - getAllocatedBytes(gc);
3620}
3621
3622// Returns the number of free bytes that the GC can use calculated as if the current GC heap size was the maxHeapSize.
3623static inline Uint32 getTotalFreeBytes(Gc* const gc) {
3624 assert(gc != NULL);
3625 return gc->maxHeapSize / 2 - getAllocatedBytes(gc);
3626}
3627
3628// Returns the usable size portion of the current heap size(currently half of it is used for copying).
3629static inline Uint32 getUsableHeapSize(Gc* const gc) {
3630 assert(gc != NULL);
3631 return gc->heapSize / 2;
3632}
3633
3634// Returns the minimum usable size portion of the minimum heap size(currently half of it is used for copying).
3635static inline Uint32 getMinUsableHeapSize(Gc* const gc) {
3636 assert(gc != NULL);
3637 return gc->minHeapSize / 2;
3638}
3639
3640// Returns the maximum usable size portion of the maximum heap size(currently half of it is used for copying).
3641static inline Uint32 getMaxUsableHeapSize(Gc* const gc) {
3642 assert(gc != NULL);
3643 return gc->maxHeapSize / 2;
3644}
3645
3646// Internal function to swap 'to' and 'from' spaces also adjusting the collection barrier.
3647static Void swapSpaces(Gc* const gc) {
3648 assert(gc != NULL);
3649
3650 Uint8* const temp = gc->fromSpaceStart;
3651 gc->fromSpaceStart = gc->toSpaceStart;
3652 gc->toSpaceStart = temp;
3653
3654 gc->fromSpace = gc->toSpace;
3655 gc->toSpace = gc->toSpaceStart;
3656
3657 gc->barrier = gc->fromSpaceStart + gc->heapSize / 2;
3658}
3659
3660// Moves the specified object only if it's not 0 and returns the moved pointer.
3661// @return the moved object or 0 if the object was 0.
3662//
3663static inline CookeeObject moveObject(const CookeeObject object, const IntX amount) {
3664 if(object == COOKEE_NULL) {
3665 return COOKEE_NULL;
3666 }
3667 else if(isHeaderMarkedUnmanaged(objectToHeader(object))) {
3668 return object;
3669 }
3670 return (CookeeObject)((Uint8*) object + amount);
3671}
3672
3673// Moves all objects within gc's reach by the specified amount.
3674static Void moveObjects(Gc* const gc, const IntX amount) {
3675 assert(gc != NULL);
3676
3677 PRINT_DEBUG_MEM("Moving local refs...\n");
3678
3679 // Move local refs.
3680
3681 CookeeObject** localRefs = gc->localRefsMin;
3682 CookeeObject** const localRefsN = gc->localRefs;
3683
3684 while(localRefs != localRefsN) {
3685 **localRefs = moveObject(**localRefs, amount);
3686 localRefs += 1;
3687 }
3688
3689 PRINT_DEBUG_MEM("Moving extension refs...\n");
3690
3691 // Move extensions.
3692
3693 GcExtension* extIter = gc->extensions;
3694
3695 while(extIter != NULL) {
3696 extIter->moveFunction(gc, extIter->context, amount);
3697 extIter = extIter->next;
3698 }
3699
3700 PRINT_DEBUG_MEM("Moving members refs...\n");
3701
3702 // Move members.
3703
3704 Uint8* heapIter = gc->fromSpaceStart;
3705 Uint8* const heapN = gc->fromSpace;
3706
3707 while(heapIter < heapN) {
3708 Uint8* const header = heapIter;
3709
3710 CookeeObject* refs = (CookeeObject*) headerToPtr(header);
3711 CookeeObject* const refsN = refs + getHeaderRefCount(header);
3712
3713 assert((Uint8*) refs < heapIter + getHeaderSize(header));
3714 assert((Uint8*) refsN < heapIter + getHeaderSize(header));
3715
3716 while(refs != refsN) {
3717 *refs = moveObject(*refs, amount);
3718 refs += 1;
3719 }
3720
3721 Uint8* partition = (Uint8*) refsN;
3722 Uint32 partitionJump = getHeaderPartitionJump(partition);
3723
3724 while(partitionJump != 0) {
3725 CookeeObject* partitionRefs = (CookeeObject*)(partition + partitionJump);
3726 CookeeObject* const partitionRefsN = partitionRefs + getHeaderPartitionRefCount(partition);
3727
3728 assert((Uint8*) partitionRefs < heapIter + getHeaderSize(header));
3729 assert((Uint8*) partitionRefsN < heapIter + getHeaderSize(header));
3730
3731 while(partitionRefs != partitionRefsN) {
3732 *partitionRefs = moveObject(*partitionRefs, amount);
3733 partitionRefs += 1;
3734 }
3735
3736 partition = (Uint8*) partitionRefsN;
3737 partitionJump = getHeaderPartitionJump(partition);
3738 }
3739
3740 heapIter += getHeaderSize(header);
3741 }
3742
3743 PRINT_DEBUG_MEM("Heap moved!\n");
3744}
3745
3746// Marks the given object as reachable. The passed object can be 0.
3747// @return the marked object. The returned object might be different from the one you pass in so be sure to update it!
3748//
3749static CookeeObject markObject(Gc* const gc, const CookeeObject object) {
3750 assert(gc != NULL);
3751
3752 if(object == COOKEE_NULL) {
3753 return COOKEE_NULL;
3754 }
3755
3756 Uint8* const header = objectToHeader(object);
3757
3758 if(isHeaderMarkedUnmanaged(header)) {
3759 return object;
3760 }
3761 else if(isHeaderMarkedForward(header)) {
3762 assert(header < gc->barrier);
3763 return *((CookeeObject*) object);
3764 }
3765 else {
3766 Uint8* const newHeader = gc->toSpace;
3767 const Uint32 size = getHeaderSize(header);
3768
3769 assert(header < gc->barrier);
3770 assert(header + size <= gc->barrier);
3771
3772 memcpy(newHeader, header, size);
3773 gc->toSpace += size;
3774
3775 const CookeeObject newObject = headerToObject(newHeader);
3776
3777 // Setup forwarding in the old ptr.
3778 markHeaderForward(header);
3779
3780 // Since our allocations are word aligned we make the old ptr point to the new ptr.
3781 *((CookeeObject*) object) = newObject;
3782
3783 return newObject;
3784 }
3785}
3786
3787// Performs garbage collection if the gc is not locked.
3788static Void collectGarbage(Gc* const gc) {
3789 assert(gc != NULL);
3790
3791 if(gc->locks > 0) {
3792 PRINT_DEBUG("Garbage collection prevented by locks!\n");
3793 return;
3794 }
3795
3796 PRINT_DEBUG("Garbage collection started on heap of size: %u\n", gc->heapSize);
3797
3798 const Uint32 startAllocatedBytes = getAllocatedBytes(gc);
3799
3800 if(gc->cycleFunction != NULL) {
3801 gc->cycleFunction(startAllocatedBytes);
3802 }
3803
3804 // Mark global references.
3805
3806 CookeeObject** localRefs = gc->localRefsMin;
3807 CookeeObject** const localRefsN = gc->localRefs;
3808
3809 while(localRefs != localRefsN) {
3810 **localRefs = markObject(gc, **localRefs);
3811 localRefs += 1;
3812 }
3813
3814 // Mark extensions.
3815
3816 GcExtension* extIter = gc->extensions;
3817
3818 while(extIter != NULL) {
3819 extIter->markFunction(gc, extIter->context);
3820 extIter = extIter->next;
3821 }
3822
3823 // Mark members.
3824
3825 Uint8* heapIter = gc->toSpaceStart;
3826 Uint8* toSpace = gc->toSpace;
3827
3828 while(heapIter < toSpace) {
3829 Uint8* const header = heapIter;
3830
3831 CookeeObject* refs = (CookeeObject*) headerToPtr(header);
3832 CookeeObject* const refsN = refs + getHeaderRefCount(header);
3833
3834 while(refs != refsN) {
3835 const CookeeObject object = *refs;
3836
3837 if(object == COOKEE_NULL) {
3838 refs += 1;
3839 continue;
3840 }
3841
3842 Uint8* const objectHeader = objectToHeader(object);
3843
3844 if(isHeaderMarkedForward(objectHeader)) {
3845 assert(objectHeader < gc->barrier);
3846 *refs++ = *((CookeeObject*) object);
3847 }
3848 else if(!isHeaderMarkedUnmanaged(objectHeader)) {
3849 Uint8* const newObjectHeader = toSpace;
3850 const Uint32 size = getHeaderSize(objectHeader);
3851
3852 assert(objectHeader < gc->barrier);
3853 assert(objectHeader + size <= gc->barrier);
3854
3855 memcpy(newObjectHeader, objectHeader, size);
3856
3857 toSpace += size;
3858
3859 const CookeeObject newObject = headerToObject(newObjectHeader);
3860
3861 // Setup forwarding in the old ptr.
3862 markHeaderForward(objectHeader);
3863
3864 // Since our allocations are word aligned we make the old ptr point to the new ptr.
3865 *((CookeeObject*) object) = newObject;
3866
3867 *refs++ = newObject;
3868 }
3869 }
3870
3871 Uint8* partition = (Uint8*) refsN;
3872 Uint32 partitionJump = getHeaderPartitionJump(partition);
3873
3874 while(partitionJump != 0) {
3875 assert(false);
3876
3877 CookeeObject* partitionRefs = (CookeeObject*)(partition + partitionJump);
3878 CookeeObject* const partitionRefsN = partitionRefs + getHeaderPartitionRefCount(partition);
3879
3880 assert((Uint8*) partitionRefs < heapIter + getHeaderSize(header));
3881 assert((Uint8*) partitionRefsN < heapIter + getHeaderSize(header));
3882
3883 while(partitionRefs != partitionRefsN) {
3884 const CookeeObject object = *partitionRefs;
3885
3886 if(object == COOKEE_NULL) {
3887 partitionRefs += 1;
3888 continue;
3889 }
3890
3891 Uint8* const objectHeader = objectToHeader(object);
3892
3893 if(isHeaderMarkedForward(objectHeader)) {
3894 *partitionRefs++ = *((CookeeObject*) object);
3895 }
3896 else if(!isHeaderMarkedUnmanaged(objectHeader)) {
3897 Uint8* const newObjectHeader = toSpace;
3898 const Uint32 size = getHeaderSize(objectHeader);
3899
3900 assert(objectHeader < gc->barrier);
3901 assert(objectHeader + size <= gc->barrier);
3902
3903 memcpy(newObjectHeader, objectHeader, size);
3904
3905 toSpace += size;
3906
3907 const CookeeObject newObject = headerToObject(newObjectHeader);
3908
3909 // Setup forwarding in the old ptr.
3910 markHeaderForward(objectHeader);
3911
3912 // Since our allocations are word aligned we make the old ptr point to the new ptr.
3913 *((CookeeObject*) object) = newObject;
3914
3915 *partitionRefs++ = newObject;
3916 }
3917 }
3918
3919 partition = (Uint8*) partitionRefsN;
3920 partitionJump = getHeaderPartitionJump(partition);
3921 }
3922
3923 heapIter += getHeaderSize(header);
3924 }
3925
3926 gc->toSpace = toSpace;
3927
3928 swapSpaces(gc);
3929
3930 const Uint32 allocatedBytes = getAllocatedBytes(gc);
3931
3932 if(gc->cycleFunction != NULL) {
3933 gc->cycleFunction(allocatedBytes);
3934 }
3935
3936 PRINT_DEBUG("Garbage collection ended, freed %u bytes in use %u\n", startAllocatedBytes - allocatedBytes, allocatedBytes);
3937}
3938
3939// Frees all of the memory allocated by the GC instance.
3940static Void purgeGc(Gc* const gc) {
3941 assert(gc != NULL);
3942
3943 if(gc->heap != NULL) {
3944 free(gc->heap);
3945 }
3946 if(gc->localRefsMin != NULL) {
3947 free(gc->localRefsMin);
3948 }
3949}
3950
3951// Initializes the GC instance.
3952// @return false if allocation error happened, true otherwise.
3953//
3954static Bool initializeGc(Gc* const gc,
3955 const Uint32 minHeapSize,
3956 const Uint32 maxHeapSize,
3957 const Uint32 expectedHeapSize,
3958 const Uint32 localRefCapacity) {
3959
3960 assert(gc != NULL);
3961
3962 if(maxHeapSize < minHeapSize) {
3963 printf("maxHeapSize %u cannot be less than minHeapSize %u.\n", maxHeapSize, minHeapSize);
3964 abort();
3965 }
3966
3967 memset(gc, 0, sizeof(Gc));
3968
3969 const Uint32 startHeapSize = alignSize(minHeapSize, sizeof(Double) * 2); // * 2 because there are 2 heaps.
3970 gc->heap = calloc(startHeapSize, sizeof(Uint8));
3971
3972 if(gc->heap == NULL) {
3973 printf("Failed allocate heap of %u bytes.\n", startHeapSize);
3974 purgeGc(gc);
3975 return false;
3976 }
3977
3978 gc->heapSize = startHeapSize;
3979 gc->minHeapSize = alignSize(minHeapSize, sizeof(Double) * 2);
3980 gc->maxHeapSize = alignSize(maxHeapSize, sizeof(Double) * 2);
3981 gc->expectedHeapSize = expectedHeapSize;
3982
3983 gc->fromSpaceStart = gc->heap;
3984 gc->fromSpace = gc->fromSpaceStart;
3985 gc->toSpaceStart = gc->heap + gc->heapSize / 2;
3986 gc->toSpace = gc->toSpaceStart;
3987 gc->barrier = gc->toSpace;
3988
3989 if((gc->localRefs = malloc(localRefCapacity * sizeof(CookeeObject))) == NULL) {
3990 printf("Failed to allocate local refs array.\n");
3991 purgeGc(gc);
3992 return false;
3993 }
3994
3995 gc->localRefsMin = gc->localRefs;
3996 gc->localRefsMax = gc->localRefsMin + localRefCapacity;
3997
3998 return gc;
3999}
4000
4001// Removes an extension from the GC.
4002static Void removeGcExtension(Gc* const gc, GcExtension* const extension) {
4003 assert(gc != NULL);
4004 assert(extension != NULL);
4005
4006 GcExtension* iter = gc->extensions;
4007 GcExtension* prev = NULL;
4008
4009 while(iter != NULL) {
4010 if(iter == extension) {
4011 if(prev != NULL) {
4012 prev->next = iter->next;
4013 }
4014 else {
4015 gc->extensions = iter->next;
4016 }
4017
4018 iter->next = NULL;
4019 return;
4020 }
4021
4022 prev = iter;
4023 iter = iter->next;
4024 }
4025}
4026
4027// Adds an extension to the gc.
4028// The extension must be removed from GC before it can be added if it was already added to the GC.
4029//
4030static inline Void addGcExtension(Gc* const gc, GcExtension* const extension) {
4031 assert(gc != NULL);
4032 assert(extension != NULL);
4033
4034 extension->next = gc->extensions;
4035 gc->extensions = extension;
4036}
4037
4038// Increments the lock of the garbage collector preventing it from triggering garbage collection and heap reallocation.
4039static inline Void lockGc(Gc* const gc) {
4040 assert(gc != NULL);
4041 gc->locks += 1;
4042}
4043
4044// Removes one lock from the garbage collector.
4045static inline Void unlockGc(Gc* const gc) {
4046 assert(gc != NULL);
4047 assert(gc->locks > 0);
4048
4049 gc->locks -= 1;
4050}
4051
4052// Returns true if gc is currently locked from performing garbage collection and heap reallocation, false otherwise.
4053static inline Bool isGcLocked(Gc* const gc) {
4054 assert(gc != NULL);
4055 return gc->locks > 0;
4056}
4057
4058// Adds a new global reference and returns a pointer to it.
4059// IMPORTANT: when using the reference, don't dereference it unless you are
4060// sure that garbage collection or heap growth will not happen.
4061//
4062static inline Void pushLocalRef(Gc* const gc, CookeeObject* const slot) {
4063 assert(gc->localRefs != gc->localRefsMax);
4064 *gc->localRefs++ = slot;
4065}
4066
4067// Removes the most recently added reference.
4068static inline Void popLocalRef(Gc* const gc) {
4069 assert(gc->localRefs != gc->localRefsMin);
4070 gc->localRefs -= 1;
4071}
4072
4073// Removes the specified amount of local references from the back of the list.
4074static inline Void popLocalRefs(Gc* const gc, const Uint32 amount) {
4075 assert(gc->localRefs - amount >= gc->localRefsMin);
4076 gc->localRefs -= amount;
4077}
4078
4079// Internal function performing the heap resizing for trimGc and ensureGcCapacity functions.
4080// @return false if the resize was prevented by locks or if allocation error happened, true otherwise.
4081//
4082static inline Bool resizeHeap(Gc* const gc, const Uint32 newSize) {
4083 assert(gc != NULL);
4084
4085 if(gc->locks > 0) {
4086 PRINT_DEBUG("Heap resize prevented by locks\n");
4087 return false;
4088 }
4089
4090 const Uint32 allocatedBytes = getAllocatedBytes(gc);
4091
4092 // In case the fromSpace is not at the start of the heap, swap the spaces.
4093 // This is needed to be able to correctly reallocate the whole heap.
4094 if(gc->fromSpaceStart != gc->heap) {
4095 PRINT_DEBUG_MEM("Swapping from space since it's not at the start of the heap...\n");
4096
4097 memcpy(gc->toSpaceStart, gc->fromSpaceStart, allocatedBytes);
4098 gc->toSpace += allocatedBytes;
4099
4100 swapSpaces(gc);
4101 moveObjects(gc, gc->fromSpaceStart - gc->toSpaceStart);
4102 }
4103
4104 Uint8* const newHeap = realloc(gc->heap, newSize);
4105
4106 if(newHeap == NULL) {
4107 PRINT_DEBUG("Failed to resize heap to %u bytes.\n", newSize);
4108 return false;
4109 }
4110
4111 PRINT_DEBUG("Heap resized to %u bytes\n", newSize);
4112
4113 const IntX heapDiff = newHeap - gc->heap;
4114
4115 gc->heap = newHeap;
4116 gc->heapSize = newSize;
4117
4118 // Update the spaces.
4119
4120 gc->fromSpaceStart = gc->heap;
4121 gc->fromSpace = gc->fromSpaceStart + allocatedBytes;
4122 gc->barrier = gc->fromSpaceStart + gc->heapSize / 2;
4123 gc->toSpaceStart = gc->barrier;
4124 gc->toSpace = gc->toSpaceStart;
4125
4126 // And finally, update the pointers inside the whole heap.
4127
4128 if(heapDiff != 0) {
4129 moveObjects(gc, heapDiff);
4130 }
4131
4132 return true;
4133}
4134
4135// Shrinks the heap if there's free space available.
4136// @return false if heap couldn't shrink, true otherwise.
4137//
4138static inline Bool trimGc(Gc* const gc) {
4139 assert(gc != NULL);
4140
4141 const Uint32 maxHeapSize = gc->maxHeapSize;
4142 const Uint32 allocatedBytes = getAllocatedBytes(gc);
4143
4144 Uint32 newHeapSize = gc->minHeapSize;
4145
4146 // Figure out how much to grow the heap.
4147 while(allocatedBytes > newHeapSize / 2) {
4148 newHeapSize *= 2;
4149
4150 // Limit the new heap size if needed.
4151 if(newHeapSize > maxHeapSize) {
4152 newHeapSize = maxHeapSize;
4153 }
4154 }
4155
4156 // The new heap size will always be <= current heap size at this point.
4157
4158 if(newHeapSize != gc->heapSize) {
4159 return resizeHeap(gc, newHeapSize);
4160 }
4161
4162 return true;
4163}
4164
4165// Ensures that the given size can fit in the heap by growing the heap if needed.
4166// @return false if heap can't fit the given size, true otherwise.
4167//
4168static inline Bool ensureGcCapacity(Gc* const gc, const Uint32 size) {
4169 assert(gc != NULL);
4170
4171 const Uint32 maxHeapSize = gc->maxHeapSize;
4172 const Uint32 requiredCapacity = getAllocatedBytes(gc) + size;
4173
4174 Uint32 newHeapSize = gc->heapSize;
4175
4176 // Figure out how much to grow the heap(and if we can fit the size at all).
4177 while(requiredCapacity > newHeapSize / 2) {
4178
4179 // If the heap is already at max size or if we reached max size and it was
4180 // not enough then there is no way we can fit the size.
4181 if(newHeapSize == maxHeapSize) {
4182 return false;
4183 }
4184
4185 newHeapSize *= 2;
4186
4187 // Limit the new heap size if needed.
4188 if(newHeapSize > maxHeapSize) {
4189 newHeapSize = maxHeapSize;
4190 }
4191 }
4192
4193 if(newHeapSize != gc->heapSize) {
4194 return resizeHeap(gc, newHeapSize);
4195 }
4196
4197 return true;
4198}
4199
4200// Allocates an instance of specified size and reference count.
4201//
4202// IMPORTANT: The allocator does not validate the parameters so be sure that the size does not exceed
4203// GC_MAX_SIZE and that refsN do not exceed GC_MAX_REFS_N.
4204// IMPORTANT: Use formatAllocSize to prepare the size parameter for proper heap alignment.
4205//
4206// @return 0 if failed to allocate, pointer address otherwise.
4207//
4208static CookeeObject allocNew(Gc* const gc,
4209 const Uint32 totalSize,
4210 const Uint32 refCount,
4211 const Uint32 partitionCount,
4212 const Uint32* const partitionRefs,
4213 const Uint32* const partitionJumps) {
4214
4215 assert(gc != NULL);
4216 assert(totalSize <= (UINT_MAX >> 1));
4217 assert(refCount <= (UINT_MAX >> 1));
4218
4219 if(gc->fromSpace + totalSize > gc->barrier) {
4220 PRINT_DEBUG_MEM("Not enough space to fit %u in heap of size %u GC\n",
4221 totalSize, (Uint32)(gc->barrier - gc->fromSpaceStart));
4222
4223 if(gc->heapSize < gc->expectedHeapSize) {
4224 PRINT_DEBUG_MEM("Heap size is still smaller than expected so trying to grow...\n");
4225
4226 if(!ensureGcCapacity(gc, totalSize)) {
4227 collectGarbage(gc);
4228
4229 // Try again after gc.
4230 if(!ensureGcCapacity(gc, totalSize)) {
4231 return COOKEE_NULL;
4232 }
4233 }
4234 }
4235 else {
4236 collectGarbage(gc);
4237
4238 if(!ensureGcCapacity(gc, totalSize)) {
4239 return COOKEE_NULL;
4240 }
4241 }
4242 }
4243
4244 assert(gc->fromSpace + totalSize <= gc->barrier);
4245
4246 PRINT_DEBUG_MEM("Alloc: %u(ref %u part %u)\n", totalSize, refCount, partitionCount);
4247
4248 Uint8* const header = gc->fromSpace;
4249
4250 initHeader(header, refCount, totalSize);
4251 memset(header + COOKEE_INSTANCE_HEADER_SIZE, 0, totalSize - COOKEE_INSTANCE_HEADER_SIZE);
4252
4253 if(partitionCount > 0) {
4254 Uint8* partition = headerToPtr(header) + (refCount * sizeof(CookeeObject));
4255 Uint32 partitionJump = partitionJumps[0];
4256
4257 setHeaderPartitionJump(partition, partitionJump);
4258 setHeaderPartitionRefCount(partition, partitionRefs[0]);
4259
4260 PRINT_DEBUG_MEM("Part %u jmp, %u ref\n", partitionJump, partitionRefs[0]);
4261
4262 Uint32 i = 1;
4263
4264 while(i < partitionCount) {
4265 partition += partitionJump;
4266 partitionJump = partitionJumps[i];
4267
4268 setHeaderPartitionJump(partition, partitionJump);
4269 setHeaderPartitionRefCount(partition, partitionRefs[i]);
4270
4271 PRINT_DEBUG_MEM("Part %u jmp, %u ref\n", partitionJump, partitionRefs[i]);
4272 i += 1;
4273 }
4274 }
4275
4276 gc->fromSpace += totalSize;
4277
4278 return headerToObject(header);
4279}
4280
4281///////////////////////////////////////////////////////////////////////
4282// DATA STRUCTURES
4283///////////////////////////////////////////////////////////////////////
4284
4285// Contains the data structures of loaded Cookee executable.
4286// The data is safe to be shared across different Cookee execution contexts.
4287
4288// Cookee field data.
4289typedef struct Field Field;
4290struct Field {
4291
4292 // The name of the field.
4293 Char* name;
4294
4295 // The signature of the field using which the field could be selected unambiguously from global scope.
4296 Char* signature;
4297
4298 // Global index of this field.
4299 Uint32 index;
4300
4301 // The index of the class in which the field is defined.
4302 Uint32 parentClassIndex;
4303
4304 // The class index of the type.
4305 // If the type is not an object this is always 0.
4306 Uint32 typeClassIndex;
4307
4308 // The offset of this field's data within an object instance.
4309 Uint32 offset;
4310
4311 // The type of the field.
4312 CookeeType type;
4313
4314};
4315
4316// Frees all of the memory allocated by the field instance.
4317static Void purgeField(Field* const field) {
4318 assert(field != NULL);
4319
4320 if(field->name != NULL) {
4321 free(field->name);
4322 }
4323 if(field->signature != NULL) {
4324 free(field->signature);
4325 }
4326}
4327
4328// Structure representing a parameter variable in the method.
4329typedef struct Parameter Parameter;
4330struct Parameter {
4331
4332 // The name of the variable.
4333 Char* name;
4334
4335 // The class index of the type.
4336 // If the type is not an object this is always 0.
4337 Uint32 typeClassIndex;
4338
4339 // The offset of the variable in the stack.
4340 Uint32 offset;
4341
4342 // The type of the variable.
4343 CookeeType type;
4344
4345};
4346
4347static Void purgeParameter(Parameter* const parameter) {
4348 assert(parameter != NULL);
4349
4350 if(parameter->name != NULL) {
4351 free(parameter->name);
4352 }
4353}
4354
4355// Cookee method data.
4356typedef struct Method Method;
4357struct Method {
4358
4359 // The name of the method.
4360 Char* name;
4361
4362 // The signature of the method using which the method could be selected unambiguously from global scope.
4363 Char* signature;
4364
4365 // Array of method's execution code(bytecode).
4366 Code* code;
4367
4368 // Original method's instructions which gets used when the method is unbinded.
4369 Code* loadedCode;
4370
4371 // List of local variable offsets.
4372 Uint32* localOffsets;
4373
4374 // List of information about parameters inside the method.
4375 Parameter* parameters;
4376
4377 // List of parameter reference offsets for quick access.
4378 Uint32* parameterRefOffsets;
4379
4380 // List of parameter offsets for quick access.
4381 Uint32* parameterOffsets;
4382
4383 // Binded native method.
4384 CookeeMethodBinding binding;
4385
4386 // The attachment of binded implementation.
4387 Void* bindingAttachment;
4388
4389 // Global index of this method.
4390 Uint32 index;
4391
4392 // Index of the class in which this method is declared.
4393 Uint32 parentClassIndex;
4394
4395 // The surface index of this method in the surface method list of the class.
4396 Uint32 surfaceIndex;
4397
4398 // The index of the method this method overrides.
4399 Uint32 overridedMethodIndex;
4400
4401 // The number of instructions this method has.
4402 Uint32 codeSize;
4403
4404 // Original method's instruction count which gets used when the method is unbinded.
4405 Uint32 loadedCodeSize;
4406
4407 // Total stack size needed to execute this method.
4408 Uint32 stackSize;
4409
4410 // The offset within the stack where arguments are stored upon invokation within the method.
4411 Uint32 nextFrameOffset;
4412
4413 // The class index of the return type.
4414 // If the type is not an object or a self type this is always 0.
4415 Uint32 returnTypeClassIndex;
4416
4417 // The number of parameters this method has.
4418 Uint32 parameterCount;
4419
4420 // Number of reference locals.
4421 Uint32 refLocalsCount;
4422
4423 // Number of 64-bit locals.
4424 Uint32 x64LocalsCount;
4425
4426 // Number of 32-bit locals.
4427 Uint32 x32LocalsCount;
4428
4429 // Number of reference parameters.
4430 Uint32 refParametersCount;
4431
4432 // Number of 64-bit parameters.
4433 Uint32 x64ParametersCount;
4434
4435 // Number of 32-bit parameters.
4436 Uint32 x32ParametersCount;
4437
4438 // Stack size needed to execute the largest invokation within the method.
4439 Uint32 peakArgumentsSize;
4440
4441 // Stack size needed by parameters.
4442 Uint32 parameterStackSize;
4443
4444 // The type of the returned value.
4445 CookeeType returnType;
4446
4447};
4448
4449// Returns a method parameter with specified name or NULL if not found.
4450static Parameter* findMethodParameter(const Method* const method, const Char* const name) {
4451 assert(method != NULL);
4452 assert(name != NULL);
4453
4454 Parameter* parameters = method->parameters;
4455 Parameter* const parametersN = method->parameters + method->parameterCount;
4456
4457 while(parameters != parametersN) {
4458 if(strcmp(parameters->name, name) == 0) {
4459 return parameters;
4460 }
4461 parameters += 1;
4462 }
4463
4464 return NULL;
4465}
4466
4467// Binds the given function as the method's implementation.
4468static Void bindMethodImplementation(Method* const method, CookeeMethodBinding const binding, Void* const bindingAttachment) {
4469 static Code CODE_TABLE[COOKEE_TYPE_N + 1][1] = {
4470 { $OPCODE_INATIVE }, // Bool
4471 { $OPCODE_INATIVE }, // Char
4472 { $OPCODE_INATIVE }, // Int
4473 { $OPCODE_LNATIVE }, // Long
4474 { $OPCODE_FNATIVE }, // Float
4475 { $OPCODE_DNATIVE }, // Double
4476 { $OPCODE_ONATIVE }, // Object
4477 { $OPCODE_NATIVESEQ } // Sequential
4478 };
4479
4480 assert(method != NULL);
4481 assert(binding != NULL);
4482
4483 method->binding = binding;
4484 method->bindingAttachment = bindingAttachment;
4485
4486 // Make the code execute the binding upon method execution.
4487
4488 // Sequential methods cannot be mapped to the code table directly so we need to identify them.
4489 if(method->returnType == $COOKEE_TYPE_OBJECT && method->returnTypeClassIndex == 0 && method->parameterCount == 1) {
4490 method->code = &CODE_TABLE[method->returnType + 1][0];
4491 }
4492 else {
4493 method->code = &CODE_TABLE[method->returnType][0];
4494 }
4495
4496 method->codeSize = 1;
4497}
4498
4499// Unbinds the method restoring it to initial state.
4500static Void unbindMethodImplementation(Method* const method) {
4501 assert(method != NULL);
4502
4503 if(method->binding == NULL) {
4504 return;
4505 }
4506
4507 method->binding = NULL;
4508 method->bindingAttachment = NULL;
4509
4510 method->code = method->loadedCode;
4511 method->codeSize = method->loadedCodeSize;
4512}
4513
4514// Frees all of the memory allocated by the method instance.
4515static Void purgeMethod(Method* const method) {
4516 assert(method != NULL);
4517
4518 if(method->loadedCode != NULL) {
4519 free(method->loadedCode);
4520 }
4521 if(method->localOffsets != NULL) {
4522 free(method->localOffsets);
4523 }
4524 if(method->parameters != NULL) {
4525 for(Uint32 i = 0; i < method->parameterCount; i += 1) {
4526 purgeParameter(&method->parameters[i]);
4527 }
4528 free(method->parameters);
4529 }
4530 if(method->parameterRefOffsets != NULL) {
4531 free(method->parameterRefOffsets);
4532 }
4533 if(method->parameterOffsets != NULL) {
4534 free(method->parameterOffsets);
4535 }
4536 if(method->name != NULL) {
4537 free(method->name);
4538 }
4539 if(method->signature != NULL) {
4540 free(method->signature);
4541 }
4542}
4543
4544// Cookee class data.
4545typedef struct Class Class;
4546struct Class {
4547
4548 // The name of the class.
4549 Char* name;
4550
4551 // The signature of the class using which the class could be selected unambiguously from global scope.
4552 Char* signature;
4553
4554 // List of locally declared fields.
4555 Field** fields;
4556
4557 // List of locally declared methods.
4558 Method** methods;
4559
4560 // Combined list of local methods and methods from super classes. All overrided methods are replaced with override methods.
4561 Method** surfaceMethods;
4562
4563 // Contains list of cast compatibility indicates, each byte being the indicator and index being the class index.
4564 Uint8* castingTable;
4565
4566 // The default initializer method of this class.
4567 Method* initializer;
4568
4569 // List of partition reference counts.
4570 Uint32* partitionRefCounts;
4571
4572 // List of partition jump amounts.
4573 Uint32* partitionJumps;
4574
4575 // List of indexes of super classes.
4576 Uint32* hierarchyClassIndexes;
4577
4578 // A function which can compare the instances of this class by equality, not by identity.
4579 CookeeEqualsFunction equalityFunction;
4580 Void* equalityFunctionAttachment;
4581
4582 // Index of the class.
4583 Uint32 index;
4584
4585 // The index of the class this class extends.
4586 Uint32 superClassIndex;
4587
4588 // Number of local fields.
4589 Uint32 fieldCount;
4590
4591 // Number of local methods.
4592 Uint32 methodCount;
4593
4594 // Number of surface methods.
4595 Uint32 surfaceMethodCount;
4596
4597 // Size of an instance of this class(not including gc size).
4598 Uint32 fullInstanceSize;
4599
4600 // The number of references at the very start of the instance.
4601 Uint32 headReferenceCount;
4602
4603 // The number of temporary instances this class requires.
4604 Uint32 temporaryInstanceCount;
4605
4606 // The number of partitions each instance of this class has.
4607 Uint32 partitionCount;
4608
4609 // The number of classes in the class hierarchy.
4610 Uint32 hierarchySize;
4611
4612};
4613
4614// Returns a field with specified signature or NULL if not found.
4615static Field* findClassField(const Class* const class, const Char* const signature) {
4616 assert(class != NULL);
4617 assert(signature != NULL);
4618
4619 Field** fields = class->fields;
4620 Field** const fieldsN = fields + class->fieldCount;
4621
4622 while(fields != fieldsN) {
4623 Field* const field = *fields;
4624
4625 if(strcmp(field->signature, signature) == 0) {
4626 return field;
4627 }
4628
4629 fields += 1;
4630 }
4631
4632 return NULL;
4633}
4634
4635// Returns a field with specified name or NULL if not found.
4636static Field* findClassFieldByName(const Class* const class, const Char* const name) {
4637 assert(class != NULL);
4638 assert(name != NULL);
4639
4640 Field** fields = class->fields;
4641 Field** const fieldsN = fields + class->fieldCount;
4642
4643 while(fields != fieldsN) {
4644 Field* const field = *fields;
4645
4646 if(strcmp(field->name, name) == 0) {
4647 return field;
4648 }
4649
4650 fields += 1;
4651 }
4652
4653 return NULL;
4654}
4655
4656// Returns a method with specified signature or NULL if not found.
4657static Method* findClassMethod(const Class* const class, const Char* const signature) {
4658 assert(class != NULL);
4659 assert(signature != NULL);
4660
4661 Method** methods = class->methods;
4662 Method** const methodsN = methods + class->methodCount;
4663
4664 while(methods != methodsN) {
4665 Method* const method = *methods;
4666
4667 if(strcmp(method->signature, signature) == 0) {
4668 return method;
4669 }
4670
4671 methods += 1;
4672 }
4673
4674 return NULL;
4675}
4676
4677// Frees all of the memory allocated by the class instance.
4678static Void purgeClass(Class* const class) {
4679 assert(class != NULL);
4680
4681 if(class->name != NULL) {
4682 free(class->name);
4683 }
4684 if(class->signature != NULL) {
4685 free(class->signature);
4686 }
4687 if(class->hierarchyClassIndexes != NULL) {
4688 free(class->hierarchyClassIndexes);
4689 }
4690 if(class->fields != NULL) {
4691 free(class->fields);
4692 }
4693 if(class->methods != NULL) {
4694 free(class->methods);
4695 }
4696 if(class->surfaceMethods != NULL) {
4697 free(class->surfaceMethods);
4698 }
4699 if(class->partitionRefCounts != NULL) {
4700 free(class->partitionRefCounts);
4701 }
4702 if(class->partitionJumps != NULL) {
4703 free(class->partitionJumps);
4704 }
4705 if(class->castingTable != NULL) {
4706 free(class->castingTable);
4707 }
4708}
4709
4710// Structure containing text literal data.
4711typedef struct Text Text;
4712struct Text {
4713
4714 // List of characters of this text literal.
4715 CookeeChar* chars;
4716
4717 // The number of characters this text literal has.
4718 Uint32 length;
4719
4720};
4721
4722// Frees all of the memory allocated by the text instance.
4723static Void purgeText(Text* const text) {
4724 assert(text != NULL);
4725
4726 if(text->chars != NULL) {
4727 free(text->chars);
4728 }
4729}
4730
4731// Structure containing all of the loaded class/field/method/literal and other data.
4732typedef struct Data Data;
4733struct Data {
4734
4735 // List of loaded classes.
4736 Class* classes;
4737
4738 // List of loaded fields.
4739 Field* fields;
4740
4741 // List of loaded methods.
4742 Method* methods;
4743
4744 // List of loaded long literal values.
4745 CookeeLong* longLiterals;
4746
4747 // List of loaded double literal values.
4748 CookeeDouble* doubleLiterals;
4749
4750 // List of loaded text literal chars.
4751 Text* textLiterals;
4752
4753 // A function which can create a text object.
4754 CookeeCreateTextFunction createTextFunction;
4755 Void* createTextFunctionAttachment;
4756
4757 // Number of classes loaded.
4758 Uint32 classCount;
4759
4760 // Number of fields loaded.
4761 Uint32 fieldCount;
4762
4763 // Number of methods loaded.
4764 Uint32 methodCount;
4765
4766 // Number of long literals loaded.
4767 Uint32 longLiteralCount;
4768
4769 // Number of double literals loaded.
4770 Uint32 doubleLiteralCount;
4771
4772 // Number of text literals loaded.
4773 Uint32 textLiteralCount;
4774
4775 // Number of contexts using the data.
4776 Uint32 contexts;
4777
4778};
4779
4780// Returns a field with specified signature or NULL if not found.
4781static Field* findField(const Data* const data, const Char* const signature) {
4782 assert(data != NULL);
4783 assert(signature != NULL);
4784
4785 Field* fields = data->fields + 1; // +1 because the first one is NULL.
4786 Field* const fieldsN = data->fields + data->fieldCount;
4787
4788 while(fields != fieldsN) {
4789 if(strcmp(fields->signature, signature) == 0) {
4790 return fields;
4791 }
4792
4793 fields += 1;
4794 }
4795
4796 return NULL;
4797}
4798
4799// Returns a method with specified signature or NULL if not found.
4800static Method* findMethod(const Data* const data, const Char* const signature) {
4801 assert(data != NULL);
4802 assert(signature != NULL);
4803
4804 Method* methods = data->methods + 1; // +1 because the first one is NULL.
4805 Method* const methodsN = data->methods + data->methodCount;
4806
4807 while(methods != methodsN) {
4808 if(strcmp(methods->signature, signature) == 0) {
4809 return methods;
4810 }
4811
4812 methods += 1;
4813 }
4814
4815 return NULL;
4816}
4817
4818// Returns a class with specified signature or NULL if not found.
4819static Class* findClass(const Data* const data, const Char* const signature) {
4820 assert(data != NULL);
4821 assert(signature != NULL);
4822
4823 Class* classes = data->classes + 1; // +1 because the first one is NULL.
4824 Class* const classesN = data->classes + data->classCount;
4825
4826 while(classes != classesN) {
4827 if(strcmp(classes->signature, signature) == 0) {
4828 return classes;
4829 }
4830
4831 classes += 1;
4832 }
4833
4834 return NULL;
4835}
4836
4837// Frees all of the memory allocated by the data instance.
4838static Void purgeData(Data* const data) {
4839 assert(data != NULL);
4840
4841 if(data->classes != NULL) {
4842 const Uint32 n = data->classCount;
4843
4844 for(Uint32 i = 1; i < n; i += 1) {
4845 purgeClass(&data->classes[i]);
4846 }
4847
4848 free(data->classes);
4849 }
4850
4851 if(data->fields != NULL) {
4852 const Uint32 n = data->fieldCount;
4853
4854 for(Uint32 i = 1; i < n; i += 1) {
4855 purgeField(&data->fields[i]);
4856 }
4857
4858 free(data->fields);
4859 }
4860
4861 if(data->methods != NULL) {
4862 const Uint32 n = data->methodCount;
4863
4864 for(Uint32 i = 1; i < n; i += 1) {
4865 purgeMethod(&data->methods[i]);
4866 }
4867
4868 free(data->methods);
4869 }
4870
4871 if(data->longLiterals != NULL) {
4872 free(data->longLiterals);
4873 }
4874 if(data->doubleLiterals != NULL) {
4875 free(data->doubleLiterals);
4876 }
4877
4878 if(data->textLiterals != NULL) {
4879 const Uint32 n = data->textLiteralCount;
4880
4881 for(Uint32 i = 0; i < n; i += 1) {
4882 purgeText(&data->textLiterals[i]);
4883 }
4884
4885 free(data->textLiterals);
4886 }
4887}
4888
4889static Int64 loadInt64(const Char** const bytesPtr, const Char* const endPtr) {
4890 const Char* const bytes = *bytesPtr;
4891 assert(bytes + 8 <= endPtr);
4892
4893 const Int64 value = ((Int64)(bytes[7] & 0xFFL) << 56) |
4894 ((Int64)(bytes[6] & 0xFFL) << 48) |
4895 ((Int64)(bytes[5] & 0xFFL) << 40) |
4896 ((Int64)(bytes[4] & 0xFFL) << 32) |
4897 ((Int64)(bytes[3] & 0xFFL) << 24) |
4898 ((Int64)(bytes[2] & 0xFFL) << 16) |
4899 ((Int64)(bytes[1] & 0xFFL) << 8) |
4900 (Int64)(bytes[0] & 0xFFL);
4901
4902 *bytesPtr += 8;
4903
4904 return value;
4905}
4906
4907static Int32 loadInt32(const Char** const bytesPtr, const Char* const endPtr) {
4908 const Char* const bytes = *bytesPtr;
4909 assert(bytes + 4 <= endPtr);
4910
4911 const Int32 value = (Int32)((bytes[3] & 0xFF) << 24) |
4912 (Int32)((bytes[2] & 0xFF) << 16) |
4913 (Int32)((bytes[1] & 0xFF) << 8) |
4914 (Int32) (bytes[0] & 0xFF);
4915
4916 *bytesPtr += 4;
4917
4918 return value;
4919}
4920
4921static Int16 loadInt16(const Char** const bytesPtr, const Char* const endPtr) {
4922 const Char* const bytes = *bytesPtr;
4923 assert(bytes + 2 <= endPtr);
4924
4925 const Int16 value = (Int16)((bytes[1] & 0xFF) << 8) |
4926 (Int16) (bytes[0] & 0xFF);
4927
4928 *bytesPtr += 2;
4929
4930 return value;
4931}
4932
4933static Uint8 loadInt8(const Char** const bytesPtr, const Char* const endPtr) {
4934 const Char* const bytes = *bytesPtr;
4935 assert(bytes + 1 <= endPtr);
4936
4937 const Uint8 value = (Uint8)(bytes[0] & 0xFF);
4938 *bytesPtr += 1;
4939
4940 return value;
4941}
4942
4943static Double loadDouble(const Char** const bytesPtr, const Char* const endPtr) {
4944 const Int64 value = loadInt64(bytesPtr, endPtr);
4945
4946 union {
4947 Double doubleValue;
4948 Int64 intValue;
4949 } i2d;
4950
4951 i2d.intValue = value;
4952 return i2d.doubleValue;
4953}
4954
4955static Float loadFloat(const Char** const bytesPtr, const Char* const endPtr) {
4956 const Int32 value = loadInt32(bytesPtr, endPtr);
4957
4958 union {
4959 Float floatValue;
4960 Int32 intValue;
4961 } i2f;
4962
4963 i2f.intValue = value;
4964 return i2f.floatValue;
4965}
4966
4967static inline Void skipInt32(const Char** const bytesPtr, const Char* const endPtr) {
4968 assert(*bytesPtr + 4 <= endPtr);
4969 *bytesPtr += 4;
4970}
4971
4972static inline Void skipInt16(const Char** const bytesPtr, const Char* const endPtr) {
4973 assert(*bytesPtr + 2 <= endPtr);
4974 *bytesPtr += 2;
4975}
4976
4977static inline Void skipInt8(const Char** const bytesPtr, const Char* const endPtr) {
4978 assert(*bytesPtr + 1 <= endPtr);
4979 *bytesPtr += 1;
4980}
4981
4982static Void loadInt64Array(const Char** const bytesPtr,
4983 Int64* const array,
4984 const Uint32 arrayLength,
4985 const Char* const endPtr) {
4986
4987 Int64* iter = array;
4988 Int64* const iterN = array + arrayLength;
4989
4990 while(iter != iterN) {
4991 *iter = loadInt64(bytesPtr, endPtr);
4992 iter += 1;
4993 }
4994}
4995
4996static Void loadInt32Array(const Char** const bytesPtr,
4997 Int32* const array,
4998 const Uint32 arrayLength,
4999 const Char* const endPtr) {
5000
5001 Int32* iter = array;
5002 Int32* const iterN = array + arrayLength;
5003
5004 while(iter != iterN) {
5005 *iter = loadInt32(bytesPtr, endPtr);
5006 iter += 1;
5007 }
5008}
5009
5010static Void loadInt16Array(const Char** const bytesPtr,
5011 Int16* const array,
5012 const Uint32 arrayLength,
5013 const Char* const endPtr) {
5014
5015 Int16* iter = array;
5016 Int16* const iterN = array + arrayLength;
5017
5018 while(iter != iterN) {
5019 *iter = loadInt16(bytesPtr, endPtr);
5020 iter += 1;
5021 }
5022}
5023
5024static Void loadInt8Array(const Char** const bytesPtr,
5025 Int8* const array,
5026 const Uint32 arrayLength,
5027 const Char* const endPtr) {
5028
5029 Int8* iter = array;
5030 Int8* const iterN = array + arrayLength;
5031
5032 while(iter != iterN) {
5033 *iter = loadInt8(bytesPtr, endPtr);
5034 iter += 1;
5035 }
5036}
5037
5038static Void loadDoubleArray(const Char** const bytesPtr,
5039 Double* const array,
5040 const Uint32 arrayLength,
5041 const Char* const endPtr) {
5042
5043 Double* iter = array;
5044 Double* const iterN = array + arrayLength;
5045
5046 while(iter != iterN) {
5047 *iter = loadDouble(bytesPtr, endPtr);
5048 iter += 1;
5049 }
5050}
5051
5052static Void loadFloatArray(const Char** const bytesPtr,
5053 Float* const array,
5054 const Uint32 arrayLength,
5055 const Char* const endPtr) {
5056
5057 Float* iter = array;
5058 Float* const iterN = array + arrayLength;
5059
5060 while(iter != iterN) {
5061 *iter = loadFloat(bytesPtr, endPtr);
5062 iter += 1;
5063 }
5064}
5065
5066static Void loadStr(const Char** const bytesPtr, Char* const str, const Uint32 strLength, const Char* const endPtr) {
5067 assert(*bytesPtr + strLength <= endPtr);
5068
5069 memcpy(str, *bytesPtr, strLength);
5070 *bytesPtr += strLength;
5071}
5072
5073// Load data from given data bytes.
5074// @return instance of data containing all of loaded information or NULL if allocation error happened.
5075//
5076static Bool loadData(Data* const data, const Char* bytes, const Char* const endPtr) {
5077 // #1 Uint -- version value
5078 const Uint32 versionValue = loadInt32(&bytes, endPtr);
5079 PRINT_DEBUG_DATA("Version value: %d\n", versionValue);
5080
5081 if(versionValue != 0xC001EE) {
5082 printf("Invalid executable version value %u\n", versionValue);
5083 return false;
5084 }
5085
5086 // #2 Uint -- class count
5087 const Uint32 classCount = loadInt32(&bytes, endPtr) + 1;
5088 PRINT_DEBUG_DATA("Class count: %d\n", classCount);
5089
5090 // #3 Uint -- field count
5091 const Uint32 fieldCount = loadInt32(&bytes, endPtr) + 1;
5092 PRINT_DEBUG_DATA("Field count: %d\n", fieldCount);
5093
5094 // #4 Uint -- method count
5095 const Uint32 methodCount = loadInt32(&bytes, endPtr) + 1;
5096 PRINT_DEBUG_DATA("Method count: %d\n", methodCount);
5097
5098 // #5 Uint -- long literal count
5099 const Uint32 longLiteralCount = loadInt32(&bytes, endPtr);
5100 PRINT_DEBUG_DATA("Long literal count: %d\n", longLiteralCount);
5101
5102 // #6 Uint -- double literal count
5103 const Uint32 doubleLiteralCount = loadInt32(&bytes, endPtr);
5104 PRINT_DEBUG_DATA("Double literal count: %d\n", doubleLiteralCount);
5105
5106 // #7 Uint -- text literal count
5107 const Uint32 textLiteralCount = loadInt32(&bytes, endPtr);
5108 PRINT_DEBUG_DATA("Text literal count: %d\n", textLiteralCount);
5109
5110 // Create data.
5111
5112 #ifdef COOKEE_DEBUG
5113 #define CHKERR(condition) \
5114 if(condition) { \
5115 purgeData(data); \
5116 abort(); \
5117 }
5118 #else
5119 #define CHKERR(condition) \
5120 if(condition) { \
5121 purgeData(data); \
5122 return false; \
5123 }
5124 #endif
5125
5126 Class* classes = NULL;
5127
5128 if(classCount > 0) {
5129 classes = calloc(classCount, sizeof(Class));
5130 CHKERR(classes == NULL);
5131
5132 data->classes = classes;
5133 data->classCount = classCount;
5134 }
5135
5136 Field* fields = NULL;
5137
5138 if(fieldCount > 0) {
5139 fields = calloc(fieldCount, sizeof(Field));
5140 CHKERR(fields == NULL);
5141
5142 data->fields = fields;
5143 data->fieldCount = fieldCount;
5144 }
5145
5146 Method* methods = NULL;
5147
5148 if(methodCount > 0) {
5149 methods = calloc(methodCount, sizeof(Method));
5150 CHKERR(methods == NULL);
5151
5152 data->methods = methods;
5153 data->methodCount = methodCount;
5154 }
5155
5156 CookeeLong* longLiterals = NULL;
5157
5158 if(longLiteralCount > 0) {
5159 longLiterals = calloc(longLiteralCount, sizeof(CookeeLong));
5160 CHKERR(longLiterals == NULL);
5161
5162 data->longLiterals = longLiterals;
5163 data->longLiteralCount = longLiteralCount;
5164 }
5165
5166 CookeeDouble* doubleLiterals = NULL;
5167
5168 if(doubleLiteralCount > 0) {
5169 doubleLiterals = calloc(doubleLiteralCount, sizeof(CookeeDouble));
5170 CHKERR(doubleLiterals == NULL);
5171
5172 data->doubleLiterals = doubleLiterals;
5173 data->doubleLiteralCount = doubleLiteralCount;
5174 }
5175
5176 Text* textLiterals = NULL;
5177
5178 if(textLiteralCount > 0) {
5179 textLiterals = calloc(textLiteralCount, sizeof(Text));
5180 CHKERR(textLiterals == NULL);
5181
5182 data->textLiterals = textLiterals;
5183 data->textLiteralCount = textLiteralCount;
5184 }
5185
5186 // #8 ... fields
5187
5188 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5189 PRINT_DEBUG_DATA("FIELDS\n");
5190 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5191
5192 for(Uint32 i = 1; i < fieldCount; i += 1) {
5193 Field* const field = &fields[i];
5194
5195 // #8.1 Uint -- field parent class index
5196 const Uint32 parentClassIndex = loadInt32(&bytes, endPtr);
5197 PRINT_DEBUG_DATA("Parent class index: %d\n", parentClassIndex);
5198
5199 // #8.2 Uint -- field name length
5200 const Uint32 nameLength = loadInt32(&bytes, endPtr);
5201 PRINT_DEBUG_DATA("Name length: %d\n", nameLength);
5202
5203 // #8.3 Uint -- field signature length
5204 const Uint32 signatureLength = loadInt32(&bytes, endPtr);
5205 PRINT_DEBUG_DATA("Signature length: %d\n", signatureLength);
5206
5207 // #8.4 Uint -- field type
5208 const Uint32 type = loadInt32(&bytes, endPtr);
5209 PRINT_DEBUG_DATA("Type: %s\n", CookeeTypeName(type));
5210
5211 // #8.5 Uint -- field instance type class index
5212 const Uint32 typeClassIndex = loadInt32(&bytes, endPtr);
5213 PRINT_DEBUG_DATA("Type class index: %d\n", typeClassIndex);
5214
5215 // #8.6 Uint -- field offset
5216 const Uint32 offset = loadInt32(&bytes, endPtr);
5217 PRINT_DEBUG_DATA("Offset: %d\n", offset);
5218
5219 // #8.7 ... field name characters(padded, null terminated)
5220 field->name = malloc(nameLength);
5221 CHKERR(field->name == NULL);
5222 loadStr(&bytes, field->name, nameLength, endPtr);
5223 PRINT_DEBUG_DATA("Name: %s\n", field->name);
5224
5225 // #8.8 ... field signature characters(padded, null terminated)
5226 field->signature = malloc(signatureLength);
5227 CHKERR(field->signature == NULL);
5228 loadStr(&bytes, field->signature, signatureLength, endPtr);
5229 PRINT_DEBUG_DATA("Signature: %s\n", field->signature);
5230
5231 field->index = i;
5232 field->parentClassIndex = parentClassIndex;
5233 field->type = (CookeeType) type;
5234 field->typeClassIndex = typeClassIndex;
5235 field->offset = offset;
5236
5237 PRINT_DEBUG_DATA("-----------------------------------\n");
5238 }
5239
5240 // #9 ... methods
5241 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5242 PRINT_DEBUG_DATA("METHODS\n");
5243 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5244
5245 for(Uint32 i = 1; i < methodCount; i += 1) {
5246 Method* const method = &methods[i];
5247
5248 // #9.1 Uint -- method parent class index
5249 const Uint32 parentClassIndex = loadInt32(&bytes, endPtr);
5250 PRINT_DEBUG_DATA("Parent class index: %d\n", parentClassIndex);
5251
5252 // #9.2 Uint -- method name length
5253 const Uint32 nameLength = loadInt32(&bytes, endPtr);
5254 PRINT_DEBUG_DATA("Name length: %d\n", nameLength);
5255
5256 // #9.3 Uint -- method signature length
5257 const Uint32 signatureLength = loadInt32(&bytes, endPtr);
5258 PRINT_DEBUG_DATA("Signature length: %d\n", signatureLength);
5259
5260 // #9.4 Uint -- method surface index
5261 const Uint32 surfaceIndex = loadInt32(&bytes, endPtr);
5262 PRINT_DEBUG_DATA("Surface index: %d\n", surfaceIndex);
5263
5264 // #9.5 Uint -- method overrided method index
5265 const Uint32 overridedMethodIndex = loadInt32(&bytes, endPtr);
5266 PRINT_DEBUG_DATA("Overrided method index: %d\n", overridedMethodIndex);
5267
5268 // #9.6 Uint -- method code size
5269 const Uint32 codeSize = loadInt32(&bytes, endPtr);
5270 PRINT_DEBUG_DATA("Code count: %d\n", codeSize);
5271
5272 // #9.7 Uint -- method local reference count
5273 const Uint32 localReferenceCount = loadInt32(&bytes, endPtr);
5274 PRINT_DEBUG_DATA("Local reference count: %d\n", localReferenceCount);
5275
5276 // #9.8 Uint -- method x64 local count
5277 const Uint32 x64LocalCount = loadInt32(&bytes, endPtr);
5278 PRINT_DEBUG_DATA("X64 local count: %d\n", x64LocalCount);
5279
5280 // #9.9 Uint -- method x32 local count
5281 const Uint32 x32LocalCount = loadInt32(&bytes, endPtr);
5282 PRINT_DEBUG_DATA("X32 local count: %d\n", x32LocalCount);
5283
5284 // #9.10 Uint -- method parameter count
5285 const Uint32 parameterCount = loadInt32(&bytes, endPtr);
5286 PRINT_DEBUG_DATA("Parameter count: %d\n", parameterCount);
5287
5288 // #9.11 Uint -- method parameter reference count
5289 const Uint32 parameterReferenceCount = loadInt32(&bytes, endPtr);
5290 PRINT_DEBUG_DATA("Parameter reference count: %d\n", parameterReferenceCount);
5291
5292 // #9.12 Uint -- method stack size
5293 const Uint32 stackSize = loadInt32(&bytes, endPtr);
5294 PRINT_DEBUG_DATA("Stack size: %d\n", stackSize);
5295
5296 // #9.13 Uint -- method peak arguments size
5297 const Uint32 peakArgumentsSize = loadInt32(&bytes, endPtr);
5298 PRINT_DEBUG_DATA("Peak arguments size: %d\n", peakArgumentsSize);
5299
5300 // #9.14 Uint -- method parameter stack size
5301 const Uint32 parameterStackSize = loadInt32(&bytes, endPtr);
5302 PRINT_DEBUG_DATA("Parameter stack size: %d\n", parameterStackSize);
5303
5304 // #9.15 Uint -- method return type
5305 const Uint32 returnType = loadInt32(&bytes, endPtr);
5306 PRINT_DEBUG_DATA("Return type: %s\n", CookeeTypeName(returnType));
5307
5308 // #9.16 Uint -- method return type class index
5309 const Uint32 returnTypeClassIndex = loadInt32(&bytes, endPtr);
5310 PRINT_DEBUG_DATA("Return type class index: %d\n", returnTypeClassIndex);
5311
5312 // #9.17 Uint -- method next frame offset
5313 const Uint32 nextFrameOffset = loadInt32(&bytes, endPtr);
5314 PRINT_DEBUG_DATA("Next frame offset offset: %d\n", nextFrameOffset);
5315
5316 // #9.18 Uint -- padding
5317 skipInt32(&bytes, endPtr);
5318
5319 // #9.19 ... method name characters(padded, null terminated)
5320 method->name = malloc(nameLength);
5321 CHKERR(method->name == NULL);
5322 loadStr(&bytes, method->name, nameLength, endPtr);
5323 PRINT_DEBUG_DATA("Name: %s\n", method->name);
5324
5325 // #9.20 ... method signature characters(padded, null terminated)
5326 method->signature = malloc(signatureLength);
5327 CHKERR(method->signature == NULL);
5328 loadStr(&bytes, method->signature, signatureLength, endPtr);
5329 PRINT_DEBUG_DATA("Signature: %s\n", method->signature);
5330
5331 // #9.21 ... method code (padded)
5332 if(codeSize > 0) {
5333 method->loadedCode = malloc(codeSize * sizeof(Code));
5334 CHKERR(method->loadedCode == NULL);
5335
5336 for(Uint32 ii = 0; ii < codeSize; ii += 1) {
5337 // #9.21.1 Uint -- method instruction
5338 method->loadedCode[ii] = (Code) loadInt32(&bytes, endPtr);
5339 }
5340
5341 PRINT_DATA_CODE(method->loadedCode, codeSize);
5342
5343 if(codeSize % 2 != 0) { // Padding.
5344 skipInt32(&bytes, endPtr);
5345 }
5346 }
5347
5348 // #9.22 ... method local offsets(padded)
5349 const Uint32 localCount = localReferenceCount + x64LocalCount + x32LocalCount;
5350 if(localCount > 0) {
5351 method->localOffsets = malloc(localCount * sizeof(Uint32));
5352 CHKERR(method->localOffsets == NULL);
5353
5354 for(Uint32 ii = 0; ii < localCount; ii += 1) {
5355 // #9.22 Uint -- method local offset
5356 const Uint32 offset = loadInt32(&bytes, endPtr);
5357 PRINT_DEBUG_DATA("Local $%d offset: %d\n", ii, offset);
5358
5359 method->localOffsets[ii] = offset;
5360 }
5361
5362 if(localCount % 2 != 0) { // Padding.
5363 skipInt32(&bytes, endPtr);
5364 }
5365 }
5366
5367 if(parameterCount > 0) {
5368 method->parameters = malloc(parameterCount * sizeof(Parameter));
5369 CHKERR(method->parameters == NULL);
5370
5371 method->parameterOffsets = malloc(parameterCount * sizeof(Uint32));
5372 CHKERR(method->parameterOffsets == NULL);
5373 }
5374
5375 // #9.23 ... method parameter names
5376 for(Uint32 ii = 0; ii < parameterCount; ii += 1) {
5377 Parameter* const parameter = &method->parameters[ii];
5378
5379 // #9.23.1 Uint -- parameter name length
5380 const Uint32 parameterNameLength = loadInt32(&bytes, endPtr);
5381 PRINT_DEBUG_DATA("Parameter $%d name length: %d\n", ii, parameterNameLength);
5382
5383 // #9.23.2 Uint -- padding
5384 skipInt32(&bytes, endPtr);
5385
5386 // #9.23.3 ... parameter name characters(padded, null terminated)
5387 parameter->name = malloc(parameterNameLength);
5388 CHKERR(parameter->name == NULL);
5389 loadStr(&bytes, parameter->name, parameterNameLength, endPtr);
5390 PRINT_DEBUG_DATA("Parameter $%d name: %s\n", ii, parameter->name);
5391 }
5392
5393 // #9.24 ... method parameter offsets (padded)
5394 for(Uint32 ii = 0; ii < parameterCount; ii += 1) {
5395 Parameter* const parameter = &method->parameters[ii];
5396
5397 // #9.24.1 Uint -- parameter offset
5398 const Uint32 offset = loadInt32(&bytes, endPtr);
5399 PRINT_DEBUG_DATA("Parameter $%d offset: %d\n", ii, offset);
5400
5401 parameter->offset = offset;
5402 method->parameterOffsets[ii] = offset;
5403 }
5404
5405 if(parameterCount % 2 != 0) { // Padding.
5406 skipInt32(&bytes, endPtr);
5407 }
5408
5409 // #9.25 ... method parameter ref offsets (padded)
5410 if(parameterReferenceCount > 0) {
5411 method->parameterRefOffsets = malloc(parameterReferenceCount * sizeof(Uint32));
5412 CHKERR(method->parameterRefOffsets == NULL);
5413
5414 for(Uint32 ii = 0; ii < parameterReferenceCount; ii += 1) {
5415 // #9.25.1 Uint -- parameter ref offset
5416 method->parameterRefOffsets[ii] = loadInt32(&bytes, endPtr);
5417 PRINT_DEBUG_DATA("Reference parameter $%d offset: %d\n", ii, method->parameterRefOffsets[ii]);
5418 }
5419
5420 if(parameterReferenceCount % 2 != 0) { // Padding.
5421 skipInt32(&bytes, endPtr);
5422 }
5423 }
5424
5425 Uint32 x64ParameterCount = 0;
5426 Uint32 x32ParameterCount = 0;
5427
5428 // #9.26 ... method parameter types (padded)
5429 for(Uint32 ii = 0; ii < parameterCount; ii += 1) {
5430 Parameter* const parameter = &method->parameters[ii];
5431
5432 // #9.26.1 Uint -- parameter type
5433 const Uint32 parameterType = loadInt32(&bytes, endPtr);
5434 PRINT_DEBUG_DATA("Parameter $%d type: %s\n", ii, CookeeTypeName(parameterType));
5435
5436 parameter->type = (CookeeType) parameterType;
5437
5438 switch(parameter->type) {
5439 case $COOKEE_TYPE_BOOL:
5440 case $COOKEE_TYPE_CHAR:
5441 case $COOKEE_TYPE_INT:
5442 x32ParameterCount += 1;
5443 break;
5444
5445 case $COOKEE_TYPE_LONG:
5446 x64ParameterCount += 1;
5447 break;
5448
5449 case $COOKEE_TYPE_FLOAT:
5450 x32ParameterCount += 1;
5451 break;
5452
5453 case $COOKEE_TYPE_DOUBLE:
5454 x64ParameterCount += 1;
5455 break;
5456
5457 case $COOKEE_TYPE_OBJECT:
5458 break;
5459
5460 default: break;
5461 }
5462 }
5463
5464 if(parameterCount % 2 != 0) { // Padding.
5465 skipInt32(&bytes, endPtr);
5466 }
5467
5468 // #9.27 ... method parameter instance type class index (padded)
5469 for(Uint32 ii = 0; ii < parameterCount; ii += 1) {
5470 Parameter* const parameter = &method->parameters[ii];
5471
5472 // #9.27.1 Uint -- parameter type
5473 const Uint32 parameterTypeClassIndex = loadInt32(&bytes, endPtr);
5474 PRINT_DEBUG_DATA("Parameter $%d type class index: %d\n", ii, parameterTypeClassIndex);
5475
5476 parameter->typeClassIndex = parameterTypeClassIndex;
5477 }
5478
5479 if(parameterCount % 2 != 0) { // Padding.
5480 skipInt32(&bytes, endPtr);
5481 }
5482
5483 method->index = i;
5484 method->parentClassIndex = parentClassIndex;
5485 method->surfaceIndex = surfaceIndex;
5486 method->overridedMethodIndex = overridedMethodIndex;
5487 method->loadedCodeSize = codeSize;
5488 method->parameterCount = parameterCount;
5489 method->refParametersCount = parameterReferenceCount;
5490 method->x64ParametersCount = x64ParameterCount;
5491 method->x32ParametersCount = x32ParameterCount;
5492 method->stackSize = stackSize;
5493 method->peakArgumentsSize = peakArgumentsSize;
5494 method->parameterStackSize = parameterStackSize;
5495 method->returnType = (CookeeType) returnType;
5496 method->returnTypeClassIndex = returnTypeClassIndex;
5497 method->nextFrameOffset = nextFrameOffset;
5498 method->refLocalsCount = localReferenceCount;
5499 method->x32LocalsCount = x32LocalCount;
5500 method->x64LocalsCount = x64LocalCount;
5501
5502 assert((method->x32ParametersCount + method->x64ParametersCount + method->refParametersCount) == method->parameterCount);
5503
5504 method->codeSize = method->loadedCodeSize;
5505 method->code = method->loadedCode;
5506
5507 PRINT_DEBUG_DATA("-----------------------------------\n");
5508 }
5509
5510 // #10 ... classes
5511 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5512 PRINT_DEBUG_DATA("CLASSES\n");
5513 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5514
5515 const Uint32 castingTableLength = alignSize(classCount, 8);
5516
5517 for(Uint32 i = 1; i < classCount; i += 1) {
5518 Class* const class = &classes[i];
5519
5520 // #10.1 Uint -- class name length
5521 const Uint32 nameLength = loadInt32(&bytes, endPtr);
5522 PRINT_DEBUG_DATA("Name length: %d\n", nameLength);
5523
5524 // #10.2 Uint -- class signature length
5525 const Uint32 signatureLength = loadInt32(&bytes, endPtr);
5526 PRINT_DEBUG_DATA("Signature length: %d\n", signatureLength);
5527
5528 // #10.3 Uint -- class super class index
5529 const Uint32 superClassIndex = loadInt32(&bytes, endPtr);
5530 PRINT_DEBUG_DATA("Super class index: %d\n", superClassIndex);
5531
5532 // #10.4 Uint -- class local field count
5533 const Uint32 fieldCount = loadInt32(&bytes, endPtr);
5534 PRINT_DEBUG_DATA("Field count: %d\n", fieldCount);
5535
5536 // #10.5 Uint -- class local method count
5537 const Uint32 methodCount = loadInt32(&bytes, endPtr);
5538 PRINT_DEBUG_DATA("Method count: %d\n", methodCount);
5539
5540 // #10.6 Uint -- class surface method count
5541 const Uint32 surfaceMethodCount = loadInt32(&bytes, endPtr);
5542 PRINT_DEBUG_DATA("Surface method count: %d\n", surfaceMethodCount);
5543
5544 // #10.7 Uint -- class initializer method index
5545 const Uint32 initializerMethodIndex = loadInt32(&bytes, endPtr);
5546 PRINT_DEBUG_DATA("Initializer method index: %d\n", initializerMethodIndex);
5547
5548 // #10.8 Uint -- class full instance size
5549 const Uint32 fullInstanceSize = loadInt32(&bytes, endPtr);
5550 PRINT_DEBUG_DATA("Full instance size: %d\n", fullInstanceSize);
5551
5552 // #10.9 Uint -- class head ref count
5553 const Uint32 headRefCount = loadInt32(&bytes, endPtr);
5554 PRINT_DEBUG_DATA("Head ref count: %d\n", headRefCount);
5555
5556 // #10.10 Uint -- class partition count
5557 const Uint32 partitionCount = loadInt32(&bytes, endPtr);
5558 PRINT_DEBUG_DATA("Partition count: %d\n", partitionCount);
5559
5560 // #10.11 Uint -- class temporary instance count
5561 const Uint32 temporaryInstanceCount = loadInt32(&bytes, endPtr);
5562 PRINT_DEBUG_DATA("Temporary instance count: %d\n", temporaryInstanceCount);
5563
5564 // #10.12 Uint -- class hierarachy size
5565 const Uint32 hierarchySize = loadInt32(&bytes, endPtr);
5566 PRINT_DEBUG_DATA("Hierarchy size: %d\n", hierarchySize);
5567
5568 // #10.13 ... class name characters(padded, null terminated)
5569 class->name = malloc(nameLength);
5570 CHKERR(class->name == NULL);
5571 loadStr(&bytes, class->name, nameLength, endPtr);
5572 PRINT_DEBUG_DATA("Name: %s\n", class->name);
5573
5574 // #10.14 ... class signature characters(padded, null terminated)
5575 class->signature = malloc(signatureLength);
5576 CHKERR(class->signature == NULL);
5577 loadStr(&bytes, class->signature, signatureLength, endPtr);
5578 PRINT_DEBUG_DATA("Signature: %s\n", class->signature);
5579
5580 // #10.15 ... class local field indexes (padded)
5581 if(fieldCount > 0) {
5582 class->fields = malloc(fieldCount * sizeof(Field*));
5583 CHKERR(class->fields == NULL);
5584
5585 for(Uint32 ii = 0; ii < fieldCount; ii += 1) {
5586 // #13.15.1 Uint -- local field index
5587 const Uint32 localFieldIndex = loadInt32(&bytes, endPtr);
5588 PRINT_DEBUG_DATA("Local field $%d index: %d\n", ii, localFieldIndex);
5589
5590 class->fields[ii] = &fields[localFieldIndex];
5591 }
5592
5593 if(fieldCount % 2 != 0) { // Padding.
5594 skipInt32(&bytes, endPtr);
5595 }
5596 }
5597
5598 // #10.16 ... class local method indexes (padded)
5599 if(methodCount > 0) {
5600 class->methods = malloc(methodCount * sizeof(Method*));
5601 CHKERR(class->methods == NULL);
5602
5603 for(Uint32 ii = 0; ii < methodCount; ii += 1) {
5604 // #13.16.1 Uint -- local method index
5605 const Uint32 localMethodIndex = loadInt32(&bytes, endPtr);
5606 PRINT_DEBUG_DATA("Local method $%d index: %d\n", ii, localMethodIndex);
5607
5608 class->methods[ii] = &methods[localMethodIndex];
5609 }
5610
5611 if(methodCount % 2 != 0) { // Padding.
5612 skipInt32(&bytes, endPtr);
5613 }
5614 }
5615
5616 // #10.17 ... class surface method indexes (padded)
5617 if(surfaceMethodCount > 0) {
5618 class->surfaceMethods = malloc(surfaceMethodCount * sizeof(Method*));
5619 CHKERR(class->surfaceMethods == NULL);
5620
5621 for(Uint32 ii = 0; ii < surfaceMethodCount; ii += 1) {
5622 // #13.17.1 Uint -- surface method index
5623 const Uint32 surfaceMethodIndex = loadInt32(&bytes, endPtr);
5624 PRINT_DEBUG_DATA("Surface method $%d index: %d\n", ii, surfaceMethodIndex);
5625
5626 class->surfaceMethods[ii] = &methods[surfaceMethodIndex];
5627 }
5628
5629 if(surfaceMethodCount % 2 != 0) { // Padding.
5630 skipInt32(&bytes, endPtr);
5631 }
5632 }
5633
5634 // #10.18 ... class partition jumps (padded)
5635 if(partitionCount > 0) {
5636 class->partitionJumps = malloc(partitionCount * sizeof(Uint32));
5637 CHKERR(class->partitionJumps == NULL);
5638
5639 for(Uint32 ii = 0; ii < partitionCount; ii += 1) {
5640 // #13.18.1 Uint -- partition jump amount
5641 const Uint32 partitionJump = loadInt32(&bytes, endPtr);
5642 PRINT_DEBUG_DATA("Partition $%d jump: %d\n", ii, partitionJump);
5643
5644 class->partitionJumps[ii] = partitionJump;
5645 }
5646
5647 if(partitionCount % 2 != 0) { // Padding.
5648 skipInt32(&bytes, endPtr);
5649 }
5650 }
5651
5652 // #10.19 ... class partition ref counts (padded)
5653 if(partitionCount > 0) {
5654 class->partitionRefCounts = malloc(partitionCount * sizeof(Uint32));
5655 CHKERR(class->partitionRefCounts == NULL);
5656
5657 for(Uint32 ii = 0; ii < partitionCount; ii += 1) {
5658 // #13.19.1 Uint -- partition ref count
5659 const Uint32 partitionRefCount = loadInt32(&bytes, endPtr);
5660 PRINT_DEBUG_DATA("Partition $%d ref count: %d\n", ii, partitionRefCount);
5661
5662 class->partitionRefCounts[ii] = partitionRefCount;
5663 }
5664
5665 if(partitionCount % 2 != 0) { // Padding.
5666 skipInt32(&bytes, endPtr);
5667 }
5668 }
5669
5670 // #10.20 ... class hierarchy class indexes (padded)
5671 // We also allocate and fill out the cast table here.
5672 class->castingTable = calloc(castingTableLength, sizeof(Uint8));
5673 CHKERR(class->castingTable == NULL);
5674
5675 if(hierarchySize > 0) {
5676 class->hierarchyClassIndexes = malloc(hierarchySize * sizeof(Uint32));
5677 CHKERR(class->hierarchyClassIndexes == NULL);
5678
5679 for(Uint32 ii = 0; ii < hierarchySize; ii += 1) {
5680 // #10.20.1 Uint -- compatible class index
5681 const Uint32 compatibleClassIndex = loadInt32(&bytes, endPtr);
5682 PRINT_DEBUG_DATA("Hierarchy class $%d index: %d\n", ii, compatibleClassIndex);
5683
5684 class->castingTable[compatibleClassIndex] = 1;
5685 class->hierarchyClassIndexes[ii] = compatibleClassIndex;
5686 }
5687 }
5688
5689 class->index = i;
5690 class->superClassIndex = superClassIndex;
5691 class->initializer = initializerMethodIndex == 0 ? NULL : &methods[initializerMethodIndex];
5692 class->fieldCount = fieldCount;
5693 class->methodCount = methodCount;
5694 class->surfaceMethodCount = surfaceMethodCount;
5695 class->temporaryInstanceCount = temporaryInstanceCount;
5696 class->fullInstanceSize = fullInstanceSize;
5697 class->headReferenceCount = headRefCount;
5698 class->partitionCount = partitionCount;
5699 class->hierarchySize = hierarchySize;
5700
5701 PRINT_DEBUG_DATA("-----------------------------------\n");
5702 }
5703
5704 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5705 PRINT_DEBUG_DATA("LONG LITERALS\n");
5706 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5707
5708 // #11 ... long literals
5709 loadInt64Array(&bytes, longLiterals, longLiteralCount, endPtr);
5710
5711 #ifdef COOKEE_DEBUG
5712 for(int i = 0; i < longLiteralCount; i += 1) {
5713 PRINT_DEBUG_DATA("Long literal $%d: %lld\n", i, longLiterals[i]);
5714 }
5715 #endif
5716
5717 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5718 PRINT_DEBUG_DATA("DOUBLE LITERALS\n");
5719 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5720
5721 // #12 ... double literals
5722 loadDoubleArray(&bytes, doubleLiterals, doubleLiteralCount, endPtr);
5723
5724 #ifdef COOKEE_DEBUG
5725 for(int i = 0; i < doubleLiteralCount; i += 1) {
5726 PRINT_DEBUG_DATA("Double literal $%d: %f\n", i, doubleLiterals[i]);
5727 }
5728 #endif
5729
5730 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5731 PRINT_DEBUG_DATA("TEXT LITERALS\n");
5732 PRINT_DEBUG_DATA("/////////////////////////////////////////////\n");
5733
5734 // #13 ... text literals
5735 for(Uint32 i = 0; i < textLiteralCount; i += 1) {
5736 Text* const textLiteral = &textLiterals[i];
5737
5738 // #13.1 Uint -- text literal length
5739 const Uint32 length = loadInt32(&bytes, endPtr);
5740 PRINT_DEBUG_DATA("Text literal $%d length: %d\n", i, length);
5741
5742 // #13.2 ... text literal characters(padded)
5743 CookeeChar* const chars = malloc((length + 1) * sizeof(CookeeChar));
5744 CHKERR(chars == NULL);
5745
5746 loadInt32Array(&bytes, (Int32*) chars, length, endPtr);
5747
5748 chars[length] = 0;
5749
5750 if(length % 2 != 0) { // Padding.
5751 skipInt32(&bytes, endPtr);
5752 }
5753
5754 textLiteral->length = length;
5755 textLiteral->chars = chars;
5756 }
5757
5758 PRINT_DEBUG_DATA("--- DATA LOADED ---\n");
5759
5760 #undef CHKERR
5761 return true;
5762}
5763
5764///////////////////////////////////////////////////////////////////////
5765// EXECUTION CONTEXT
5766///////////////////////////////////////////////////////////////////////
5767
5768// Contains standard library information.
5769typedef struct Lib Lib;
5770struct Lib {
5771
5772 // Pointer to the builtins class.
5773 const Class* builtinsClass;
5774
5775 // Index search range for builtin lib methods.
5776 Uint32 builtinsSearchRangeMin;
5777 Uint32 builtinsSearchRangeMax;
5778
5779};
5780
5781// Structure containing per-context class state.
5782typedef struct ClassState ClassState;
5783struct ClassState {
5784
5785 // Global instance of this class.
5786 CookeeObject globalInstance;
5787
5788 // Pool of instances for old instance allocation.
5789 CookeeObject* instancePool;
5790
5791 // List of temporary instances for tmp instance allocation.
5792 CookeeObject* temporaryInstances;
5793
5794 // The total capacity of instance pool.
5795 Uint32 instancePoolCapacity;
5796
5797 // The number of available freed old instances in instance pool.
5798 Uint32 availableOldInstances;
5799
5800};
5801
5802static Void purgeClassState(ClassState* const classState) {
5803 if(classState->temporaryInstances != NULL) {
5804 free(classState->temporaryInstances);
5805 }
5806 if(classState->instancePool != NULL) {
5807 free(classState->instancePool);
5808 }
5809}
5810
5811// Structure representing a frame which was inlined.
5812typedef struct InlineFrame InlineFrame;
5813struct InlineFrame {
5814
5815 // The method which was inclined.
5816 const Method* method;
5817
5818 // The sequence index of this inlined frame.
5819 Uint32 sequenceIndex;
5820
5821 // The sequence length of this inlined frame.
5822 Uint32 sequenceLength;
5823
5824 // The offset of the inline instruction containing location information.
5825 Uint32 inlineInstructionOffset;
5826
5827 // The offset in container stack frame where this inlined frame begins.
5828 Uint32 offset;
5829
5830 // The length of the frame indicating how many opcodes this frame spans through.
5831 Uint32 length;
5832
5833};
5834
5835typedef struct MethodState MethodState;
5836struct MethodState {
5837
5838 // Holds the method's modified code.
5839 Code* code;
5840
5841 // Holds a list of inlined frames.
5842 InlineFrame* inlineFrames;
5843
5844 // Holds the size of method's optimized code.
5845 Uint32 codeSize;
5846
5847 // The stack size of method after modification.
5848 Uint32 stackSize;
5849
5850 // The next frame offset of method after modification.
5851 Uint32 nextFrameOffset;
5852
5853 // The max number of bytes used for arguments within the method.
5854 Uint32 peakArgumentsSize;
5855
5856 // The number of inline frames this method state has.
5857 Uint32 inlineFrameCount;
5858
5859 // Total number of ref params and locals.
5860 Uint32 refVariables;
5861
5862 // Total number of x64 params and locals.
5863 Uint32 x64Variables;
5864
5865 // Total number of x32 params and locals.
5866 Uint32 x32Variables;
5867
5868 // Number of local references for the GC.
5869 Uint32 refLocals;
5870
5871 // Indicates if the optimizer is currently traversing through this method's code.
5872 // Needed to avoid infinite optimization loops.
5873 Bool traversing;
5874
5875 // Indicates if this method's code has been crumbled preventing the whole method from being inlined.
5876 Bool crumbled;
5877
5878};
5879
5880static Void purgeMethodState(MethodState* const methodState) {
5881 if(methodState->code != NULL) {
5882 free(methodState->code);
5883 }
5884 if(methodState->inlineFrames != NULL) {
5885 free(methodState->inlineFrames);
5886 }
5887}
5888
5889// Structure representing one stack frame.
5890typedef struct StackFrame StackFrame;
5891struct StackFrame {
5892
5893 // Pointer to the local stack of this frame for locals.
5894 Uint8* locals;
5895
5896 // Program counter of this frame at most recent position.
5897 Code* pc;
5898
5899 // Program count of this frame at the very start.
5900 Code* pcStart;
5901
5902 // The method being executed in this frame.
5903 const Method* method;
5904
5905 // Contains the offset in bytes of the next frame relative to this frame locals.
5906 Uint32 nextFrameOffset;
5907
5908 // Contains the offset of invokation in the current method call sequence
5909 Uint32 sequenceIndex;
5910
5911 // Contains the current method call sequence's length
5912 Uint32 sequenceLength;
5913
5914 // Indicates if this frame is fake and used only to wrap other frames.
5915 Bool fake;
5916
5917};
5918
5919// The execution context structure.
5920typedef struct Context Context;
5921struct Context {
5922
5923 // The data containing all loaded class/field/method/literal information.
5924 Data* data;
5925
5926 // Pointer to the garbage collector of the context.
5927 Gc* gc;
5928
5929 // The context's garbage collector extension. Saved so that it could be removed on context termination.
5930 GcExtension* gcExtension;
5931
5932 // Pointer to the start of the stack.
5933 Uint8* stackMin;
5934
5935 // Pointer to the end of the stack.
5936 Uint8* stackMax;
5937
5938 // Pointer to the stack frame which is currently being executed.
5939 StackFrame* currentFrame;
5940
5941 // Array of class states for all classes.
5942 ClassState** classStates;
5943
5944 // Array of method states for all methods.
5945 MethodState** methodStates;
5946
5947 // Table of text literal objects.
5948 CookeeObject* textLiteralTable;
5949
5950 // Message describing the panic.
5951 const Char* panicMessage;
5952
5953 // Holds the attachment of the currently executed native frame.
5954 Void* currentBindingAttachment;
5955
5956 // The stack frame which is currently being prepared to be called from a native frame.
5957 StackFrame* preparedFrame;
5958
5959 // A pointer to the standard library information. Might be NULL incase the standard library is not used.
5960 Lib* lib;
5961
5962 // Holds a data of the frame of first execute call. Used to unwind the stack in case of a panic.
5963 jmp_buf panicJmp;
5964
5965 // Indicates if the context is currently executing code. Used for recursive execute calls.
5966 Bool executing;
5967
5968 // Indicates if the context have panicked.
5969 Bool panicked;
5970
5971 // The index of next crumb that will be binded.
5972 Uint32 crumbIdx;
5973
5974 // Crumb table.
5975 CookeeCrumbFunction crumbles[MAX_CRUMBLES];
5976
5977};
5978
5979// Garbage collection extension function for reference marking.
5980static Void contextGcMarkExtension(Gc* const gc, Void* const ctx) {
5981 Context* const context = (Context*) ctx;
5982
5983 // Mark text literals.
5984
5985 CookeeObject* textLiteralTable = context->textLiteralTable;
5986 CookeeObject* const textLiteralTableN = textLiteralTable + context->data->textLiteralCount;
5987
5988 while(textLiteralTable != textLiteralTableN) {
5989 *textLiteralTable = markObject(gc, *textLiteralTable);
5990 textLiteralTable += 1;
5991 }
5992
5993 // Mark class states.
5994
5995 ClassState** const classStates = context->classStates;
5996 Class* const classes = context->data->classes;
5997 const Uint32 classesN = context->data->classCount;
5998
5999 for(Uint32 i = 0; i < classesN; i += 1) {
6000 ClassState* const classState = classStates[i];
6001
6002 if(classState == NULL) {
6003 continue;
6004 }
6005
6006 classState->globalInstance = markObject(gc, classState->globalInstance);
6007
6008 CookeeObject* temporaryInstances = classState->temporaryInstances;
6009
6010 if(temporaryInstances != NULL) {
6011 CookeeObject* const temporaryInstancesN = temporaryInstances + classes[i].temporaryInstanceCount;
6012
6013 while(temporaryInstances != temporaryInstancesN) {
6014 *temporaryInstances = markObject(gc, *temporaryInstances);
6015 temporaryInstances += 1;
6016 }
6017 }
6018
6019 CookeeObject* instancePool = classState->instancePool;
6020 CookeeObject* const instancePoolN = instancePool + classState->availableOldInstances;
6021
6022 while(instancePool != instancePoolN) {
6023 *instancePool = markObject(gc, *instancePool);
6024 instancePool += 1;
6025 }
6026 }
6027
6028 // Mark the stack.
6029
6030 MethodState** const methodStates = context->methodStates;
6031 StackFrame* frame = context->currentFrame;
6032
6033 // Skip very last frame since it's the execution frame.
6034 StackFrame* const frameN = (StackFrame*) context->stackMax - 1;
6035
6036 while(frame != frameN) {
6037 if(frame->fake) {
6038 frame += 1;
6039 continue;
6040 }
6041
6042 const Method* const method = frame->method;
6043 Uint8* const locals = frame->locals;
6044
6045 // Mark this pointer.
6046 assert(*((CookeeObject*) locals) != COOKEE_NULL); // This pointer should never be null.
6047 *((CookeeObject*) locals) = markObject(gc, *((CookeeObject*) locals));
6048
6049 Uint32* refOffsets = method->parameterRefOffsets;
6050 Uint32* const refOffsetsN = refOffsets + method->refParametersCount;
6051
6052 while(refOffsets != refOffsetsN) {
6053 CookeeObject* const offset = (CookeeObject*)(locals + *refOffsets);
6054 assert((Uint64)(offset) % sizeof(CookeeObject) == 0);
6055 *offset = markObject(gc, *offset);
6056 refOffsets += 1;
6057 }
6058
6059 CookeeObject* iter = (CookeeObject*)(locals + method->parameterStackSize);
6060 CookeeObject* const iterN = iter + methodStates[method->index]->refLocals;
6061
6062 while(iter != iterN) {
6063 *iter = markObject(gc, *iter);
6064 iter += 1;
6065 }
6066
6067 frame += 1;
6068 }
6069}
6070
6071// Garbage collection extension function for reference moving.
6072static void contextGcMoveExtension(Gc* const gc, Void* const ctx, const IntX amount) {
6073 Context* const context = (Context*) ctx;
6074
6075 // Move text literals.
6076
6077 CookeeObject* textLiteralTable = context->textLiteralTable;
6078 CookeeObject* const textLiteralTableN = textLiteralTable + context->data->textLiteralCount;
6079
6080 while(textLiteralTable != textLiteralTableN) {
6081 *textLiteralTable = moveObject(*textLiteralTable, amount);
6082 textLiteralTable += 1;
6083 }
6084
6085 // Move class states.
6086
6087 ClassState** const classStates = context->classStates;
6088 MethodState** const methodStates = context->methodStates;
6089 Class* const classes = context->data->classes;
6090 const Uint32 classesN = context->data->classCount;
6091
6092 for(Uint32 i = 0; i < classesN; i += 1) {
6093 ClassState* const classState = classStates[i];
6094
6095 if(classState == NULL) {
6096 continue;
6097 }
6098
6099 classState->globalInstance = moveObject(classState->globalInstance, amount);
6100
6101 CookeeObject* temporaryInstances = classState->temporaryInstances;
6102
6103 if(temporaryInstances != NULL) {
6104 CookeeObject* const temporaryInstancesN = temporaryInstances + classes[i].temporaryInstanceCount;
6105
6106 while(temporaryInstances != temporaryInstancesN) {
6107 *temporaryInstances = moveObject(*temporaryInstances, amount);
6108 temporaryInstances += 1;
6109 }
6110 }
6111
6112 CookeeObject* instancePool = classState->instancePool;
6113 CookeeObject* const instancePoolN = instancePool + classState->availableOldInstances;
6114
6115 while(instancePool != instancePoolN) {
6116 *instancePool = moveObject(*instancePool, amount);
6117 instancePool += 1;
6118 }
6119 }
6120
6121 // Move the stack.
6122
6123 StackFrame* frame = context->currentFrame;
6124
6125 // Skip very last frame since it's the execution frame.
6126 StackFrame* const frameN = (StackFrame*) context->stackMax - 1;
6127
6128 while(frame != frameN) {
6129 if(frame->fake) {
6130 frame += 1;
6131 continue;
6132 }
6133
6134 const Method* const method = frame->method;
6135 Uint8* const locals = frame->locals;
6136
6137 // Mark this pointer.
6138 *((CookeeObject*) locals) = moveObject(*((CookeeObject*) locals), amount);
6139
6140 Uint32* refOffsets = method->parameterRefOffsets;
6141 Uint32* const refOffsetsN = refOffsets + method->refParametersCount;
6142
6143 while(refOffsets != refOffsetsN) {
6144 CookeeObject* const offset = (CookeeObject*)(locals + *refOffsets);
6145 *offset = moveObject(*offset, amount);
6146 refOffsets += 1;
6147 }
6148
6149 CookeeObject* iter = (CookeeObject*)(locals + method->parameterStackSize);
6150 CookeeObject* const iterN = iter + methodStates[method->index]->refLocals;
6151
6152 while(iter != iterN) {
6153 *iter = moveObject(*iter, amount);
6154 iter += 1;
6155 }
6156
6157 frame += 1;
6158 }
6159}
6160
6161// Puts an indicator to the context indicating that it crashed and that all execution for the context should stop.
6162// Also stores the provided message describing what caused the crash.
6163// This function does not touch the current execution state so an uncorrupted stack trace can be retrieved afterwards.
6164//
6165static Void panic(Context* const context, const Char* const description) {
6166 context->panicked = true;
6167 context->panicMessage = description;
6168
6169 // Get back to the execution frame.
6170 longjmp(context->panicJmp, 1);
6171}
6172
6173// Returns aligned, gc formatted size including some additional space per instance data(such as the class index).
6174static Uint32 formatInstanceSize(const Uint32 size) {
6175 return formatAllocSize(size + sizeof(Uint8) + sizeof(Uint32));
6176}
6177
6178// Sets the instance type flag value for the given instance.
6179// On arrays this value is used to store the CookeeType of the array's items.
6180// On objects this value is used to store the allocation type.
6181//
6182static inline Void setInstanceTypeFlag(const CookeeObject instance, const Uint8 flag) {
6183 *((Uint8*) instance + getHeaderSize(objectToHeader(instance)) - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32) - 1) = flag;
6184}
6185
6186// Returns the instance type flag value of given instance.
6187static inline Uint8 getInstanceTypeFlag(const CookeeObject instance) {
6188 return *((Uint8*) instance + getHeaderSize(objectToHeader(instance)) - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32) - 1);
6189}
6190
6191// Sets the instance size flag value for given instance.
6192// On arrays this value is used to store the number of items in the array.
6193// On objects this value is used to store the index of the object's class.
6194//
6195static inline Void setInstanceSizeFlag(const CookeeObject instance, const Uint32 flag) {
6196 const Uint32 size = getHeaderSize(objectToHeader(instance));
6197 *((Uint32*)((Uint8*) instance + size - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32))) = flag;
6198}
6199
6200// Returns the instance size flag value of given instance.
6201static inline Uint32 getInstanceSizeFlag(const CookeeObject instance) {
6202 const Uint32 size = getHeaderSize(objectToHeader(instance));
6203 return *((Uint32*)((Uint8*) instance + size - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32)));
6204}
6205
6206static Void initInstance(const CookeeObject instance,
6207 const Uint32 size,
6208 const Uint8 typeFlag,
6209 const Uint32 sizeFlag) {
6210
6211 // Set the flags.
6212 Uint8* const ptr = (Uint8*) instance;
6213 *(ptr + size - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32) - 1) = typeFlag;
6214 *((Uint32*)(ptr + size - COOKEE_INSTANCE_HEADER_SIZE - sizeof(Uint32))) = sizeFlag;
6215}
6216
6217// Allocates a new instance of an array or object and returns it.
6218// @return the allocated instance or 0 if allocation failed.
6219//
6220static CookeeObject newInstance(Context* const context,
6221 const Uint32 refCount,
6222 const Uint32 size,
6223 const Uint8 typeFlag,
6224 const Uint32 sizeFlag,
6225 const Uint32 partitionCount,
6226 const Uint32* const partitionRefs,
6227 const Uint32* const partitionJumps) {
6228
6229 const CookeeObject instance = allocNew(context->gc, size, refCount, partitionCount, partitionRefs, partitionJumps);
6230
6231 if(instance != 0) {
6232 initInstance(instance, size, typeFlag, sizeFlag);
6233 }
6234
6235 return instance;
6236}
6237
6238// The flag used as object's freed indicator.
6239static const Uint8 OBJECT_FREE_FLAG = 0x80;
6240
6241// Mask used when retrieving the allocation type of the object(since one of the bits is used for free flag).
6242static const Uint8 OBJECT_ALLOCATION_TYPE_MASK = 0x7F;
6243
6244// Returns the class index of the given object.
6245static inline Uint32 getObjectClassIndex(const CookeeObject object) {
6246 return getInstanceSizeFlag(object);
6247}
6248
6249// Returns the allocation type of the given object.
6250static inline CookeeAllocationType getObjectAllocationType(const CookeeObject object) {
6251 return (CookeeAllocationType)(getInstanceTypeFlag(object) & OBJECT_ALLOCATION_TYPE_MASK);
6252}
6253
6254// Returns true if the object is marked as freed, false otherwise.
6255static inline Bool isObjectFreed(const CookeeObject object) {
6256 return (getInstanceTypeFlag(object) & OBJECT_FREE_FLAG) != 0;
6257}
6258
6259// Sets an indicator to the object instance that it is freed.
6260static inline Void setObjectFreeIndicator(const CookeeObject object) {
6261 const Uint8 instanceTypeFlag = getInstanceTypeFlag(object);
6262
6263 if((instanceTypeFlag & OBJECT_FREE_FLAG) != 0) {
6264 setInstanceTypeFlag(object, instanceTypeFlag | OBJECT_FREE_FLAG);
6265 }
6266}
6267
6268// Allocates a new object instance of a class.
6269static inline CookeeObject newObjectInstance(Context* const context,
6270 const Class* const class,
6271 const CookeeAllocationType type) {
6272
6273 return newInstance(context,
6274 class->headReferenceCount,
6275 class->fullInstanceSize,
6276 (Uint8) type,
6277 class->index,
6278 class->partitionCount,
6279 class->partitionRefCounts,
6280 class->partitionJumps);
6281}
6282
6283// Allocates a new object instance and returns it.
6284// @return the allocated object instance or 0 if allocation failed.
6285//
6286static inline CookeeObject newObject(Context* const context, const Class* const class) {
6287 return newObjectInstance(context, class, $COOKEE_ALLOCATION_TYPE_NEW);
6288}
6289
6290// Allocates or obtains an old object instance and returns it.
6291// @return the allocated or obtained object instance or 0 if allocation failed.
6292//
6293static CookeeObject oldObject(Context* const context, const Class* const class, ClassState* const classState) {
6294 assert(classState != NULL);
6295
6296 if(classState->availableOldInstances == 0) {
6297 // If the pool is empty allocate a new instance.
6298 return newObjectInstance(context, class, $COOKEE_ALLOCATION_TYPE_OLD);
6299 }
6300 else {
6301 const CookeeObject object = classState->instancePool[classState->availableOldInstances -= 1];
6302 assert(object != COOKEE_NULL);
6303
6304 // We need to reset the allocation type since it was flagged when the object was returned to the pool.
6305 setInstanceTypeFlag(object, $COOKEE_ALLOCATION_TYPE_OLD);
6306
6307 return object;
6308 }
6309}
6310
6311// Allocates or retrieves a temporary instance of given class and index.
6312// @return the allocated or retrieved object instance or 0 if allocation failed.
6313//
6314static CookeeObject tmpObject(Context* const context,
6315 const Class* const class,
6316 ClassState* const classState,
6317 const Code tmpIndex) {
6318
6319 assert(classState != NULL);
6320 assert(classState->temporaryInstances != NULL);
6321 assert(tmpIndex < class->temporaryInstanceCount);
6322
6323 CookeeObject* const temporaryInstances = classState->temporaryInstances;
6324 const CookeeObject tmpInstance = temporaryInstances[tmpIndex];
6325
6326 if(tmpInstance == 0) {
6327 // This will happen if it's the first time this instance is being accessed.
6328 const CookeeObject newTmpInstance = newObjectInstance(context, class, $COOKEE_ALLOCATION_TYPE_TMP);
6329 temporaryInstances[tmpIndex] = newTmpInstance;
6330 return newTmpInstance;
6331 }
6332 else {
6333 return tmpInstance;
6334 }
6335}
6336
6337// Puts the given instance back to old instance pool.
6338// Only instances allocated using oldObject function can be returned to the pool.
6339// One old instance can only be returned once.
6340// @return false if instance is not old or already freed, true if object successfully added back
6341// to the pool or an allocation error happened while resizing the pool.
6342//
6343static Bool freeOldObject(Context* const context, const CookeeObject instance) {
6344 assert(instance != COOKEE_NULL);
6345
6346 const Uint8 type = getInstanceTypeFlag(instance);
6347
6348 // Check if the type of instance is old and also make sure that the
6349 // freed bit is not already set(indicates that the instance is already in the pool)
6350 if(type != $COOKEE_ALLOCATION_TYPE_OLD || isObjectFreed(instance)) {
6351 return false;
6352 }
6353
6354 const Uint32 classIndex = getInstanceSizeFlag(instance);
6355 ClassState* const classState = context->classStates[classIndex];
6356
6357 assert(classState != NULL);
6358
6359 if(classState->instancePool == NULL) {
6360 classState->instancePoolCapacity = 4;
6361 classState->instancePool = malloc(classState->instancePoolCapacity * sizeof(CookeeObject));
6362
6363 if(classState->instancePool == NULL) {
6364 return true;
6365 }
6366 }
6367 else if(classState->availableOldInstances == classState->instancePoolCapacity) {
6368 const Uint32 newCapacity = classState->instancePoolCapacity * 2;
6369 CookeeObject* const newInstancePool = realloc(classState->instancePool, newCapacity * sizeof(CookeeObject));
6370
6371 if(newInstancePool == NULL) {
6372 return true;
6373 }
6374
6375 classState->instancePoolCapacity = newCapacity;
6376 classState->instancePool = newInstancePool;
6377 }
6378
6379 classState->instancePool[classState->availableOldInstances++] = instance;
6380
6381 // Update the type so that it would indicate that the instance is already in the pool.
6382 setObjectFreeIndicator(instance);
6383
6384 return true;
6385}
6386
6387// The flag used as array's lock indicator.
6388static const Uint8 ARRAY_LOCK_FLAG = 0x80;
6389
6390// Mask used when retrieving the type of the array(since one of the bits is used for lock flag).
6391static const Uint8 ARRAY_TYPE_MASK = 0x7F;
6392
6393// The flag used to indicate that the instance is an array.
6394static const Uint32 ARRAY_CATEGORY_FLAG = 0x80000000;
6395
6396// Mask used when retrieving the length of the array(since one of the bits is used to indicate that this is an array).
6397static const Uint32 ARRAY_LENGTH_MASK = 0x7FFFFFFF;
6398
6399// Allocates a new array with given item size and length.
6400// @return the allocated array or 0 if allocation failed.
6401//
6402static CookeeObject newArray(Context* const context, const CookeeType type, const Uint32 length) {
6403 assert(context != NULL);
6404 assert(type >= 0 && type < COOKEE_TYPE_N);
6405
6406 const Uint32 object = type == $COOKEE_TYPE_OBJECT;
6407 const Uint32 size = formatInstanceSize(length * CookeeTypeSize(type));
6408 const Uint32 refs = length * object;
6409
6410 return newInstance(context, refs, size, type, length | ARRAY_CATEGORY_FLAG, 0, NULL, NULL);
6411}
6412
6413// Returns true if the given instance is an array, false otherwise.
6414static inline Bool isArray(const CookeeObject instance) {
6415 return (getInstanceSizeFlag(instance) & ARRAY_CATEGORY_FLAG) != 0;
6416}
6417
6418// Returns the length of the given array.
6419static inline Uint32 getArrayLength(const CookeeObject array) {
6420 return getInstanceSizeFlag(array) & ARRAY_LENGTH_MASK;
6421}
6422
6423// Returns the type of items in the given array.
6424static inline CookeeType getArrayItemType(const CookeeObject array) {
6425 return (CookeeType) (getInstanceTypeFlag(array) & ARRAY_TYPE_MASK);
6426}
6427
6428// Returns true if the array is locked, false otherwise.
6429static inline Bool isArrayLocked(const CookeeObject array) {
6430 return (getInstanceTypeFlag(array) & ARRAY_LOCK_FLAG) != 0;
6431}
6432
6433// Sets an indicator to the array instance that the contents of the array should not change.
6434static inline Void setArrayLockIndicator(const CookeeObject array) {
6435 const Uint8 instanceTypeFlag = getInstanceTypeFlag(array);
6436
6437 if((instanceTypeFlag & ARRAY_LOCK_FLAG) != 0) {
6438 setInstanceTypeFlag(array, instanceTypeFlag | ARRAY_LOCK_FLAG);
6439 }
6440}
6441
6442// Destroys the given context and frees all allocated data.
6443static Void purgeContext(Context* const context) {
6444 // Unmark gc and data from usage.
6445 if(context->gc != NULL) {
6446 context->gc->contexts -= 1;
6447 }
6448 if(context->data != NULL) {
6449 context->data->contexts -= 1;
6450 }
6451
6452 if(context->methodStates != NULL) {
6453 const Uint32 methodCount = context->data->methodCount;
6454
6455 for(Uint32 i = 0; i < methodCount; i += 1) {
6456 MethodState* const methodState = context->methodStates[i];
6457
6458 if(methodState == NULL) {
6459 continue;
6460 }
6461
6462 purgeMethodState(methodState);
6463 free(methodState);
6464 }
6465 free(context->methodStates);
6466 }
6467 if(context->lib != NULL) {
6468 free(context->lib);
6469 }
6470 if(context->stackMin != NULL) {
6471 free(context->stackMin);
6472 }
6473 if(context->textLiteralTable != NULL) {
6474 free(context->textLiteralTable);
6475 }
6476 if(context->classStates != NULL) {
6477 const Uint32 classCount = context->data->classCount;
6478
6479 for(Uint32 i = 0; i < classCount; i += 1) {
6480 ClassState* const classState = context->classStates[i];
6481
6482 if(classState == NULL) {
6483 continue;
6484 }
6485
6486 purgeClassState(classState);
6487 free(classState);
6488 }
6489
6490 free(context->classStates);
6491 }
6492 if(context->gcExtension != NULL) {
6493 removeGcExtension(context->gc, context->gcExtension);
6494 free(context->gcExtension);
6495 }
6496}
6497
6498static Void initializeLib(Lib* const lib, const Data* const data) {
6499 const Class* const builtinsClass = findClass(data, LIB_CLASS_BUILTINS_SIGNATURE);
6500
6501 // Make sure it does not have any side effects.
6502 assert(builtinsClass->methodCount > 0);
6503 assert(builtinsClass->initializer == NULL);
6504 assert(builtinsClass->fieldCount == 0);
6505
6506 const Uint32 minMethodIndex = builtinsClass->methods[0]->index;
6507 const Uint32 maxMethodIndex = builtinsClass->methods[builtinsClass->methodCount - 1]->index;
6508
6509 lib->builtinsClass = builtinsClass;
6510 lib->builtinsSearchRangeMin = minMethodIndex;
6511 lib->builtinsSearchRangeMax = maxMethodIndex;
6512
6513 // Assert method indexing.
6514 #ifdef COOKEE_DEBUG
6515 for(Uint32 i = 1; i < builtinsClass->methodCount; i += 1) {
6516 assert(builtinsClass->methods[i]->index == builtinsClass->methods[i - 1]->index + 1);
6517 }
6518 #endif
6519
6520 // Assert array field offsets.
6521 assert(findField(data, LIB_FIELD_ARRAY_RAW_ARRAY_SIGNATURE)->offset == LIB_ARRAY_FIELD_RAW_ARRAY);
6522 assert(findField(data, LIB_FIELD_ARRAY_OFFSET_SIGNATURE)->offset == LIB_ARRAY_FIELD_OFFSET);
6523 assert(findField(data, LIB_FIELD_ARRAY_LENGTH_SIGNATURE)->offset == LIB_ARRAY_FIELD_LENGTH);
6524}
6525
6526// Initializes an execution context with provided configuration.
6527static Bool initializeContext(Context* const context,
6528 Data* const data,
6529 Gc* const gc,
6530 const Char* const starterClassSignature,
6531 const Uint32 stackSize) {
6532
6533 // Init stack
6534
6535 Uint8* const stack = calloc(stackSize, sizeof(Uint8));
6536
6537 if(stack == NULL) {
6538 printf("Failed to allocate the stack\n");
6539 purgeContext(context);
6540 return false;
6541 }
6542
6543 context->stackMin = stack;
6544 context->stackMax = stack + stackSize;
6545
6546 // Init data
6547
6548 // TODO: requires lock?
6549 data->contexts += 1;
6550 context->data = data;
6551
6552 if((context->textLiteralTable = calloc(data->textLiteralCount, sizeof(CookeeObject))) == NULL) {
6553 printf("Failed to allocate text literal table\n");
6554 purgeContext(context);
6555 return false;
6556 }
6557 if((context->classStates = calloc(data->classCount, sizeof(ClassState*))) == NULL) {
6558 printf("Failed to allocate class state table\n");
6559 purgeContext(context);
6560 return false;
6561 }
6562
6563 if((context->methodStates = calloc(data->methodCount, sizeof(MethodState*))) == NULL) {
6564 printf("Failed to allocate method state table\n");
6565 purgeContext(context);
6566 return false;
6567 }
6568
6569 // Init GC
6570
6571 // TODO: requires lock?
6572 context->gc = gc;
6573 gc->contexts += 1;
6574
6575 GcExtension* const gcExtension = malloc(sizeof(GcExtension));
6576
6577 if(gcExtension == NULL) {
6578 printf("Failed to allocate gc extension\n");
6579 purgeContext(context);
6580 return false;
6581 }
6582
6583 gcExtension->context = context;
6584 gcExtension->markFunction = contextGcMarkExtension;
6585 gcExtension->moveFunction = contextGcMoveExtension;
6586
6587 context->gcExtension = gcExtension;
6588
6589 // TODO: requires lock?
6590 addGcExtension(gc, gcExtension);
6591
6592 // Load standard library information if it's used.
6593
6594 if(findClass(data, LIB_ID) != NULL) {
6595 PRINT_DEBUG("Standard library usage found!\n");
6596
6597 if((context->lib = calloc(1, sizeof(Lib))) == NULL) {
6598 printf("Failed to allocate lib information.\n");
6599 purgeContext(context);
6600 return false;
6601 }
6602 initializeLib(context->lib, data);
6603 }
6604 else {
6605 PRINT_DEBUG("Standard library usage not found!\n");
6606 }
6607
6608 // Prepare starter frame for execution.
6609
6610 Class* const starterClass = findClass(data, starterClassSignature);
6611
6612 if(starterClass == NULL) {
6613 printf("Failed to find starter class %s\n", starterClassSignature);
6614 purgeContext(context);
6615 return false;
6616 }
6617
6618 const CookeeObject starterInstance = newObject(context, starterClass);
6619
6620 if(starterInstance == COOKEE_NULL) {
6621 printf("Failed to create started instance");
6622 purgeContext(context);
6623 return false;
6624 }
6625
6626 // Push the initializer frame.
6627 if(starterClass->initializer != NULL) {
6628 // Set up some of the initial frame variables.
6629 StackFrame* const frame = (StackFrame*)(stack + stackSize) - 1;
6630
6631 frame->locals = context->stackMin;
6632 frame->fake = true;
6633 frame->method = starterClass->initializer;
6634 frame->pc = starterClass->initializer->code;
6635 frame->pcStart = starterClass->initializer->code;
6636 frame->nextFrameOffset = starterClass->initializer->nextFrameOffset;
6637
6638 *((CookeeObject*) frame->locals) = starterInstance;
6639
6640 context->currentFrame = frame;
6641 }
6642
6643 return true;
6644}
6645
6646// This function should be called before executing the context.
6647// Returns true if context is valid for execution, false otherwise.
6648static Bool validateContext(Context* const context) {
6649 if(context->panicked) {
6650 return false;
6651 }
6652 if(context->data->createTextFunction == NULL) {
6653 panic(context, "No text creation function provided");
6654 return false;
6655 }
6656
6657 return true;
6658}
6659
6660///////////////////////////////////////////////////////////////////////
6661// OPTIMIZER
6662///////////////////////////////////////////////////////////////////////
6663
6664//////////////////////////////////////
6665// CODE INITIALIZATION FUNCTIONS
6666//////////////////////////////////////
6667
6668// Predeclaration of method initialization function since it is needed to recursively initialize all method calls.
6669static Void initializeMethod(Context* const context, const Method* const method);
6670
6671// Ensures that class state of a class is allocated.
6672//
6673// @param context - the current execution context.
6674// @param classIndex - the index of the class whose state should be allocated.
6675//
6676// @return the allocated class state.
6677//
6678static ClassState* ensureClassState(Context* const context, const Uint32 classIndex) {
6679 ClassState* classState = context->classStates[classIndex];
6680
6681 if(classState == NULL) {
6682 PRINT_DEBUG("Initializing class %s state\n", context->data->classes[classIndex].signature);
6683 classState = calloc(1, sizeof(ClassState));
6684
6685 if(classState == NULL) {
6686 panic(context, "Out of memory");
6687 }
6688
6689 context->classStates[classIndex] = classState;
6690 }
6691
6692 assert(classState != NULL);
6693 return classState;
6694}
6695
6696// Prepares OLD instruction for execution.
6697//
6698// @param context - the current execution context.
6699// @param classIndex - the index of the class that the old instruction is allocating.
6700//
6701static inline Void initOpcodeOLD(Context* const context, const Uint32 classIndex) {
6702 ensureClassState(context, classIndex);
6703}
6704
6705// Prepares TMP instruction for execution.
6706//
6707// @param context - the current execution context.
6708// @param classIndex - the index of the class that the tmp instruction is allocating.
6709//
6710static Void initOpcodeTMP(Context* const context, const Uint32 classIndex) {
6711 ClassState* const classState = ensureClassState(context, classIndex);
6712 CookeeObject* temporaryInstances = classState->temporaryInstances;
6713
6714 if(temporaryInstances == NULL) {
6715 PRINT_DEBUG("Initializing class %s tmp instance table\n", context->data->classes[classIndex].signature);
6716 temporaryInstances = calloc(context->data->classes[classIndex].temporaryInstanceCount, sizeof(CookeeObject));
6717
6718 if(temporaryInstances == NULL) {
6719 panic(context, "Out of memory");
6720 }
6721
6722 classState->temporaryInstances = temporaryInstances;
6723 }
6724}
6725
6726// Prepares GLOBAL instruction for execution.
6727//
6728// @param context - the current execution context.
6729// @param classIndex - the index of the class whose global instance the instruction is referring to.
6730//
6731static inline Void initOpcodeGLOBAL(Context* const context, const Uint32 classIndex) {
6732 ensureClassState(context, classIndex);
6733
6734 // Also prepare the initializer if it exists.
6735 const Method* const initializer = context->data->classes[classIndex].initializer;
6736 if(initializer != NULL) {
6737 initializeMethod(context, initializer);
6738 }
6739}
6740
6741// Prepares TEXT instruction for execution.
6742//
6743// @param context - the current execution context.
6744// @param literalIndex - the index of the text literal that the instruction is referring to.
6745//
6746static Void initOpcodeTEXT(Context* const context, const Uint32 literalIndex) {
6747 if(context->textLiteralTable[literalIndex] == COOKEE_NULL) {
6748 PRINT_DEBUG("Initializing text literal %d\n", literalIndex);
6749
6750 Void* const attachmentBackup = context->currentBindingAttachment;
6751 context->currentBindingAttachment = context->data->createTextFunctionAttachment;
6752
6753 const Data* const data = context->data;
6754 const CookeeObject textLiteral = data->createTextFunction(context,
6755 data->textLiterals[literalIndex].chars,
6756 data->textLiterals[literalIndex].length);
6757
6758 context->currentBindingAttachment = attachmentBackup;
6759
6760 if(textLiteral == COOKEE_NULL) {
6761 panic(context, "Out of memory");
6762 }
6763
6764 context->textLiteralTable[literalIndex] = textLiteral;
6765 }
6766}
6767
6768// Prepares INVOKE instruction for execution.
6769//
6770// @param context - the current execution context.
6771// @param methodIndex - the index of the method that is getting invoked.
6772//
6773static inline Void initOpcodeINVOKE(Context* const context, const Uint32 methodIndex) {
6774 initializeMethod(context, &context->data->methods[methodIndex]);
6775}
6776
6777// Prepares INVOKESEQ instruction for execution.
6778//
6779// @param context - the current execution context.
6780// @param methodIndex - the index of the method that is getting invoked.
6781//
6782static inline Void initOpcodeINVOKESEQ(Context* const context, const Uint32 methodIndex) {
6783 initializeMethod(context, &context->data->methods[methodIndex]);
6784}
6785
6786// Prepares an instruction for execution if any initialization is needed for it.
6787//
6788// @param context - the current execution context.
6789// @param instruction - the instruction to prepare.
6790//
6791static inline Void initInstruction(Context* const context,
6792 const Code* const instruction) {
6793
6794 switch(*instruction) {
6795 case $OPCODE_OLD:
6796 initOpcodeOLD(context, instruction[OLD_INSTRUCTION_CLASS_INDEX_OPERAND + 1]);
6797 break;
6798
6799 case $OPCODE_TMP:
6800 initOpcodeTMP(context, instruction[TMP_INSTRUCTION_CLASS_INDEX_OPERAND + 1]);
6801 break;
6802
6803 case $OPCODE_GLOBAL:
6804 initOpcodeGLOBAL(context, instruction[GLOBAL_INSTRUCTION_CLASS_INDEX_OPERAND + 1]);
6805 break;
6806
6807 case $OPCODE_TEXT:
6808 initOpcodeTEXT(context, instruction[TEXT_INSTRUCTION_TEXT_INDEX_OPERAND + 1]);
6809 break;
6810
6811 case $OPCODE_INVOKE:
6812 initOpcodeINVOKE(context, instruction[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1]);
6813 break;
6814
6815 case $OPCODE_INVOKESEQ:
6816 initOpcodeINVOKESEQ(context, instruction[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1]);
6817 break;
6818 }
6819}
6820
6821// Prepares the code of a method for execution if it contains any instruction which needs initialization.
6822//
6823// @param context - the current execution context.
6824// @param method - the method whose code should be prepared.
6825//
6826static Void initCode(Context* const context,
6827 const Method* const method) {
6828
6829 const Code* iter = method->code;
6830 const Code* const iterN = iter + method->codeSize;
6831
6832 while(iter != iterN) {
6833 initInstruction(context, iter);
6834 iter += reflectInstruction(*iter)->length;
6835 }
6836}
6837
6838//////////////////////////////////////
6839// CODE GENERATION FUNCTIONS
6840//////////////////////////////////////
6841
6842// Writes an OPCODE_CHKNULL_INLINE_INVOKE instruction to the destination array.
6843//
6844// @param dst - the destination array to which the instruction should be written.
6845// @param srcOffset - the local offset of the checked variable.
6846// @param location - the location of the instruction in source code.
6847//
6848// @return the given dst at location immediately after the instruction.
6849//
6850static inline Code* writeChknullInlineInvokeInstruction(Code* dst, const Uint32 srcOffset, const Uint32 location) {
6851 *dst++ = $OPCODE_CHKNULL_INLINE_INVOKE;
6852 *dst++ = srcOffset;
6853 *dst++ = location;
6854
6855 return dst;
6856}
6857
6858// Writes an OPCODE_INLINE_INVOKE instruction to the destination array.
6859//
6860// @param dst - the destination array to which the instruction should be written.
6861// @param location - the location of the instruction in source code.
6862//
6863// @return the given dst at location immediately after the instruction.
6864//
6865static inline Code* writeInlineInvokeInstruction(Code* dst, const Uint32 location) {
6866 *dst++ = $OPCODE_INLINE_INVOKE;
6867 *dst++ = location;
6868
6869 return dst;
6870}
6871
6872// Writes an OPCODE_INVOKE_NATIVE group instruction to the destination array.
6873//
6874// @param dst - the destination array to which the instruction should be written.
6875// @param opcode - the specific opcode of the OPCODE_INVOKE_NATIVE group instruction.
6876// @param srcOffset - the local offset of the invocation source.
6877// @param methodIndex - the index of the method to be invoked.
6878// @param dstOffset - the local offset of the destination.
6879// @param location - the location of the instruction in source code.
6880//
6881// @return the given dst at location immediately after the instruction.
6882//
6883static inline Code* writeInvokeNative(Code* dst,
6884 const Opcode opcode,
6885 const Uint32 srcOffset,
6886 const Uint32 methodIndex,
6887 const Uint32 dstOffset,
6888 const Uint32 location) {
6889
6890 assert(opcode >= $OPCODE_INVOKE_INATIVE && opcode <= $OPCODE_INVOKE_ONATIVE);
6891
6892 *dst++ = opcode;
6893 *dst++ = srcOffset;
6894 *dst++ = methodIndex;
6895 *dst++ = dstOffset;
6896 *dst++ = location;
6897
6898 return dst;
6899}
6900
6901// Writes an OPCODE_INVOKE_NATIVESEQ group instruction to the destination array.
6902//
6903// @param dst - the destination array to which the instruction should be written.
6904// @param opcode - the specific opcode of the OPCODE_INVOKE_NATIVESEQ group instruction.
6905// @param srcOffset - the local offset of the invocation source.
6906// @param methodIndex - the index of the method to be invoked.
6907// @param sequenceData - the sequence data to be passed upon invocation.
6908// @param dstOffset - the local offset of the destination.
6909// @param location - the location of the instruction in source code.
6910//
6911// @return the given dst at location immediately after the instruction.
6912//
6913static inline Code* writeInvokeNativeSeq(Code* dst,
6914 const Uint32 srcOffset,
6915 const Uint32 methodIndex,
6916 const Uint32 sequenceData,
6917 const Uint32 dstOffset,
6918 const Uint32 location) {
6919
6920 *dst++ = $OPCODE_INVOKE_NATIVESEQ;
6921 *dst++ = srcOffset;
6922 *dst++ = methodIndex;
6923 *dst++ = sequenceData;
6924 *dst++ = dstOffset;
6925 *dst++ = location;
6926
6927 return dst;
6928}
6929
6930// Writes an OPCODE_MOVE group instruction to the destination array.
6931//
6932// @param dst - the destination array to which the instruction should be written.
6933// @param opcode - the specific opcode of the OPCODE_MOVE group instruction.
6934// @param srcOffset - the local offset of the source value.
6935// @param dstOffset - the local offset of the destination.
6936//
6937// @return the given dst at location immediately after the instruction.
6938//
6939static inline Code* writeMove(Code* dst, const Opcode opcode, const Uint32 srcOffset, const Uint32 dstOffset) {
6940 assert(opcode >= $OPCODE_IMOVE && opcode <= $OPCODE_OMOVE);
6941
6942 *dst++ = opcode;
6943 *dst++ = srcOffset;
6944 *dst++ = dstOffset;
6945
6946 return dst;
6947}
6948
6949// Writes an OPCODE_GOTO instruction to the destination array.
6950//
6951// @param dst - the destination array to which the instruction should be written.
6952// @param offset - offset of code to which the goto instruction should jump to.
6953//
6954// @return the given dst at location immediately after the instruction.
6955//
6956static inline Code* writeGoto(Code* dst, const Uint32 offset) {
6957 *dst++ = $OPCODE_GOTO;
6958 *dst++ = offset;
6959
6960 return dst;
6961}
6962
6963//////////////////////////////////////
6964// OPTIMIZATION UTILITIES
6965//////////////////////////////////////
6966
6967#if MAX_METHOD_CODE_SIZE > 65536
6968 #error Code offset buffers are only suited for 16-bit offsets
6969#endif
6970
6971#if MAX_METHOD_STACK_SIZE > 65536
6972 #error Stack offset buffers are only suited for 16-bit offsets
6973#endif
6974
6975// All buffers needed by optimizations.
6976
6977// The argument write buffer needed by method inlining and native optimization passes.
6978static Uint32 ARGUMENT_WRITE_BUFFER[MAX_METHOD_PARAMETERS];
6979
6980// The number of buffers needed can be reduced later after all optimizations are implemented.
6981
6982// Code offset buffer used to map old code offsets to new ones when code is being modified. So another pass can adjust all
6983// goto offsets and inline frame offsets to the changes made.
6984//
6985static Uint16 CODE_OFFSET_BUFFER[MAX_METHOD_CODE_SIZE];
6986
6987static Uint32 UINT32_BUFFER_MAX_METHOD_CODE_SIZE2[MAX_METHOD_CODE_SIZE]; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TEMP
6988
6989// Variable offset buffer for relocating variables. Used for mapping old variable offsets to new ones.
6990static Uint16 VARIABLE_OFFSET_BUFFER[MAX_METHOD_STACK_SIZE];
6991
6992// Two code buffer to ping-pong between when modifying code.
6993static Code SWAP_CODE_BUFFER1[MAX_METHOD_CODE_SIZE];
6994static Code SWAP_CODE_BUFFER2[MAX_METHOD_CODE_SIZE];
6995
6996// Some macros to keep the code easier to read.
6997
6998#define INSTRUCTION_OPERAND_SRC_STACK_OFFSET \
6999 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT: \
7000 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG: \
7001 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT: \
7002 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE: \
7003 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT
7004
7005#define INSTRUCTION_OPERAND_DST_STACK_OFFSET \
7006 $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT: \
7007 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG: \
7008 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT: \
7009 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE: \
7010 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT
7011
7012#define INSTRUCTION_OPERAND_STACK_OFFSET \
7013 $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT: \
7014 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG: \
7015 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT: \
7016 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE: \
7017 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT: \
7018 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT: \
7019 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG: \
7020 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT: \
7021 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE: \
7022 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT
7023
7024// Checks if given instruction is a method invocation which can be optimized.
7025// E.g. It's not possible to optimize native or abstract invocations since their code is not statically known.
7026//
7027// @param instruction - the instruction to check.
7028// @return true if instruction is an invocation which can be optimized, false otherwise.
7029//
7030static inline Bool isOptimizableInvoke(const Instruction* const instruction) {
7031 return instruction->category == $INSTRUCTION_CATEGORY_INVOKE &&
7032 !isInvocationInstructionAbstract(instruction) &&
7033 !isInvocationInstructionNative(instruction);
7034}
7035
7036// Eliminates all NOOP instructions from src code buffer by copying all code excluding the NOOP instructions from src code
7037// buffer to dst code buffer. During copy also stores the mappings from old code offsets to new ones so that gotos could
7038// be adjusted. This function is used after passes which eliminate instructions since it's more efficient to replace an
7039// instruction with a bunch of NOOPs and later remove them all in one go than to copy all code after the removed instruction
7040// multiple times.
7041//
7042// @param srcStart - pointer to the start of the source code buffer.
7043// @param srcEnd - pointer to the end of the source code buffer.
7044// @param codeOffsetBuffer - pointer to the code offset buffer.
7045// @param dst - pointer to the start of the destination code buffer.
7046//
7047// @return pointer to the end of the destination code buffer.
7048//
7049static Code* eliminateNoops(const Code* const srcStart,
7050 const Code* const srcEnd,
7051 Uint16* const codeOffsetBuffer,
7052 Code* dst) {
7053
7054 Code* const dstStart = dst;
7055
7056 const Code* const iterStart = srcStart;
7057 const Code* const iterN = srcEnd;
7058 const Code* iter = iterStart;
7059
7060 while(iter != iterN) {
7061 const Instruction* const instruction = reflectInstruction(*iter);
7062 const Uint32 instructionLength = instruction->length;
7063
7064 codeOffsetBuffer[iter - iterStart] = (Uint16)(dst - dstStart);
7065
7066 if(instruction->opcode == $OPCODE_NOOP) {
7067 iter += instructionLength;
7068 continue;
7069 }
7070
7071 memcpy(dst, iter, instructionLength * sizeof(Code));
7072 dst += instructionLength;
7073 iter += instructionLength;
7074 }
7075
7076 return dst;
7077}
7078
7079// Relocates all argument space references to a new offset. This function is used when the stack size of a method needs to be
7080// shrinked or grown.
7081//
7082// @param start - pointer to the start of the code buffer.
7083// @param end - pointer to the end of the code buffer.
7084// @param oldArgumentsOffset - the old offset of the argument space.
7085// @param newArgumentsOffset - the new offset of the argument space(to which to change to).
7086//
7087static Void relocateArgs(Code* const start,
7088 Code* const end,
7089 const Uint32 oldArgumentsOffset,
7090 const Uint32 newArgumentsOffset) {
7091
7092 Code* iter = start;
7093 Code* const iterN = end;
7094
7095 while(iter != iterN) {
7096 const Instruction* const instruction = reflectInstruction(*iter);
7097 const Uint32 instructionLength = instruction->length;
7098 const InstructionOperand* const operands = instruction->operands;
7099
7100 // Start the loop from 1 since the first one is the opcode.
7101 for(Uint32 i = 1; i < instructionLength; i += 1) {
7102 switch(operands[i - 1]) {
7103 case INSTRUCTION_OPERAND_STACK_OFFSET: {
7104 const Uint32 offset = iter[i];
7105
7106 if(offset >= oldArgumentsOffset) {
7107 iter[i] = newArgumentsOffset + (offset - oldArgumentsOffset);
7108 }
7109 }
7110 break;
7111
7112 default: break;
7113 }
7114 }
7115
7116 iter += instructionLength;
7117 }
7118}
7119
7120// Relocates a single variable offset to a new offset.
7121//
7122// @param variableOffets - pointer to the variable offset buffer.
7123// @param offset - pointer to the code point containing the offset. It can be modified to point to the new offset.
7124// @param typeOffset - the current offset of the vairiable's type.
7125// @param typeStep - the amount to step the variable's type offset in case a new offset is created.
7126// @param argumentsOffset - offset of the argument space to identify arguments.
7127//
7128// @return type offset if a new offset was not created or the type offset after type step if the new offset was created.
7129//
7130static inline Uint32 relocateVar(Uint16* const variableOffsetBuffer,
7131 Code* const offset,
7132 const Uint32 typeOffset,
7133 const Uint32 typeStep,
7134 const Uint32 argumentsOffset) {
7135
7136 assert(typeOffset % typeStep == 0); // Make sure the offsets are properly aligned.
7137
7138 const Uint32 oldOffset = *offset;
7139
7140 // If the offset is not this reference and not argument then relocate it.
7141 if(oldOffset != 0 && oldOffset < argumentsOffset) {
7142 // Check if there's a relocation assigned to the variable.
7143 const Uint32 reloc = variableOffsetBuffer[oldOffset];
7144
7145 if(reloc == 0) {
7146 // There's no relocated offset assigned, assign one.
7147 variableOffsetBuffer[oldOffset] = typeOffset;
7148 *offset = typeOffset;
7149 return typeOffset + typeStep;
7150 }
7151 else {
7152 assert(reloc % typeStep == 0); // Make sure the offsets are properly aligned.
7153
7154 *offset = reloc;
7155 return typeOffset;
7156 }
7157 }
7158
7159 return typeOffset;
7160}
7161
7162// Relocates all variables within the method to point to new offsets. Used after variable counts changed.
7163//
7164// @param methodState - state of the method whose variables are being relocated.
7165// @param methodData - data of the method whose variables are being relocated.
7166// @param start - pointer to the start of the method's code.
7167// @param end - pointer to the end of the method's code.
7168//
7169static Void relocateVars(const MethodState* const methodState,
7170 const Method* const methodData,
7171 Code* const start,
7172 Code* const end) {
7173
7174 const Uint32 argumentsOffset = methodState->nextFrameOffset;
7175
7176 Uint16* const variableOffsets = VARIABLE_OFFSET_BUFFER;
7177
7178 // Only the variables up to the point of argument space will be mapped, so to be more efficient zero out only that space.
7179 memset(variableOffsets, 0, argumentsOffset * sizeof(Uint16));
7180
7181 // Immediately assign parameter indexes in the variable array since they always need to maintain the order.
7182 const Parameter* const parameters = methodData->parameters;
7183 const Uint32 parameterCount = methodData->parameterCount;
7184
7185 for(Uint32 i = 0; i < parameterCount; i += 1) {
7186 const Parameter* const parameter = ¶meters[i];
7187 variableOffsets[parameter->offset] = parameter->offset;
7188 }
7189
7190 // Calculate the starting offset of each size(refs, 64-bit values, 32-bit values).
7191 Uint32 refOffset = methodData->parameterStackSize;
7192 Uint32 x64Offset = refOffset + (methodState->refVariables - methodData->refParametersCount) * sizeof(CookeeObject);
7193 Uint32 x32Offset = x64Offset + (methodState->x64Variables - methodData->x64ParametersCount) * sizeof(CookeeDouble);
7194
7195 assert(refOffset % sizeof(CookeeObject) == 0);
7196 assert(x64Offset % sizeof(CookeeDouble) == 0);
7197 assert(x32Offset % sizeof(CookeeInt) == 0);
7198
7199 Code* iter = start;
7200 Code* const iterN = end;
7201
7202 while(iter != iterN) {
7203 const Instruction* const instruction = reflectInstruction(*iter);
7204 const Uint32 instructionLength = instruction->length;
7205 const InstructionOperand* const operands = instruction->operands;
7206 const Uint32 operandCount = instructionLength - 1;
7207
7208 for(Uint32 i = 0; i < operandCount; i += 1) {
7209 const InstructionOperand operand = operands[i];
7210 Code* const operandPtr = iter + i + 1;
7211
7212 switch(operand) {
7213 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_INT:
7214 x32Offset = relocateVar(variableOffsets, operandPtr, x32Offset, sizeof(CookeeInt), argumentsOffset);
7215 break;
7216
7217 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_LONG:
7218 x64Offset = relocateVar(variableOffsets, operandPtr, x64Offset, sizeof(CookeeDouble), argumentsOffset);
7219 break;
7220
7221 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_FLOAT:
7222 x32Offset = relocateVar(variableOffsets, operandPtr, x32Offset, sizeof(CookeeInt), argumentsOffset);
7223 break;
7224
7225 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_DOUBLE:
7226 x64Offset = relocateVar(variableOffsets, operandPtr, x64Offset, sizeof(CookeeDouble), argumentsOffset);
7227 break;
7228
7229 case $INSTRUCTION_OPERAND_SRC_STACK_OFFSET_OBJECT:
7230 refOffset = relocateVar(variableOffsets, operandPtr, refOffset, sizeof(CookeeObject), argumentsOffset);
7231 break;
7232
7233 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_INT:
7234 x32Offset = relocateVar(variableOffsets, operandPtr, x32Offset, sizeof(CookeeInt), argumentsOffset);
7235 break;
7236
7237 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_LONG:
7238 x64Offset = relocateVar(variableOffsets, operandPtr, x64Offset, sizeof(CookeeDouble), argumentsOffset);
7239 break;
7240
7241 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_FLOAT:
7242 x32Offset = relocateVar(variableOffsets, operandPtr, x32Offset, sizeof(CookeeInt), argumentsOffset);
7243 break;
7244
7245 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_DOUBLE:
7246 x64Offset = relocateVar(variableOffsets, operandPtr, x64Offset, sizeof(CookeeDouble), argumentsOffset);
7247 break;
7248
7249 case $INSTRUCTION_OPERAND_DST_STACK_OFFSET_OBJECT:
7250 refOffset = relocateVar(variableOffsets, operandPtr, refOffset, sizeof(CookeeObject), argumentsOffset);
7251 break;
7252
7253 default:
7254 break;
7255 }
7256 }
7257
7258 iter += instructionLength;
7259 }
7260}
7261
7262// Relocates all jump offsets inside the code to new offsets by using the code offset buffer's old-to-new mapping.
7263// This function is used after passes which adds or removes instructions(modifies code size) from a method.
7264//
7265// @param start - pointer to the start of the code buffer.
7266// @param end - pointer to the end of the code buffer.
7267// @param codeOffsetBuffer - pointer to the code offset buffer.
7268//
7269static Void relocateJumps(Code* const start,
7270 Code* const end,
7271 const Uint16* const codeOffsetBuffer) {
7272
7273 assert(MAX_INSTRUCTION_CODE_OFFSETS == 1);
7274
7275 Code* iter = start;
7276 Code* const iterN = end;
7277
7278 while(iter != iterN) {
7279 const Instruction* const instruction = reflectInstruction(*iter);
7280 const Uint32 instructionLength = instruction->length;
7281 const Uint32 jumpOperandIndex = indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_CODE_OFFSET);
7282
7283 if(jumpOperandIndex != -1) {
7284 iter[jumpOperandIndex + 1] = codeOffsetBuffer[iter[jumpOperandIndex + 1]];
7285 }
7286
7287 iter += instructionLength;
7288 }
7289}
7290
7291// Relocates all offsets/lengths of inline frames to new ones by using the code offset buffer's old-to-new mapping.
7292// This function is used after passes which adds or removes instructions(modifies code size) from a method.
7293//
7294// @param start - pointer to the start of the inline frame list.
7295// @param end - pointer to the end of the inline frame list.
7296// @param codeOffsetBuffer - pointer to the code offset buffer.
7297//
7298static Void relocateFrames(InlineFrame* const start,
7299 InlineFrame* const end,
7300 const Uint16* const codeOffsetBuffer) {
7301
7302 InlineFrame* inlineFrameIter = start;
7303 InlineFrame* const inlineFrameN = end;
7304
7305 while(inlineFrameIter != inlineFrameN) {
7306 const Uint32 offset = inlineFrameIter->offset;
7307 const Uint32 length = inlineFrameIter->length;
7308
7309 inlineFrameIter->inlineInstructionOffset = codeOffsetBuffer[inlineFrameIter->inlineInstructionOffset];
7310
7311 inlineFrameIter->offset = codeOffsetBuffer[offset];
7312 inlineFrameIter->length = codeOffsetBuffer[offset + length] - inlineFrameIter->offset;
7313
7314 inlineFrameIter += 1;
7315 }
7316}
7317
7318//////////////////////////////////////
7319// LIB/NATIVE CALL OPTIMIZATION
7320//////////////////////////////////////
7321
7322// Checks if an instruction is a MOVE from argument space indicating a fetch of a return value.
7323//
7324// @param instructionCode - the code of the instruction to check.
7325// @param argumentsOffset - the argument space offset of the method where the instruction is located.
7326//
7327// @return true if instruction is a MOVE operation from argument space, false otherwise.
7328//
7329static inline Bool isMoveFromReturn(const Code* const instructionCode, const Uint32 argumentsOffset) {
7330 const Instruction* const instruction = reflectInstruction(*instructionCode);
7331 return instruction->category == $INSTRUCTION_CATEGORY_MOVE &&
7332 instructionCode[MOVE_INSTRUCTION_SRC_OFFSET_OPERAND + 1] == argumentsOffset;
7333}
7334
7335// Checks if the iterator is currently pointing the a move instruction which is used to fetch a returned value and if so,
7336// fetches the offset where the returned value would be stored locally returning the offset and moving the iterator forward.
7337//
7338// @param iterPtr - pointer to the current code iterator.
7339// @param iterN - pointer to the end of the code.
7340// @param argumentsOffset - the stack offset of argument space.
7341//
7342// @return the offset where result value should be stored.
7343//
7344static inline Uint32 reducedDstOffset(const Code** const iterPtr, const Code* const iterN, const Uint32 argumentsOffset) {
7345 const Code* const iter = *iterPtr;
7346
7347 if(iter < iterN && isMoveFromReturn(iter, argumentsOffset)) {
7348 const Uint32 offset = iter[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
7349 *iterPtr += reflectInstruction(*iter)->length;
7350 return offset;
7351 }
7352 else {
7353 return argumentsOffset;
7354 }
7355}
7356
7357// Fetches the local offset of an argument from argument MOVE instruction(a move instruction which moved a local value
7358// to argument space) also replacing the whole MOVE instruction with NOOPs.
7359//
7360// @param argumentMoveCode - pointer to an argument MOVE instruction.
7361// @return the local offset from which argument was moved.
7362//
7363static inline Uint32 reducedSrcOffset(Code* const argumentMoveCode) {
7364 assert(reflectInstruction(*argumentMoveCode)->category == $INSTRUCTION_CATEGORY_MOVE);
7365 const Uint32 offset = argumentMoveCode[MOVE_INSTRUCTION_SRC_OFFSET_OPERAND + 1];
7366 memset(argumentMoveCode, $OPCODE_NOOP, reflectInstruction(*argumentMoveCode)->length * sizeof(Code));
7367 return offset;
7368}
7369
7370// Some lib calls returns this but their equivalent instructions don't have a dst offset argument, so this function moves the
7371// source of the lib call to where the user wanted it, but only if the return value was actually used.
7372//
7373// @param iterPtr - pointer to the current code iterator.
7374// @param iterN - pointer to the end of the code.
7375// @param sourceOffset - the offset of the object instance on which the library call was invoked.
7376// @param argumentsOffset - the stack offset of argument space.
7377// @param dst - the destination pointer to which the MOVE should be written if needed.
7378//
7379// @return the same dst pointer if no move instruction was written, or pointer to the code immediately after the newly
7380// written move.
7381//
7382static inline Code* handleSetterMove(const Code** const iterPtr,
7383 const Code* const iterN,
7384 const Uint32 sourceOffset,
7385 const Uint32 argumentsOffset,
7386 Code* const dst) {
7387
7388 const Code* const iter = *iterPtr;
7389
7390 if(iter < iterN && isMoveFromReturn(iter, argumentsOffset)) {
7391 Code* const newDst = writeMove(dst, $OPCODE_OMOVE, sourceOffset, iter[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1]);
7392 *iterPtr += reflectInstruction($OPCODE_OMOVE)->length;
7393 return newDst;
7394 }
7395 else {
7396 return dst;
7397 }
7398}
7399
7400// Stores the local value offset of an argument of a lib call with 1 parameter.
7401//
7402// @param argumentWriteBuffer - pointer to the start of the argument write buffer.
7403// @param argumentWrites - pointer to the current slot in argument write buffer.
7404// @param dstStart - pointer to the start of the destination code buffer.
7405// @param arg1 - pointer to the output integer where the local offset will be stored.
7406//
7407// @return pointer to the start of the argument write buffer.
7408//
7409static inline Uint32* readLibCallArgs1(const Uint32* const argumentWriteBuffer,
7410 const Uint32* const argumentWrites,
7411 Code* const dstStart,
7412 Uint32* const arg1) {
7413
7414 assert(argumentWrites - argumentWriteBuffer >= 1);
7415 *arg1 = reducedSrcOffset(dstStart + *(argumentWrites - 1));
7416 return (Uint32*) argumentWriteBuffer;
7417}
7418
7419// Stores the local value offsets of 2 arguments of a lib call with 2 parameters while also handling the order
7420// in which they were provided.
7421//
7422// @param method - pointer to the method which is being called.
7423// @param argumentWriteBuffer - the pointer to the start of the argument write buffer.
7424// @param argumentWrites - the pointer to the current slot in argument write buffer.
7425// @param argumentsOffset - offset of the argument space.
7426// @param dstStart - pointer to the start of the destination code buffer.
7427// @param arg1 - pointer to the output integer where the local offset of the first argument will be stored.
7428// @param arg2 - pointer to the output integer where the local offset of the second argument will be stored.
7429//
7430// @return pointer to the start of the argument write buffer.
7431//
7432static Uint32* readLibCallArgs2(const Method* const method,
7433 const Uint32* const argumentWriteBuffer,
7434 const Uint32* const argumentWrites,
7435 const Uint32 argumentsOffset,
7436 Code* const dstStart,
7437 Uint32* const arg1,
7438 Uint32* const arg2) {
7439
7440 assert(method->parameterCount == 2);
7441 assert(argumentWrites - argumentWriteBuffer >= 2);
7442
7443 Code* instruction;
7444
7445 instruction = dstStart + *(argumentWrites - 1);
7446 assert(reflectInstruction(*instruction)->category == $INSTRUCTION_CATEGORY_MOVE);
7447
7448 if(instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1] == method->parameters[0].offset + argumentsOffset) {
7449 *arg1 = reducedSrcOffset(instruction);
7450 }
7451 else {
7452 assert(instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1] == method->parameters[1].offset + argumentsOffset);
7453 *arg2 = reducedSrcOffset(instruction);
7454 }
7455
7456 instruction = dstStart + *(argumentWrites - 2);
7457 assert(reflectInstruction(*instruction)->category == $INSTRUCTION_CATEGORY_MOVE);
7458
7459 if(instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1] == method->parameters[0].offset + argumentsOffset) {
7460 *arg1 = reducedSrcOffset(instruction);
7461 }
7462 else {
7463 assert(instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1] == method->parameters[1].offset + argumentsOffset);
7464 *arg2 = reducedSrcOffset(instruction);
7465 }
7466
7467 return (Uint32*) argumentWriteBuffer;
7468}
7469
7470// Stores the local value offsets of 3 arguments of a lib call with 3 parameters while also handling the order
7471// in which they were provided.
7472//
7473// @param method - pointer to the method which is being called.
7474// @param argumentWriteBuffer - the pointer to the start of the argument write buffer.
7475// @param argumentWrites - the pointer to the current slot in argument write buffer.
7476// @param argumentsOffset - offset of the argument space.
7477// @param dstStart - pointer to the start of the destination code buffer.
7478// @param arg1 - pointer to the output integer where the local offset of the first argument will be stored.
7479// @param arg2 - pointer to the output integer where the local offset of the second argument will be stored.
7480// @param arg3 - pointer to the output integer where the local offset of the third argument will be stored.
7481//
7482// @return pointer to the start of the argument write buffer.
7483//
7484static Uint32* readLibCallArgs3(const Method* const method,
7485 const Uint32* const argumentWriteBuffer,
7486 const Uint32* const argumentWrites,
7487 const Uint32 argumentsOffset,
7488 Code* const dstStart,
7489 Uint32* const arg1,
7490 Uint32* const arg2,
7491 Uint32* const arg3) {
7492
7493 assert(method->parameterCount == 3);
7494 assert(argumentWrites - argumentWriteBuffer >= 3);
7495
7496 Code* instruction;
7497
7498 instruction = dstStart + *(argumentWrites - 1);
7499 assert(reflectInstruction(*instruction)->category == $INSTRUCTION_CATEGORY_MOVE);
7500
7501 const Uint32 moveOffset1 = instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
7502
7503 if(moveOffset1 == method->parameters[0].offset + argumentsOffset) {
7504 *arg1 = reducedSrcOffset(instruction);
7505 }
7506 else if(moveOffset1 == method->parameters[1].offset + argumentsOffset) {
7507 *arg2 = reducedSrcOffset(instruction);
7508 }
7509 else {
7510 assert(moveOffset1 == method->parameters[2].offset + argumentsOffset);
7511 *arg3 = reducedSrcOffset(instruction);
7512 }
7513
7514 instruction = dstStart + *(argumentWrites - 2);
7515 assert(reflectInstruction(*instruction)->category == $INSTRUCTION_CATEGORY_MOVE);
7516
7517 const Uint32 moveOffset2 = instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
7518
7519 if(moveOffset2 == method->parameters[0].offset + argumentsOffset) {
7520 *arg1 = reducedSrcOffset(instruction);
7521 }
7522 else if(moveOffset2 == method->parameters[1].offset + argumentsOffset) {
7523 *arg2 = reducedSrcOffset(instruction);
7524 }
7525 else {
7526 assert(moveOffset2 == method->parameters[2].offset + argumentsOffset);
7527 *arg3 = reducedSrcOffset(instruction);
7528 }
7529
7530 instruction = dstStart + *(argumentWrites - 3);
7531 assert(reflectInstruction(*instruction)->category == $INSTRUCTION_CATEGORY_MOVE);
7532
7533 const Uint32 moveOffset3 = instruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
7534
7535 if(moveOffset3 == method->parameters[0].offset + argumentsOffset) {
7536 *arg1 = reducedSrcOffset(instruction);
7537 }
7538 else if(moveOffset3 == method->parameters[1].offset + argumentsOffset) {
7539 *arg2 = reducedSrcOffset(instruction);
7540 }
7541 else {
7542 assert(moveOffset3 == method->parameters[2].offset + argumentsOffset);
7543 *arg3 = reducedSrcOffset(instruction);
7544 }
7545
7546 return (Uint32*) argumentWriteBuffer;
7547}
7548
7549// Replaces simple invocations to natively implemented methods with native invocation instruction counterparts and
7550// replaces invocations to library methods which are implemented as instructions with the appropriate instructions.
7551// This is a copying pass meaning that the code from source code buffer will be copied over to the destination code buffer
7552// after modification.
7553//
7554// @param context - the current execution context.
7555// @param srcStart - pointer to the start of a source code buffer.
7556// @param srcEnd - pointer to the end of a source code buffer.
7557// @param argumentsOffset - stack offset of the argument space.
7558// @param codeOffsetBuffer - pointer to code offset buffer to which mappings from old code offsets to new ones will be stored.
7559// @param dst - pointer to destination code buffer.
7560//
7561// @return pointer to the end of the destination code buffer.
7562//
7563static Code* optimizeNatives(Context* const context,
7564 const Code* const srcStart,
7565 const Code* const srcEnd,
7566 const Uint32 argumentsOffset,
7567 Uint16* const codeOffsetBuffer,
7568 Code* dst) {
7569
7570 const Lib* const lib = context->lib;
7571 const Uint32 builtinsSearchRangeMin = lib == NULL ? 0 : lib->builtinsSearchRangeMin;
7572 const Uint32 builtinsSearchRangeMax = lib == NULL ? 0 : lib->builtinsSearchRangeMax;
7573
7574 const Method* const methods = context->data->methods;
7575 const MethodState* const* const methodStates = (const MethodState* const*) context->methodStates;
7576
7577 // Pointer to the current slot in argument write buffer.
7578 // Used to store all of the indexes in dst that perform the writes to argument space.
7579 Uint32* argumentWriteBuffer = ARGUMENT_WRITE_BUFFER;
7580 Uint32* argumentWrites = argumentWriteBuffer;
7581
7582 Code* const dstStart = dst;
7583
7584 const Code* const iterStart = srcStart;
7585 const Code* const iterN = srcEnd;
7586 const Code* iter = iterStart;
7587
7588 while(iter != iterN) {
7589 const Instruction* const instruction = reflectInstruction(*iter);
7590 const Uint32 instructionLength = instruction->length;
7591
7592 codeOffsetBuffer[iter - iterStart] = (Uint32)(dst - dstStart);
7593
7594 if(isOptimizableInvoke(instruction)) {
7595 const Uint32 srcOffset = iter[INVOCATION_INSTRUCTION_SOURCE_OFFSET_OPERAND + 1];
7596 const Uint32 methodIndex = iter[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1];
7597 const Uint32 location = iter[instruction->length - 1];
7598
7599 const MethodState* const methodState = methodStates[methodIndex];
7600 assert(methodState != NULL);
7601
7602 // Handle lib calls.
7603 // Note that for all of the library calls the argument write buffer is reset.
7604 if(lib != NULL) {
7605 if(methodIndex >= builtinsSearchRangeMin && methodIndex <= builtinsSearchRangeMax) {
7606 const Method* const method = &methods[methodIndex];
7607 const Uint32 builtinIndex = methodIndex - builtinsSearchRangeMin;
7608 const Instruction* const builtinInstruction = reflectInstruction(FIRST_BUILTIN_OPCODE + builtinIndex);
7609
7610 assert(builtinInstruction->category == $INSTRUCTION_CATEGORY_LIB);
7611 assert(method->parameterCount <= 3);
7612
7613 iter += instructionLength;
7614
7615 *dst++ = builtinInstruction->opcode;
7616
7617 switch(method->parameterCount) {
7618 case 1:
7619 {
7620 Uint32 arg1;
7621 argumentWrites = readLibCallArgs1(argumentWriteBuffer, argumentWrites, dstStart, &arg1);
7622 *dst++ = arg1;
7623 }
7624 break;
7625
7626 case 2:
7627 {
7628 Uint32 arg1;
7629 Uint32 arg2;
7630
7631 argumentWrites = readLibCallArgs2(method, argumentWriteBuffer, argumentWrites, argumentsOffset,
7632 dstStart, &arg1, &arg2);
7633
7634 *dst++ = arg1;
7635 *dst++ = arg2;
7636 }
7637 break;
7638
7639 case 3:
7640 {
7641 Uint32 arg1;
7642 Uint32 arg2;
7643 Uint32 arg3;
7644
7645 argumentWrites = readLibCallArgs3(method, argumentWriteBuffer, argumentWrites, argumentsOffset,
7646 dstStart, &arg1, &arg2, &arg3);
7647
7648 *dst++ = arg1;
7649 *dst++ = arg2;
7650 *dst++ = arg3;
7651 }
7652 break;
7653
7654 default: break;
7655 }
7656
7657 if(method->returnTypeClassIndex == 0 && method->returnType == $COOKEE_TYPE_OBJECT) {
7658 if(builtinInstruction->canCausePanic) {
7659 *dst++ = location;
7660 }
7661
7662 dst = handleSetterMove(&iter, iterN, srcOffset, argumentsOffset, dst);
7663 }
7664 else {
7665 const Uint32 dstOffset = reducedDstOffset(&iter, iterN, argumentsOffset);
7666 *dst++ = dstOffset;
7667
7668 if(builtinInstruction->canCausePanic) {
7669 *dst++ = location;
7670 }
7671 }
7672
7673 continue;
7674 }
7675 }
7676
7677 // If we got to this point it means it wasn't a library call.
7678 // Next try to replace a natively implemented method with a native invocation instruction.
7679 if(methodState->codeSize == 1) {
7680 const Instruction* const firstInstruction = reflectInstruction(methodState->code[0]);
7681
7682 if(firstInstruction->category == $INSTRUCTION_CATEGORY_NATIVE) {
7683 // Upon invoke the argument write buffer needs to be reset so that it would not overflow.
7684 argumentWrites = argumentWriteBuffer;
7685
7686 const Opcode opcode = firstInstruction->opcode;
7687
7688 // Sequences needs some special handling.
7689 if(isNativeInstructionSequential(firstInstruction)) {
7690 const Uint32 sd = iter[indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_SEQUENCE_DATA) + 1];
7691 iter += instructionLength;
7692
7693 const Uint32 dstOffset = reducedDstOffset(&iter, iterN, argumentsOffset);
7694 dst = writeInvokeNativeSeq(dst, srcOffset, methodIndex, sd, dstOffset, location);
7695 }
7696 else {
7697 iter += instructionLength;
7698
7699 const Uint32 dstOffset = reducedDstOffset(&iter, iterN, argumentsOffset);
7700 dst = writeInvokeNative(dst, $OPCODE_INVOKE_INATIVE + (opcode - $OPCODE_INATIVE), srcOffset,
7701 methodIndex, dstOffset, location);
7702 }
7703
7704 continue;
7705 }
7706 }
7707 }
7708
7709 // Upon invoke the argument write buffer needs to be reset so that it would not overflow.
7710 if(instruction->category == $INSTRUCTION_CATEGORY_INVOKE) {
7711 argumentWrites = argumentWriteBuffer;
7712 }
7713
7714 memcpy(dst, iter, instructionLength * sizeof(Code));
7715
7716 // Collect all instruction indexes of argument writes.
7717 const InstructionOperand* const operands = instruction->operands;
7718
7719 for(Uint32 i = 1; i < instructionLength; i += 1) {
7720 const InstructionOperand operand = operands[i - 1];
7721
7722 switch(operand) {
7723 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
7724 {
7725 if(dst[i] >= argumentsOffset) {
7726 *argumentWrites++ = (Uint32)(dst - dstStart);
7727 }
7728 }
7729 break;
7730
7731 default: break;
7732 }
7733 }
7734
7735 dst += instructionLength;
7736 iter += instructionLength;
7737 }
7738
7739 return dst;
7740}
7741
7742//////////////////////////////////////
7743// METHOD INLINING OPTIMIZATION
7744//////////////////////////////////////
7745
7746// Contains the data filled out by inline analysis.
7747typedef struct InlineAnalysis InlineAnalysis;
7748struct InlineAnalysis {
7749
7750 // The peak size of arguments in bytes.
7751 Uint32 peakArgumentsSize;
7752
7753 // The number of inline frames after the inlining will be performed.
7754 Uint32 inlineFrameCount;
7755
7756 // The number of reference locals after inlining will be performed.
7757 Uint32 refLocals;
7758
7759 // The number of x64 locals after inlining will be performed.
7760 Uint32 x64Locals;
7761
7762 // The number of x32 locals after inlining will be performed.
7763 Uint32 x32Locals;
7764
7765};
7766
7767// Check if a method is inlinable.
7768//
7769// @param methodState - the state of the method which should be checked if inlinable.
7770// @return true if the method is inlinable, false otherwise.
7771//
7772static inline Bool isMethodInlinable(const MethodState* const methodState) {
7773 return !methodState->traversing && methodState->codeSize < MAX_LEVEL_1_INLINE_METHOD_LENGTH && !methodState->crumbled;
7774}
7775
7776// Analyze the number of locals and inline frames and peak argument size after inlining would be performed.
7777//
7778// @param context - the current execution context.
7779// @param srcStart - pointer to the start of the source code buffer.
7780// @param srcEnd - pointer to the end of the soruce code buffer.
7781// @param analysis - pointer to the instance where to store the results of the analysis.
7782//
7783static Void analyzeInlines(Context* const context,
7784 const Code* const srcStart,
7785 const Code* const srcEnd,
7786 InlineAnalysis* const analysis) {
7787
7788 const MethodState* const* const methodStates = (const MethodState* const*) context->methodStates;
7789
7790 Uint32 refLocals = 0;
7791 Uint32 x64Locals = 0;
7792 Uint32 x32Locals = 0;
7793
7794 Uint32 peakArgumentsSize = 0;
7795 Uint32 inlineFrameCount = 0;
7796
7797 const Code* iter = srcStart;
7798 const Code* const iterN = srcEnd;
7799
7800 while(iter != iterN) {
7801 const Instruction* const instruction = reflectInstruction(*iter);
7802
7803 if(isOptimizableInvoke(instruction)) {
7804 const MethodState* const methodState = methodStates[iter[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1]];
7805 assert(methodState != NULL);
7806
7807 if(isMethodInlinable(methodState)) {
7808 const Uint32 methodPeakArgumentsSize = methodState->peakArgumentsSize;
7809
7810 if(methodPeakArgumentsSize > peakArgumentsSize) {
7811 peakArgumentsSize = methodPeakArgumentsSize;
7812 }
7813
7814 refLocals += methodState->refVariables;
7815 x64Locals += methodState->x64Variables;
7816 x32Locals += methodState->x32Variables;
7817
7818 // The inline frames inside the called method + the method itself.
7819 inlineFrameCount += methodState->inlineFrameCount + 1;
7820 }
7821 }
7822
7823 iter += instruction->length;
7824 }
7825
7826 analysis->peakArgumentsSize = peakArgumentsSize;
7827 analysis->inlineFrameCount = inlineFrameCount;
7828 analysis->refLocals = refLocals;
7829 analysis->x64Locals = x64Locals;
7830 analysis->x32Locals = x32Locals;
7831}
7832
7833// Translate an inlined stack offset to local space.
7834//
7835// @param offset - the offset to translate.
7836// @param sourceOffset - the offset of the source object(a.k.a. this reference) on which the inline method was invoked.
7837// @param inlineParamTranslation - the translation in bytes of all parameter offsets within the inlined method.
7838// @param inlinedStackTranslation - the translation in bytes of all stack offsets within the inlined method.
7839// @param inlineArgumentOffset - the translation in bytes of all argument offsets within the inlined method.
7840// @param argumentsOffset - stack offset of the argument space of current method.
7841//
7842// @return the translated stack offset.
7843//
7844static inline Uint32 translateInlinedOffset(const Uint32 offset,
7845 const Uint32 sourceOffset,
7846 const Uint32 inlineParamTranslation,
7847 const Uint32 inlineStackTranslation,
7848 const Uint32 inlineArgumentsOffset,
7849 const Uint32 argumentsOffset) {
7850
7851 if(offset == 0) {
7852 return sourceOffset;
7853 }
7854 else if(offset >= inlineArgumentsOffset) {
7855 return argumentsOffset + (offset - inlineArgumentsOffset);
7856 }
7857 else {
7858 return (offset - inlineParamTranslation) + inlineStackTranslation;
7859 }
7860}
7861
7862// Inlines all code of invocations within the method which can be inlined.
7863// This is a copying pass meaning that the code from source code buffer will be copied over to the destination code buffer
7864// after modification.
7865//
7866// @param context - pointer to the current execution context.
7867// @param methodState - the state of the method in which code will get inlined.
7868// @param srcStart - pointer to the start of the source code buffer.
7869// @param srcEnd - pointer to the end of the source code buffer.
7870// @param codeOffsetBuffer - pointer to code offset buffer to which mappings from old code offsets to new ones will be stored.
7871// @param startStackTranslation - the initial amount in bytes which all inlined stack offsets of the first method should be
7872// translated by.
7873// @param startCodeOffsetTranslation - the initial amount in which all inlined code offsets of the first method should be
7874// translated by.
7875// @param inlineFrames - pointer to an array of inlineFrames to which all inline frames of inlined methods will be written.
7876// @param argumentsOffset - stack offset of the argument space of the method.
7877// @param dst - pointer to the destination code buffer.
7878//
7879// @return pointer to the end of the destination code buffer.
7880//
7881static Code* inlineMethods(Context* const context,
7882 const MethodState* const methodState,
7883 const Code* const srcStart,
7884 const Code* const srcEnd,
7885 Uint16* const codeOffsetBuffer,
7886 const Uint32 startStackTranslation,
7887 const Uint32 startCodeOffsetTranslation,
7888 InlineFrame* const inlineFrames,
7889 const Uint32 argumentsOffset,
7890 Code* dst) {
7891
7892 const Method* const methods = context->data->methods;
7893 const MethodState* const* const methodStates = (const MethodState* const*) context->methodStates;
7894
7895 Code* const dstStart = dst;
7896
7897 // Pointer to the current slot in argument write buffer.
7898 // Used to store all of the indexes in dst that perform the writes to argument space.
7899 Uint32* argumentWriteBuffer = ARGUMENT_WRITE_BUFFER;
7900 Uint32* argumentWrites = argumentWriteBuffer;
7901
7902 // Holds the number by which all variables in inlined method code needs to be translated.
7903 Uint32 inlinedStackTranslation = startStackTranslation;
7904
7905 // Holds the number by which all jumps in inlined method code needs to be translated.
7906 Uint32 inlinedCodeOffsetTranslation = startCodeOffsetTranslation;
7907
7908 // Holds the pointer to the current inline frame which needs to be filled out.
7909 InlineFrame* inlineFramesPtr = inlineFrames;
7910
7911 const Code* const iterStart = srcStart;
7912 const Code* const iterN = srcEnd;
7913 const Code* iter = iterStart;
7914
7915 while(iter != iterN) {
7916 const Instruction* const instruction = reflectInstruction(*iter);
7917 const Uint32 instructionLength = instruction->length;
7918 const Uint32 iterCodeOffset = (Uint32)(iter - iterStart);
7919
7920 codeOffsetBuffer[iterCodeOffset] = (Uint16)(dst - dstStart);
7921
7922 if(isOptimizableInvoke(instruction)) {
7923 const Uint32 sourceOffset = iter[INVOCATION_INSTRUCTION_SOURCE_OFFSET_OPERAND + 1];
7924 const Uint32 methodIndex = iter[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1];
7925 const Uint32 location = iter[instruction->length - 1];
7926
7927 const MethodState* const inlinedMethodState = methodStates[methodIndex];
7928 assert(inlinedMethodState != NULL);
7929
7930 if(isMethodInlinable(inlinedMethodState)) {
7931 PRINT_DEBUG_OPTS("Inlined call to %s\n", context->data->methods[methodIndex].signature);
7932
7933 // The itertor is moved immediately since we don't need it anymore but we need the next instruction.
7934 iter += instructionLength;
7935
7936 const Method* const inlinedMethodData = &methods[methodIndex];
7937 const Uint32 inlineParamTranslation = inlinedMethodData->parameterStackSize -
7938 (inlinedMethodData->refParametersCount * sizeof(CookeeObject) +
7939 inlinedMethodData->x64ParametersCount * sizeof(CookeeDouble) +
7940 inlinedMethodData->x32ParametersCount * sizeof(CookeeInt));
7941
7942 // Make all buffered argument writes point to local space instead of argument space.
7943 {
7944 Uint32* const argumentWritesN = argumentWrites - inlinedMethodData->parameterCount;
7945 assert(argumentWrites - argumentWriteBuffer >= inlinedMethodData->parameterCount);
7946
7947 while(argumentWrites != argumentWritesN) {
7948 argumentWrites -= 1;
7949
7950 const Uint32 argumentOffset = (dstStart[*argumentWrites] - argumentsOffset);
7951 dstStart[*argumentWrites] = inlinedStackTranslation + (argumentOffset - inlineParamTranslation);
7952 }
7953
7954 // The argument write buffer needs to be reset to that it would not overflow.
7955 argumentWrites = argumentWriteBuffer;
7956 }
7957
7958 const Uint32 inlinedCodeLocationCodeOffset = (Uint32)(dst - dstStart);
7959
7960 // If the source is not this reference the source still must be checked for null.
7961 // Else just insert a placeholder so that it would be possible to know the location which invoked the method.
7962 if(sourceOffset != 0) {
7963 dst = writeChknullInlineInvokeInstruction(dst, sourceOffset, location);
7964 }
7965 else {
7966 dst = writeInlineInvokeInstruction(dst, location);
7967 }
7968
7969 const Uint32 inlinedCodeStartOffset = (Uint32)(dst - dstStart);
7970
7971 // Setup inline frame. The length is filled out after the method is actually inlined.
7972 InlineFrame* const inlinedFrame = inlineFramesPtr++;
7973 {
7974 inlinedFrame->inlineInstructionOffset = inlinedCodeLocationCodeOffset;
7975 inlinedFrame->offset = inlinedCodeStartOffset;
7976 inlinedFrame->method = inlinedMethodData;
7977
7978 // If this is sequential invoke the sequence information must be included in the inlined frame too.
7979 if(isInvocationInstructionSequential(instruction)) {
7980 const Int32 sequenceDataIndex = indexOfInstructionOperand(instruction,
7981 $INSTRUCTION_OPERAND_SEQUENCE_DATA);
7982
7983 assert(sequenceDataIndex != -1);
7984
7985 const Uint32 sequenceData = iter[sequenceDataIndex + 1];
7986 inlinedFrame->sequenceIndex = instructionSequenceDataIndex(sequenceData);
7987 inlinedFrame->sequenceLength = instructionSequenceDataLength(sequenceData);
7988 }
7989 }
7990
7991 // Copy all of the inline frames of the inlined method.
7992 for(Uint32 i = 0; i < inlinedMethodState->inlineFrameCount; i += 1) {
7993 *inlineFramesPtr = inlinedMethodState->inlineFrames[i];
7994 inlineFramesPtr += 1;
7995 }
7996
7997 // The argument space offset of the inlined method.
7998 const Uint32 inlineArgumentsOffset = inlinedMethodState->nextFrameOffset;
7999
8000 // Offset pointing to the end of the inlined method code within the parent method.
8001 // At this point is incorrect because some code might change within the inlined method.
8002 // This offset will get relocated in relocate function.
8003 const Uint32 inlineReturnJumpOffset = inlinedCodeOffsetTranslation + inlinedMethodState->codeSize;
8004
8005 // Ok so finally start the inlining also changing some things along the way.
8006 const Code* const inlineIterStart = inlinedMethodState->code;
8007 const Code* const inlineIterN = inlineIterStart + inlinedMethodState->codeSize;
8008 const Code* inlineIter = inlineIterStart;
8009
8010 assert(inlinedMethodState->codeSize > 0);
8011
8012 const Bool needsReturnMove = iter != iterN && isMoveFromReturn(iter, argumentsOffset);
8013 Uint32 returnDstOffset;
8014
8015 if(needsReturnMove) {
8016 returnDstOffset = iter[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
8017
8018 // Skip the move in iter since we will write directly to it.
8019 iter += reflectInstruction(*iter)->length;
8020 }
8021 else {
8022 returnDstOffset = 0;
8023 }
8024
8025 while(inlineIter != inlineIterN) {
8026 const Instruction* const inlinedInstruction = reflectInstruction(*inlineIter);
8027 const Uint32 inlineInstructionLength = inlinedInstruction->length;
8028 const Uint32 inlinedCodeOffset = (Uint32)(inlineIter - inlineIterStart);
8029
8030 assert(inlinedInstruction->category != $INSTRUCTION_CATEGORY_NATIVE);
8031
8032 codeOffsetBuffer[inlinedCodeOffsetTranslation + inlinedCodeOffset] = (Uint16)(dst - dstStart);
8033
8034 // Returns must be replaced with simple moves + optionally a goto to the end of inlined code.
8035 if(inlinedInstruction->category == $INSTRUCTION_CATEGORY_RETURN) {
8036 const Opcode opcode = inlinedInstruction->opcode;
8037
8038 // The move only needs to be added if it's readed afterwards in the parent frame.
8039 if(needsReturnMove) {
8040 Opcode moveOpcode;
8041 Uint32 srcOffset;
8042
8043 // 'this' returns can directly refer to the source of the inlined method call.
8044 if(opcode == $OPCODE_RETURN) {
8045 moveOpcode = $OPCODE_OMOVE;
8046 srcOffset = sourceOffset;
8047 }
8048 else {
8049 moveOpcode = $OPCODE_IMOVE + (opcode - $OPCODE_IRETURN);
8050 srcOffset = inlineIter[RETURN_INSTRUCTION_SOURCE_OFFSET_OPERAND + 1];
8051 srcOffset = translateInlinedOffset(srcOffset, sourceOffset, inlineParamTranslation,
8052 inlinedStackTranslation, inlineArgumentsOffset,
8053 argumentsOffset);
8054 }
8055
8056 if(srcOffset != returnDstOffset) {
8057 dst = writeMove(dst, moveOpcode, srcOffset, returnDstOffset);
8058 }
8059 }
8060
8061 // If this is not the last instruction of the inlined method code then
8062 // add a goto to jump to the end of the inlined method.
8063 if(inlineIter + inlineInstructionLength != inlineIterN) {
8064 dst = writeGoto(dst, inlineReturnJumpOffset);
8065 }
8066 }
8067 else {
8068 // First copy the data.
8069 memcpy(dst, inlineIter, inlineInstructionLength * sizeof(Code));
8070
8071 // For the inlined instruction it is needed to translate the jump and stack offsets.
8072 // The iteration starts from 1 because the first operand one is the opcode.
8073 const InstructionOperand* const inlineOperands = inlinedInstruction->operands;
8074
8075 for(Uint32 i = 1; i < inlineInstructionLength; i += 1) {
8076 const InstructionOperand operand = inlineOperands[i - 1];
8077
8078 switch(operand) {
8079 case $INSTRUCTION_OPERAND_CODE_OFFSET:
8080 dst[i] += inlinedCodeOffsetTranslation;
8081 break;
8082
8083 case INSTRUCTION_OPERAND_STACK_OFFSET:
8084 dst[i] = translateInlinedOffset(dst[i], sourceOffset, inlineParamTranslation,
8085 inlinedStackTranslation, inlineArgumentsOffset,
8086 argumentsOffset);
8087 break;
8088
8089 default:
8090 break;
8091 }
8092 }
8093
8094 dst += inlineInstructionLength;
8095 }
8096
8097 inlineIter += inlineInstructionLength;
8098 }
8099
8100 const Uint32 inlinedCodeEndOffset = (Uint32)(dst - dstStart);
8101
8102 // Another offset has to be writter which would map the gotos generated instead of returns to the code
8103 // after the inlined method's code.
8104 codeOffsetBuffer[inlinedCodeOffsetTranslation + inlinedMethodState->codeSize] = inlinedCodeEndOffset;
8105
8106 // Now after the method was inlined we know the length of the code and can finally fill out the length of
8107 // the inlined frame.
8108 inlinedFrame->length = inlinedCodeEndOffset - inlinedCodeStartOffset;
8109
8110 // Since all returns could invalidate inline frame offsets and lengths of the inlined frame they have to be
8111 // adjusted. It can be done using the code offset buffer.
8112 {
8113 InlineFrame* iter = inlineFramesPtr - inlinedMethodState->inlineFrameCount;
8114 InlineFrame* const iterN = inlineFramesPtr;
8115
8116 while(iter != iterN) {
8117 const Uint32 offset = iter->offset;
8118 const Uint32 length = iter->length;
8119
8120 iter->inlineInstructionOffset = codeOffsetBuffer[inlinedCodeOffsetTranslation +
8121 iter->inlineInstructionOffset];
8122
8123 iter->offset = codeOffsetBuffer[inlinedCodeOffsetTranslation + offset];
8124 iter->length = codeOffsetBuffer[inlinedCodeOffsetTranslation + offset + length] - iter->offset;
8125
8126 iter += 1;
8127 }
8128 }
8129
8130 // Translate the stack and code offset translations so that the next inlined method would not overlap.
8131 inlinedCodeOffsetTranslation += inlinedMethodState->codeSize + 1; // +1 because of return jump.
8132 inlinedStackTranslation += inlinedMethodState->refVariables * sizeof(CookeeObject) +
8133 inlinedMethodState->x64Variables * sizeof(CookeeDouble) +
8134 inlinedMethodState->x32Variables * sizeof(CookeeInt);
8135
8136 continue;
8137 }
8138 }
8139
8140 // Upon invoke the argument write buffer needs to be reset so that it would not overflow.
8141 if(instruction->category == $INSTRUCTION_CATEGORY_INVOKE) {
8142 argumentWrites = argumentWriteBuffer;
8143 }
8144
8145 memcpy(dst, iter, instructionLength * sizeof(Code));
8146
8147 // Collect all indexes of dst argument writes.
8148 const InstructionOperand* const operands = instruction->operands;
8149
8150 for(Uint32 i = 1; i < instructionLength; i += 1) {
8151 const InstructionOperand operand = operands[i - 1];
8152
8153 switch(operand) {
8154 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8155 {
8156 if(dst[i] >= argumentsOffset) {
8157 *argumentWrites++ = (Uint32)((dst + i) - dstStart);
8158 }
8159 }
8160 break;
8161
8162 default: break;
8163 }
8164 }
8165
8166 dst += instructionLength;
8167 iter += instructionLength;
8168 }
8169
8170 return dst;
8171}
8172
8173//////////////////////////////////////
8174// LOCAL OPTIMIZATIONS
8175//////////////////////////////////////
8176
8177// Optimizer utility methods.
8178
8179static const Code* lastInstructionInRange(const Code* iter, const Code* const iterN) {
8180 const Code* lastInstruction = NULL;
8181
8182 while(iter != iterN) {
8183 lastInstruction = iter;
8184 iter += reflectInstruction(*iter)->length;
8185 }
8186
8187 return lastInstruction;
8188}
8189
8190static Void mapBlocksRecursive(const Code* const iterStart,
8191 const Code* const iterN,
8192 const Code* iter,
8193 Uint32* const blockOffsetBuffer,
8194 const Uint32 blockOffset) {
8195
8196 while(iter != iterN) {
8197 const Instruction* const instruction = reflectInstruction(*iter);
8198 const Uint32 instructionLength = instruction->length;
8199 const Uint32 iterCodeOffset = (Uint32)(iter - iterStart);
8200
8201 // In case the instruction would get replaced with smaller instruction every instruction operand has to be mapped.
8202 for(Uint32 i = 0; i < instructionLength; i += 1) {
8203 blockOffsetBuffer[iterCodeOffset + i] = blockOffset;
8204 }
8205
8206 const Uint32 jumpOperandIndex = indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_CODE_OFFSET);
8207 if(jumpOperandIndex != -1 && isInstructionJumpingToCodeOffset(instruction)) {
8208 const Uint32 jumpOffset = iter[jumpOperandIndex + 1];
8209
8210 if(jumpOffset > iterCodeOffset && isJumpInstructionConditional(instruction)) {
8211 const Code* const topBranchEnd = iterStart + jumpOffset;
8212 const Code* const nextInstruction = iter + instructionLength;
8213
8214 // Map out top branch block.
8215 assert(nextInstruction <= topBranchEnd);
8216 mapBlocksRecursive(iterStart, topBranchEnd, nextInstruction, blockOffsetBuffer, iterCodeOffset);
8217
8218 iter = topBranchEnd;
8219
8220 // If there's a bottom branch then map it as well.
8221 const Code* const lastInstruction = lastInstructionInRange(nextInstruction, topBranchEnd);
8222 if(lastInstruction != NULL && *lastInstruction == $OPCODE_GOTO) {
8223 assert(reflectInstruction($OPCODE_GOTO)->operands[0] == $INSTRUCTION_OPERAND_CODE_OFFSET);
8224 const Code* const bottomBranchEnd = iterStart + lastInstruction[1];
8225
8226 assert(iter <= bottomBranchEnd);
8227 mapBlocksRecursive(iterStart, bottomBranchEnd, iter, blockOffsetBuffer, (Uint32)(topBranchEnd - iterStart));
8228 iter = bottomBranchEnd;
8229 }
8230
8231 assert(iter <= iterN);
8232 continue;
8233 }
8234 }
8235
8236 iter += instructionLength;
8237 }
8238}
8239
8240static Void mapBlocks(const Code* const srcStart, const Code* const srcEnd, Uint32* const blockOffsetBuffer) {
8241 mapBlocksRecursive(srcStart, srcEnd, srcStart, blockOffsetBuffer, 0);
8242}
8243
8244// Quick peephole optimizations(add stack values):
8245// 1) mul a a -> sq a
8246// 2) is a a -> true
8247// 3) isnt a a -> false
8248// 4) add a a -> dbl a
8249// 5) sub a a -> 0
8250// 7) goto/if/not +1 instr -> noop
8251// 8) div a a -> 1
8252// 9) move a a -> noop
8253// 10) move a b; move b a -> noop
8254// 11) gotoif true -> noop
8255// 12) gotoifnot false -> noop
8256// 13) gotoifnot true -> noop (WHOLE BLOCK ?)
8257// 14) mul num num -> num * num
8258// 15) div num num -> num / num or panic
8259// 16) add num num -> num + num
8260// 17) sub num num -> num - num
8261// 18) gt/lt/lte/gte num num -> num </<=/>/>= num
8262// 19) gotoif/not + 2 instr; goto + 1 instr -> noop
8263// 20) setfield a offset val; getfield a offset val; -> setfield a offset val; move val
8264// 21) add a num -> add a $num
8265// 22) add num a -> add a $num
8266// 22) sub a num -> sub a $num
8267// 23) sub num a -> sub a -$num
8268// 24) chknull_inline_invoke NONNULL -> inline_invoke
8269// 25) chktype null -> noop
8270
8271// Other:
8272// Code that processes to some state and then back without using the processed state.
8273// AND/OR/IFS which were checked earlier.
8274// REMOVE CODE BETWEEN GOTO AND IT'S TARGET IF NOONE JUMPS IN BETWEEN
8275
8276// Value caching(basic for now):
8277// Calculate used numbers/texts/other constants preload at start if meets threashold or used within a loop
8278
8279static Bool isOffsetReadInRange(const Code* iter,
8280 const Code* const iterN,
8281 const Uint32 offset,
8282 const Uint32 argumentsOffset) {
8283
8284 while(iter != iterN) {
8285 const Instruction* const instruction = reflectInstruction(*iter);
8286 const Uint32 instructionLength = instruction->length;
8287
8288 if(offset >= argumentsOffset) {
8289 if(instruction->canCauseFrame) {
8290 return true;
8291 }
8292 }
8293
8294 const InstructionOperand* const operands = instruction->operands;
8295 for(Uint32 i = 1; i < instructionLength; i += 1) {
8296 switch(operands[i - 1]) {
8297
8298 case INSTRUCTION_OPERAND_SRC_STACK_OFFSET:
8299 if(iter[i] == offset) {
8300 return true;
8301 }
8302 break;
8303
8304 default: break;
8305 }
8306 }
8307
8308 iter += instructionLength;
8309 }
8310
8311 return false;
8312}
8313
8314static Bool isOffsetWrittenInRange(const Code* const iterStart,
8315 const Code* const iterN,
8316 const Code* iter,
8317 const Uint32 offset) {
8318
8319 const Uint32 startCodeOffset = (Uint32)(iter - iterStart);
8320
8321 // In case the write analyzed is within a loop, it might be needed to jump to the start of the loop.
8322 // There two variables make sure the iteration from the start of the loop is iterated only to the offset the overall
8323 // iteration started and that the iterator is placed to the location where the iteration halted.
8324 const Code* loopSeek = NULL;
8325 const Code* continueAfterLoopSeek = NULL;
8326
8327 while(iter != iterN) {
8328 const Instruction* const instruction = reflectInstruction(*iter);
8329 const Uint32 instructionLength = instruction->length;
8330
8331 // If the iteration needs to jump to the start of the loop or to a location of a goto instruction, the pointer to
8332 // that code location is first store here so that the operand iteration could be finished first before jumping.
8333 const Code* jump = NULL;
8334
8335 const InstructionOperand* const operands = instruction->operands;
8336 for(Uint32 i = 1; i < instructionLength; i += 1) {
8337 switch(operands[i - 1]) {
8338 case $INSTRUCTION_OPERAND_CODE_OFFSET:
8339 if(loopSeek == NULL && isInstructionJumpingToCodeOffset(instruction)) {
8340 const Uint32 jumpOffset = iter[i];
8341
8342 if(jumpOffset < iter - iterStart) {
8343 loopSeek = iterStart + startCodeOffset;
8344 continueAfterLoopSeek = iter + instructionLength;
8345 jump = iterStart + jumpOffset;
8346 }
8347 }
8348 break;
8349
8350 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8351 if(iter[i] == offset) {
8352 return true;
8353 }
8354 break;
8355
8356 default: break;
8357 }
8358 }
8359
8360 if(jump != NULL) {
8361 iter = jump;
8362 }
8363 else {
8364 iter += instructionLength;
8365 }
8366
8367 // Check if the point of the needed loop location is reached and continue when the iteration previously halted.
8368 if(loopSeek == iter) {
8369 iter = continueAfterLoopSeek;
8370 loopSeek = NULL;
8371 }
8372 }
8373
8374 return false;
8375}
8376
8377
8378static Bool isDstReadedBeforeWrite(const Code* const iterStart,
8379 const Code* const iterN,
8380 const Code* iter,
8381 const Uint32 offset) {
8382
8383 const Uint32 startCodeOffset = (Uint32)(iter - iterStart);
8384
8385 // In case the write analyzed is within a loop, it might be needed to jump to the start of the loop.
8386 // There two variables make sure the iteration from the start of the loop is iterated only to the offset the overall
8387 // iteration started and that the iterator is placed to the location where the iteration halted.
8388 const Code* loopSeek = NULL;
8389 const Code* continueAfterLoopSeek = NULL;
8390
8391 while(iter != iterN) {
8392 const Instruction* const instruction = reflectInstruction(*iter);
8393 const Uint32 instructionLength = instruction->length;
8394 const InstructionOperand* const operands = instruction->operands;
8395
8396 // If the iteration needs to jump to the start of the loop or to a location of a goto instruction, the pointer to
8397 // that code location is first store here so that the operand iteration could be finished first before jumping.
8398 const Code* jump = NULL;
8399
8400 for(Uint32 i = 1; i < instructionLength; i += 1) {
8401 switch(operands[i - 1]) {
8402 case $INSTRUCTION_OPERAND_CODE_OFFSET:
8403 if(loopSeek == NULL && isInstructionJumpingToCodeOffset(instruction)) {
8404 const Uint32 jumpOffset = iter[i];
8405
8406 if(jumpOffset < iter - iterStart) {
8407 loopSeek = iterStart + startCodeOffset;
8408 continueAfterLoopSeek = iter + instructionLength;
8409 jump = iterStart + jumpOffset;
8410 }
8411 }
8412 break;
8413
8414 case INSTRUCTION_OPERAND_SRC_STACK_OFFSET:
8415 if(iter[i] == offset) {
8416 return true;
8417 }
8418 break;
8419
8420 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8421 if(iter[i] == offset) {
8422 return false;
8423 }
8424 break;
8425
8426 default: break;
8427 }
8428 }
8429
8430 if(jump != NULL) {
8431 iter = jump;
8432 }
8433 else {
8434 iter += instructionLength;
8435 }
8436
8437 // Check if the point of the needed loop location is reached and continue when the iteration previously halted.
8438 if(loopSeek == iter) {
8439 iter = continueAfterLoopSeek;
8440 loopSeek = NULL;
8441 }
8442 }
8443
8444 return false;
8445}
8446
8447static Void findSrcWindow(const Code* const iterStart,
8448 const Code* const iterN,
8449 const Code* iter,
8450 const Uint32 argumentsOffset,
8451 const Uint32 offset,
8452 const Bool isObject,
8453 Int32* const writeOffsetOut,
8454 Int32* const readOffsetOut) {
8455
8456 Int32 writeOffset = -1;
8457 Int32 readOffset = -1;
8458
8459 if(offset >= argumentsOffset) {
8460 while(iter != iterN) {
8461 const Instruction* const instruction = reflectInstruction(*iter);
8462 const Uint32 instructionLength = instruction->length;
8463 const InstructionOperand* const operands = instruction->operands;
8464
8465 if(instruction->category == $INSTRUCTION_CATEGORY_INVOKE ||
8466 instruction->opcode == $OPCODE_GLOBAL ||
8467 (isObject && instruction->canCauseGc)) {
8468
8469 writeOffset = (Int32)(iter - iterStart);
8470 break;
8471 }
8472
8473 for(Uint32 i = 1; i < instructionLength; i += 1) {
8474 switch(operands[i - 1]) {
8475 case INSTRUCTION_OPERAND_SRC_STACK_OFFSET:
8476 if(iter[i] == offset) {
8477 readOffset = (Int32)(iter - iterStart);
8478 }
8479 break;
8480
8481 default: break;
8482 }
8483 }
8484
8485 iter += instructionLength;
8486 }
8487 }
8488 else {
8489 while(iter != iterN) {
8490 const Instruction* const instruction = reflectInstruction(*iter);
8491 const Uint32 instructionLength = instruction->length;
8492 const InstructionOperand* const operands = instruction->operands;
8493
8494 for(Uint32 i = 1; i < instructionLength; i += 1) {
8495 switch(operands[i - 1]) {
8496 case INSTRUCTION_OPERAND_SRC_STACK_OFFSET:
8497 if(iter[i] == offset) {
8498 readOffset = (Int32)(iter - iterStart);
8499 }
8500 break;
8501
8502 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8503 if(iter[i] == offset) {
8504 writeOffset = (Int32)(iter - iterStart);
8505 }
8506 break;
8507
8508 default: break;
8509 }
8510 }
8511
8512 if(writeOffset != -1) {
8513 break;
8514 }
8515
8516 iter += instructionLength;
8517 }
8518 }
8519
8520 *writeOffsetOut = writeOffset;
8521 *readOffsetOut = readOffset;
8522}
8523
8524static Void replaceVariableUsage(Code* iter, Code* const iterN, const Uint32 fromOffset, const Uint32 toOffset) {
8525 while(iter != iterN) {
8526 const Instruction* const instruction = reflectInstruction(*iter);
8527 const Uint32 instructionLength = instruction->length;
8528 const InstructionOperand* const operands = instruction->operands;
8529
8530 Bool replaced = false;
8531
8532 for(Uint32 i = 1; i < instructionLength; i += 1) {
8533 switch(operands[i - 1]) {
8534 case INSTRUCTION_OPERAND_STACK_OFFSET:
8535 if(iter[i] == fromOffset) {
8536 iter[i] = toOffset;
8537 replaced = true;
8538 }
8539 break;
8540
8541 default: break;
8542 }
8543 }
8544
8545 if(replaced) {
8546 if(instruction->category == $INSTRUCTION_CATEGORY_MOVE &&
8547 iter[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1] == iter[MOVE_INSTRUCTION_SRC_OFFSET_OPERAND]) {
8548
8549 memset(iter, $OPCODE_NOOP, instructionLength * sizeof(Code));
8550 }
8551 }
8552
8553 iter += instructionLength;
8554 }
8555}
8556
8557typedef struct WriteUsageAnalysis WriteUsageAnalysis;
8558struct WriteUsageAnalysis {
8559
8560 // Indicates if the write should be kept.
8561 Bool keep;
8562
8563 // Indicates if the write's destination should be changed.
8564 Bool changeDestination;
8565
8566 // Indicates if an instruction using the write's destination should be eliminated.
8567 Bool eliminateUsage;
8568
8569 // Indicates that all usage of the write's destination should be changed to some other offset.
8570 Bool changeUsage;
8571
8572 // The stack offset which should be used instead of the current write's destination offset.
8573 Uint32 changeDestinationOffset;
8574
8575 // The code offset of the instruction using this write's destination which should be eliminated.
8576 Uint32 eliminateUsageOffset;
8577
8578 // The stack offset which should be used instead of the write's destination offset.
8579 Uint32 changeUsageOffset;
8580
8581 // The code offset where usage offset change should start happening.
8582 Uint32 changeUsageStartOffset;
8583
8584 // The code offset where usage offset change should end happening.
8585 Uint32 changeUsageEndOffset;
8586
8587};
8588
8589// The analysis checks for four cases:
8590//
8591// 1) Write should be eliminated
8592// Happens when:
8593// 1) no code is using the output to that offset.
8594// 2) output of the write is not used before another write to the offset happens.
8595// 3) the write is a move and it's source is equal to it's destination.
8596//
8597// 2) Write should be eliminated and it's source used instead
8598// Happens when:
8599// 1) the write is a move instruction
8600// 2) if after next write to source the write's destination is not used before another write to the write's destination
8601// 3) if source is not read before another write to write's destination(before next write to source)
8602// Notes:
8603// * if the source is from argument space, any gc triggers, invokes or global instructions should be treated as writes.
8604//
8605// 3) Write should be kept but it's destination should be changed and it's usage instruction eliminated
8606// Happens when:
8607// 1) the write is not a move instruction
8608// 2) there is only one usage of the write's destination as source at all or before another write to the same offset
8609// happens
8610// 3) the instruction using the write's destination is a move instruction
8611// 4) the destination of the move instruction is not used in between
8612// 5) if the move instruction is OMOVE to argument space there aren't any GC triggers in between
8613// 6) The single use is within the same block
8614//
8615// 4) Write should be kept
8616// Happens when:
8617// 1) all three cases above falls short or the write offset is to argument space
8618// 2) the write is not a global instruction with side effects
8619//
8620static Void analyzeWriteUsage(Context* const context,
8621 const Code* const iterStart,
8622 const Code* const iterN,
8623 const Code* analysisIter,
8624 const Code* const writeInstructionCode,
8625 const Uint32 writeOffset,
8626 const Uint32* const blockOffsetBuffer,
8627 const Uint32 argumentsOffset,
8628 WriteUsageAnalysis* const analysis) {
8629
8630
8631 // DONT WRAP YOUR HEAD ABOUT PARTIAL DEAD CODE, FLATTENING WILL TAKE CARE OF A LOT OF CASES
8632 // CURRENT PROBLEM WITH VARIABLE OFFSET SWAP IS THE LOOPS WHEN WINDOW IS GOING TO THE END OF THE METHOD
8633
8634 // Check for case #4.1.
8635 if(writeOffset > argumentsOffset) {
8636 analysis->keep = true;
8637 return;
8638 }
8639
8640 const Instruction* const writeInstruction = reflectInstruction(*writeInstructionCode);
8641
8642 // Check for case #4.2.
8643 if(writeInstruction->opcode == $OPCODE_GLOBAL) {
8644 const Uint32 classIndexOperand = indexOfInstructionOperand(writeInstruction, $INSTRUCTION_OPERAND_CLASS_INDEX);
8645 const Uint32 classIndex = writeInstructionCode[classIndexOperand + 1];
8646
8647 if(context->data->classes[classIndex].initializer != NULL) {
8648 // Scan if there's any side effects within the initializer.
8649 analysis->keep = true;
8650 return;
8651 }
8652 }
8653
8654 const Uint32 writeBlockOffset = blockOffsetBuffer[writeInstructionCode - iterStart];
8655
8656 // Check for case #1 and #3.
8657 {
8658 const Uint32 startOffset = (Uint32)(analysisIter - iterStart);
8659
8660 // Indicates if single use optimization is in question.
8661 Bool optimizeSingleUse = true;//writeInstruction->category != $INSTRUCTION_CATEGORY_MOVE;
8662
8663 // Indicates if a usage of the write offset was found.
8664 Bool usageFound = false;
8665
8666 // Contains a pointer to the instruction which is using the write offset.
8667 const Code* usageInstruction = NULL;
8668
8669 // In case the write analyzed is within a loop, it might be needed to jump to the start of the loop.
8670 // There two variables make sure the iteration from the start of the loop is iterated only to the offset the overall
8671 // iteration started and that the iterator is placed to the location where the iteration halted.
8672 const Code* loopSeek = NULL;
8673 const Code* continueAfterLoopSeek = NULL;
8674
8675 const Code* iter = analysisIter;
8676
8677 while(iter != iterN) {
8678 const Instruction* const instruction = reflectInstruction(*iter);
8679 const Uint32 instructionLength = instruction->length;
8680 const Uint32 iterCodeOffset = (Uint32)(iter - iterStart);
8681
8682 // If a destination write was found the iteration should be finished, but this indication should be first stored
8683 // here so that operand iteration could be finished before exiting the loop.
8684 Bool writeFound = false;
8685
8686 // If the iteration needs to jump to the start of the loop or to a location of a goto instruction, the pointer to
8687 // that code location is first store here so that the operand iteration could be finished first before jumping.
8688 const Code* jump = NULL;
8689
8690 const InstructionOperand* const operands = instruction->operands;
8691 for(Uint32 i = 1; i < instructionLength; i += 1) {
8692 switch(operands[i - 1]) {
8693 case $INSTRUCTION_OPERAND_CODE_OFFSET:
8694 if(loopSeek == NULL && isInstructionJumpingToCodeOffset(instruction)) {
8695 const Uint32 jumpOffset = iter[i];
8696
8697 if(jumpOffset < startOffset) {
8698 loopSeek = iterStart + startOffset;
8699 continueAfterLoopSeek = iter + instructionLength;
8700 jump = iterStart + jumpOffset;
8701 }
8702 }
8703 break;
8704
8705 case INSTRUCTION_OPERAND_SRC_STACK_OFFSET:
8706 if(iter[i] == writeOffset) {
8707 const Bool usageWasFound = usageFound;
8708 usageFound = true;
8709
8710 if(usageWasFound || instruction->category != $INSTRUCTION_CATEGORY_MOVE) {
8711 optimizeSingleUse = false;
8712 goto exitSingleUseAnalysis;
8713 }
8714
8715 usageInstruction = iter;
8716 }
8717 break;
8718
8719 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8720 if(iter[i] == writeOffset) {
8721 const Uint32 overwriteBlock = blockOffsetBuffer[iterCodeOffset];
8722
8723 if(overwriteBlock > writeBlockOffset) {
8724 usageFound = true;
8725 optimizeSingleUse = false;
8726 goto exitSingleUseAnalysis;
8727 }
8728 else {
8729 optimizeSingleUse = overwriteBlock == writeBlockOffset;
8730 writeFound = true;
8731 }
8732 }
8733 break;
8734
8735 default: break;
8736 }
8737 }
8738
8739 if(writeFound) {
8740 break;
8741 }
8742
8743 if(jump != NULL) {
8744 iter = jump;
8745 }
8746 else {
8747 iter += instructionLength;
8748 }
8749
8750 // Check if the point of the needed loop location is reached and continue when the iteration previously halted.
8751 if(loopSeek == iter) {
8752 iter = continueAfterLoopSeek;
8753 loopSeek = NULL;
8754 }
8755 }
8756 exitSingleUseAnalysis:;
8757
8758 if(usageFound) {
8759 if(optimizeSingleUse && blockOffsetBuffer[usageInstruction - iterStart] == writeBlockOffset) {
8760 const Uint32 newDst = usageInstruction[MOVE_INSTRUCTION_DST_OFFSET_OPERAND + 1];
8761
8762 // Check for case #3.5
8763 if(*usageInstruction == $OPCODE_OMOVE && newDst >= argumentsOffset) {
8764 const Code* subIter = iterStart + startOffset;
8765 while(subIter != iterN) {
8766 const Instruction* const checkedInstruction = reflectInstruction(*subIter);
8767 const Uint32 checkedInstructionLength = checkedInstruction->length;
8768
8769 if(checkedInstruction->category == $INSTRUCTION_CATEGORY_INVOKE) {
8770 break;
8771 }
8772 else if(checkedInstruction->canCauseGc) {
8773 optimizeSingleUse = false;
8774 break;
8775 }
8776
8777 subIter += checkedInstructionLength;
8778 }
8779 }
8780
8781 // Check for case #3.4
8782 if(optimizeSingleUse) {
8783 const Code* const checkStart = iterStart + startOffset;
8784 optimizeSingleUse = !isOffsetReadInRange(checkStart, usageInstruction, newDst, argumentsOffset);
8785 }
8786
8787 if(optimizeSingleUse) {
8788 analysis->keep = true;
8789 analysis->changeDestination = true;
8790 analysis->changeDestinationOffset = newDst;
8791 analysis->eliminateUsage = true;
8792 analysis->eliminateUsageOffset = (Uint32)(usageInstruction - iterStart);
8793 return;
8794 }
8795 }
8796 }
8797 else {
8798 analysis->keep = false;
8799 return;
8800 }
8801 }
8802
8803 if(writeInstruction->category == $INSTRUCTION_CATEGORY_MOVE) {
8804 const Uint32 srcOffset = writeInstructionCode[MOVE_INSTRUCTION_SRC_OFFSET_OPERAND + 1];
8805 Int32 srcNextWriteOffset;
8806 Int32 srcLastReadInWindow;
8807
8808 findSrcWindow(iterStart, iterN, analysisIter, argumentsOffset, srcOffset, writeInstruction->opcode == $OPCODE_OMOVE,
8809 &srcNextWriteOffset, &srcLastReadInWindow);
8810
8811 Bool dstReadedAfterSrcWindow;
8812
8813 if(srcNextWriteOffset != -1) {
8814 dstReadedAfterSrcWindow = isDstReadedBeforeWrite(iterStart, iterN, iterStart + srcNextWriteOffset, writeOffset);
8815 }
8816 else {
8817 dstReadedAfterSrcWindow = false;
8818 }
8819
8820 Bool replacable = true;
8821
8822 // Check window validity.
8823 if(replacable && srcLastReadInWindow != -1) {
8824 replacable = writeBlockOffset <= blockOffsetBuffer[srcLastReadInWindow];
8825 }
8826 else {
8827 replacable = writeBlockOffset == 0;
8828 }
8829
8830 if(replacable && srcNextWriteOffset != -1) {
8831 replacable = writeBlockOffset <= blockOffsetBuffer[srcNextWriteOffset];
8832 }
8833 else {
8834 replacable = writeBlockOffset == 0;
8835 }
8836
8837 if(replacable && !dstReadedAfterSrcWindow) {
8838 if(!isOffsetWrittenInRange(iterStart, (srcNextWriteOffset == -1 ? iterN : iterStart + srcNextWriteOffset),
8839 analysisIter, writeOffset)) {
8840
8841 replacable = true;
8842 }
8843 else {
8844 replacable = false;
8845 }
8846 }
8847 else {
8848 replacable = false;
8849 }
8850
8851 if(replacable) {
8852 analysis->keep = false;
8853 analysis->changeUsage = true;
8854 analysis->changeUsageOffset = srcOffset;
8855 analysis->changeUsageStartOffset = (Uint32)(analysisIter - iterStart);
8856 analysis->changeUsageEndOffset = srcNextWriteOffset == -1 ? (Uint32)(iterN - iterStart) : srcNextWriteOffset;
8857 return;
8858 }
8859 }
8860
8861 analysis->keep = true;
8862 return;
8863}
8864
8865static Bool writeOptimization(Context* const context,
8866 Code* const srcStart,
8867 Code* const srcEnd,
8868 const Uint32* const blockOffsetBuffer,
8869 const Uint32 argsOffset) {
8870
8871 Code* const iterStart = srcStart;
8872 Code* const iterN = srcEnd;
8873 Code* iter = iterStart;
8874
8875 Bool codeChanged = false;
8876
8877 while(iter != iterN) {
8878 const Instruction* const instruction = reflectInstruction(*iter);
8879 const Uint32 instructionLength = instruction->length;
8880
8881 Bool eliminate = false;
8882 const InstructionOperand* const operands = instruction->operands;
8883
8884 for(Uint32 i = 1; i < instructionLength; i += 1) {
8885 switch(operands[i - 1]) {
8886 case INSTRUCTION_OPERAND_DST_STACK_OFFSET:
8887 {
8888 const Uint32 writeOffset = iter[i];
8889
8890 if(writeOffset < argsOffset) {
8891 WriteUsageAnalysis analysis = {};
8892 memset(&analysis, 0, sizeof(WriteUsageAnalysis));
8893
8894 Code* const analysisStart = iter + instructionLength;
8895 analyzeWriteUsage(context, iterStart, iterN, analysisStart, iter, writeOffset, blockOffsetBuffer,
8896 argsOffset, &analysis);
8897
8898 if(!analysis.keep) {
8899 eliminate = true;
8900 }
8901 if(analysis.changeDestination) {
8902 PRINT_DEBUG_OPTS("Changing destination offset of a write from %u to %u\n", iter[i],
8903 analysis.changeDestinationOffset);
8904
8905 iter[i] = analysis.changeDestinationOffset;
8906 }
8907 if(analysis.eliminateUsage) {
8908 PRINT_DEBUG_OPTS("Eliminating usage of a write at offset %u\n", analysis.eliminateUsageOffset);
8909
8910 Code* const eliminatedCode = iterStart + analysis.eliminateUsageOffset;
8911 memset(eliminatedCode, $OPCODE_NOOP,reflectInstruction(*eliminatedCode)->length * sizeof(Code));
8912
8913 codeChanged = true;
8914 }
8915 if(analysis.changeUsage) {
8916 PRINT_DEBUG_OPTS("Replacing variable usage from %u to %u in offset range [%u; %u)\n",
8917 writeOffset, analysis.changeUsageOffset, analysis.changeUsageStartOffset,
8918 analysis.changeUsageEndOffset);
8919
8920 replaceVariableUsage(iterStart + analysis.changeUsageStartOffset,
8921 iterStart + analysis.changeUsageEndOffset,
8922 writeOffset, analysis.changeUsageOffset);
8923
8924 codeChanged = true;
8925 }
8926 }
8927 }
8928 break;
8929
8930 default: break;
8931 }
8932 }
8933
8934 if(eliminate) {
8935 codeChanged = true;
8936
8937 PRINT_DEBUG_OPTS("Eliminated unused write at offset %u\n", (Uint32)(iter - iterStart));
8938 memset(iter, $OPCODE_NOOP, instructionLength * sizeof(Code));
8939 }
8940
8941 iter += instructionLength;
8942 }
8943
8944 return codeChanged;
8945}
8946
8947// Collect info about each write. From this info you should be able to make following decisions:
8948// 1) If the write can be eliminated
8949// 2) If the write's dst could be changed and it's usage eliminated
8950// 3) If the write can be eliminated but it's usaged pointed to a different variable
8951// 4) Find out if a write could use another variable based on it's latest write
8952
8953static Bool reduceInlineFrames(MethodState* const methodState, Code* const code) {
8954 Bool reduced = false;
8955 Bool iterationModified = true;
8956
8957 InlineFrame* const iterStart = methodState->inlineFrames;
8958 Uint32 inlineFrameCount = methodState->inlineFrameCount;
8959
8960 while(iterationModified) {
8961 iterationModified = false;
8962
8963 InlineFrame* iter = iterStart;
8964 InlineFrame* iterN = iterStart + inlineFrameCount;
8965
8966 while(iter != iterN) {
8967 Uint32 subFrameIndex = 0;
8968
8969 const Uint32 iterOffset = iter->offset;
8970 const Uint32 iterLength = iter->length;
8971 const Uint32 iterEnd = iterOffset + iterLength;
8972
8973 InlineFrame* subIter = iterStart;
8974
8975 while(subIter != iter) {
8976 if(subIter->length != 0) {
8977 const Uint32 subIterOffset = subIter->offset;
8978
8979 if(iterOffset <= subIterOffset && iterEnd >= subIterOffset + subIter->length) {
8980 subFrameIndex += 1;
8981 }
8982 }
8983 subIter += 1;
8984 }
8985
8986 if(iterLength == 0) {
8987 Code* const inlineCode = code + iter->inlineInstructionOffset;
8988 assert(*inlineCode == $OPCODE_INLINE_INVOKE || *inlineCode == $OPCODE_CHKNULL_INLINE_INVOKE);
8989
8990 if(*inlineCode == $OPCODE_INLINE_INVOKE) {
8991 memset(inlineCode, $OPCODE_NOOP, reflectInstruction($OPCODE_INLINE_INVOKE)->length * sizeof(Code));
8992 }
8993
8994 memcpy(iter, iter + 1, (iterN - iter - 1) * sizeof(InlineFrame));
8995
8996 inlineFrameCount -= 1;
8997 iterN -= 1;
8998
8999 iterationModified = true;
9000 reduced = true;
9001
9002 continue;
9003 }
9004 else {
9005 Code* const inlineCode = code + iter->inlineInstructionOffset;
9006 assert(*inlineCode == $OPCODE_INLINE_INVOKE || *inlineCode == $OPCODE_CHKNULL_INLINE_INVOKE);
9007
9008 if(*inlineCode == $OPCODE_INLINE_INVOKE) {
9009 // Check if all of the instructions inside are safe.
9010 // Field setters/getters are a special case since if the source is 0 they are safe to use.
9011 const Code* codeIter = code + iterOffset;
9012 const Code* const codeIterN = codeIter + iterLength;
9013
9014 Bool containsUnsafe = false;
9015
9016 while(codeIter != codeIterN) {
9017 const Instruction* const instruction = reflectInstruction(*codeIter);
9018
9019 if(instruction->canCausePanic) {
9020 if(instruction->category == $INSTRUCTION_CATEGORY_FIELD_ACCESS) {
9021 if(codeIter[FIELD_ACCESS_INSTRUCTION_SOURCE_OFFSET_OPERAND + 1] != 0) {
9022 containsUnsafe = true;
9023 break;
9024 }
9025 }
9026 else {
9027 containsUnsafe = true;
9028 break;
9029 }
9030 }
9031
9032 codeIter += instruction->length;
9033 }
9034
9035 if(!containsUnsafe) {
9036 memcpy(iter, iter + 1, (iterN - iter - 1) * sizeof(InlineFrame));
9037
9038 inlineFrameCount -= 1;
9039 iterN -= 1;
9040
9041 iterationModified = true;
9042 reduced = true;
9043
9044 memset(inlineCode, $OPCODE_NOOP, reflectInstruction($OPCODE_INLINE_INVOKE)->length * sizeof(Code));
9045
9046 continue;
9047 }
9048 }
9049 }
9050
9051 iter += 1;
9052 }
9053 }
9054
9055 if(inlineFrameCount != methodState->inlineFrameCount) {
9056 PRINT_DEBUG_OPTS("Removed %u inline frames\n", methodState->inlineFrameCount - inlineFrameCount);
9057 InlineFrame* const newInlineFrames = realloc(methodState->inlineFrames, inlineFrameCount * sizeof(InlineFrame));
9058 methodState->inlineFrameCount = inlineFrameCount;
9059
9060 if(newInlineFrames != NULL) {
9061 methodState->inlineFrames = newInlineFrames;
9062 }
9063 }
9064
9065 return reduced;
9066}
9067
9068// 3 marks - linear, branched, repeated
9069// each value also has a pointer to the start of it's block
9070// linear code always points to 0
9071
9072typedef struct Branch Branch;
9073struct Branch {
9074
9075 Uint16 caseOffset;
9076 Uint16 fallthroughOffset;
9077
9078};
9079
9080// Have a list of ranges where code is repeated.
9081
9082typedef struct CodeProperty CodeProperty;
9083struct CodeProperty {
9084
9085 Uint16 blockOffset;
9086
9087 Bool branch;
9088 Bool repeated;
9089
9090};
9091
9092static Void level1OptimizationPass(Context* const context, const Method* const methodData, MethodState* const methodState) {
9093 methodState->traversing = true;
9094
9095 // Before doing anything we have to make sure that all sub invokations are initialized and optimized.
9096 // We cannot do any writing to code buffer before it is done.
9097
9098 initCode(context, methodData);
9099
9100 // TODO: lock
9101
9102 PRINT_DEBUG_OPTS("Optimizing method %s of size %d with optimization level 1...\n", methodData->signature,
9103 methodData->codeSize);
9104
9105 Uint16* const codeOffsetBuffer = CODE_OFFSET_BUFFER;
9106
9107 // First make a mutable copy of the code.
9108 Code* srcStart = SWAP_CODE_BUFFER1;
9109 Code* dstStart = SWAP_CODE_BUFFER2;
9110
9111 Code* src = NULL;
9112 Code* dst = NULL;
9113
9114 memcpy(dstStart, methodData->code, methodData->codeSize * sizeof(Code));
9115 dst = dstStart + methodData->codeSize;
9116
9117 // Optimize natives and copy the code in one go.
9118
9119 dst = optimizeNatives(context,
9120 methodData->code,
9121 methodData->code + methodData->codeSize,
9122 methodData->nextFrameOffset,
9123 codeOffsetBuffer,
9124 dstStart);
9125
9126 #define SWAP_BUFFERS() { \
9127 Code* tmp = srcStart; \
9128 srcStart = dstStart; \
9129 dstStart = tmp; \
9130 src = dst; \
9131 dst = dstStart; \
9132 }
9133
9134 SWAP_BUFFERS();
9135
9136 relocateJumps(srcStart, src, codeOffsetBuffer);
9137
9138 // After native optimization there might be some noops which got inserted during argument elimination.
9139 dst = eliminateNoops(srcStart, src, codeOffsetBuffer, dstStart);
9140
9141 SWAP_BUFFERS();
9142
9143 relocateJumps(srcStart, src, codeOffsetBuffer);
9144
9145 assert(src - srcStart > 0);
9146
9147 InlineAnalysis inlineAnalysis;
9148 analyzeInlines(context, srcStart, src, &inlineAnalysis);
9149
9150 // The inline of methods is only performed if there's anything to inline.
9151 if(inlineAnalysis.inlineFrameCount > 0) {
9152 // Fill out method state information about the stack.
9153 const Uint32 refLocals = inlineAnalysis.refLocals + methodData->refLocalsCount;
9154 const Uint32 x64Locals = inlineAnalysis.x64Locals + methodData->x64LocalsCount;
9155 const Uint32 x32Locals = inlineAnalysis.x32Locals + methodData->x32LocalsCount;
9156
9157 methodState->refLocals = refLocals;
9158 methodState->refVariables = refLocals + methodData->refParametersCount;
9159 methodState->x64Variables = x64Locals + methodData->x64ParametersCount;
9160 methodState->x32Variables = x32Locals + methodData->x32ParametersCount;
9161
9162 if(methodData->peakArgumentsSize > inlineAnalysis.peakArgumentsSize) {
9163 methodState->peakArgumentsSize = methodData->peakArgumentsSize;
9164 }
9165 else {
9166 methodState->peakArgumentsSize = inlineAnalysis.peakArgumentsSize;
9167 }
9168
9169 const Uint32 oldArgumentsOffset = methodData->nextFrameOffset;
9170 const Uint32 argumentsOffset = alignSize(methodData->parameterStackSize +
9171 refLocals * sizeof(CookeeObject) +
9172 x64Locals * sizeof(CookeeDouble) +
9173 x32Locals * sizeof(CookeeInt), sizeof(CookeeObject));
9174
9175 methodState->nextFrameOffset = argumentsOffset;
9176 methodState->stackSize = argumentsOffset + methodState->peakArgumentsSize;
9177
9178 InlineFrame* const inlineFrames = malloc(inlineAnalysis.inlineFrameCount * sizeof(InlineFrame));
9179
9180 if(inlineFrames == NULL) {
9181 panic(context, "Out of memory");
9182 }
9183
9184 methodState->inlineFrames = inlineFrames;
9185 methodState->inlineFrameCount = inlineAnalysis.inlineFrameCount;
9186
9187 relocateArgs(srcStart, src, oldArgumentsOffset, argumentsOffset);
9188
9189 const Uint32 initialInlineStackTranslation = methodData->parameterStackSize +
9190 methodData->x32LocalsCount * sizeof(CookeeInt) +
9191 methodData->x64LocalsCount * sizeof(CookeeDouble) +
9192 methodData->refLocalsCount * sizeof(CookeeObject);
9193
9194 const Uint32 initialInlineCodeOffsetTranslation = methodData->codeSize;
9195
9196 dst = inlineMethods(context, methodState, srcStart, src, codeOffsetBuffer,
9197 initialInlineStackTranslation, initialInlineCodeOffsetTranslation, inlineFrames, argumentsOffset,
9198 dstStart);
9199
9200 SWAP_BUFFERS();
9201
9202 relocateJumps(srcStart, src, codeOffsetBuffer);
9203 relocateVars(methodState, methodData, srcStart, src);
9204 }
9205 else {
9206 // The variables remain unchanged.
9207 methodState->stackSize = methodData->stackSize;
9208 methodState->peakArgumentsSize = methodData->peakArgumentsSize;
9209 methodState->nextFrameOffset = methodData->nextFrameOffset;
9210 methodState->refLocals = methodData->refLocalsCount;
9211 methodState->refVariables = methodData->refLocalsCount + methodData->refParametersCount;
9212 methodState->x64Variables = methodData->x64LocalsCount + methodData->x64ParametersCount;
9213 methodState->x32Variables = methodData->x32LocalsCount + methodData->x32ParametersCount;
9214 }
9215
9216 const Uint32 argumentsOffset = methodState->nextFrameOffset;
9217 Uint32* const blockOffsetBuffer = UINT32_BUFFER_MAX_METHOD_CODE_SIZE2;
9218
9219 mapBlocks(srcStart, src, blockOffsetBuffer);
9220
9221 Bool writesOptimized = false;
9222
9223 //PRINT_DEBUG_OPTS("BEFORE WRITE\n");
9224 //printCode(srcStart, (Uint32)(src - srcStart));
9225
9226 while(writeOptimization(context, srcStart, src, blockOffsetBuffer, argumentsOffset)) {
9227 //PRINT_DEBUG_OPTS("WRITE OPT PASS FINISHED\n");
9228 //printCode(srcStart, (Uint32)(src - srcStart));
9229 writesOptimized = true;
9230 }
9231
9232 if(writesOptimized) {
9233 // After write elimination there might be some noops which got inserted during the elimination of instructions.
9234 dst = eliminateNoops(srcStart, src, codeOffsetBuffer, dstStart);
9235
9236 SWAP_BUFFERS();
9237
9238 relocateJumps(srcStart, src, codeOffsetBuffer);
9239 relocateFrames(methodState->inlineFrames, methodState->inlineFrames + methodState->inlineFrameCount, codeOffsetBuffer);
9240
9241 //relocateVars(methodState, methodData, srcStart, (Uint32)(src - srcStart), argumentsOffset);
9242 }
9243
9244 if(reduceInlineFrames(methodState, srcStart)) {
9245 // After frame elimination there might be some noops which got inserted during the elimination of instructions.
9246 dst = eliminateNoops(srcStart, src, codeOffsetBuffer, dstStart);
9247
9248 SWAP_BUFFERS();
9249
9250 relocateJumps(srcStart, src, codeOffsetBuffer);
9251 relocateFrames(methodState->inlineFrames, methodState->inlineFrames + methodState->inlineFrameCount, codeOffsetBuffer);
9252 }
9253
9254 // The code will always be at src buffer.
9255 assert(dst == dstStart);
9256
9257 PRINT_DEBUG_OPTS("Final code size after optimization level 1 pass: %d\n", (Uint32)(src - srcStart));
9258
9259 const Uint32 codeSize = (Uint32)(src - srcStart);
9260 Code* const code = malloc(codeSize * sizeof(Code));
9261
9262 if(code == NULL) {
9263 panic(context, "Out of memory");
9264 }
9265
9266 memcpy(code, srcStart, codeSize * sizeof(Code));
9267
9268 methodState->code = code;
9269 methodState->codeSize = codeSize;
9270
9271 PRINT_DEBUG_OPTS("LEVEL 1 OPT CODE OF METHOD %s:\n", methodData->signature);
9272 PRINT_DEBUG_OPTS("Stack size: %d\n", methodState->stackSize);
9273 PRINT_OPTS_CODE(code, codeSize);
9274
9275 methodState->traversing = false;
9276
9277 #undef SWAP_BUFFERS
9278}
9279
9280static Void bindCrumbFunction(Context* const context,
9281 const Method* const methodData,
9282 MethodState* const methodState,
9283 CookeeCrumbFunction const crumbFunction) {
9284
9285 if(context->crumbIdx == MAX_CRUMBLES) {
9286 PRINT_DEBUG("Crumb limit reached.");
9287 return;
9288 }
9289
9290 const Instruction* const crumbInstruction = reflectInstruction($OPCODE_EXECUTE_CRUMB);
9291 const Uint32 crumbInstructionLength = crumbInstruction->length;
9292
9293 const Uint32 newCodeSize = methodState->codeSize + crumbInstructionLength;
9294 Code* const newCode = realloc(methodState->code, newCodeSize * sizeof(Code));
9295
9296 if(newCode == NULL) {
9297 PRINT_DEBUG("Failed ot realloc method code for crumb");
9298 return;
9299 }
9300
9301 memcpy(newCode + crumbInstructionLength, newCode, methodState->codeSize * sizeof(Code));
9302
9303 *newCode = $OPCODE_EXECUTE_CRUMB;
9304 newCode[indexOfInstructionOperand(crumbInstruction, $INSTRUCTION_OPERAND_CODE_OFFSET) + 1] = methodState->codeSize;
9305 newCode[indexOfInstructionOperand(crumbInstruction, $INSTRUCTION_OPERAND_CRUMB_INDEX) + 1] = context->crumbIdx;
9306
9307 // Translate all code offsets.
9308 Code* iter = newCode;
9309 Code* const iterN = newCode + newCodeSize;
9310
9311 while(iter != iterN) {
9312 const Instruction* const instruction = reflectInstruction(*iter);
9313 const Uint32 instructionLength = instruction->length;
9314 const Uint32 jumpOperandIndex = indexOfInstructionOperand(instruction, $INSTRUCTION_OPERAND_CODE_OFFSET);
9315
9316 if(jumpOperandIndex != -1) {
9317 iter[jumpOperandIndex + 1] += crumbInstructionLength;
9318 }
9319
9320 iter += instructionLength;
9321 }
9322
9323 InlineFrame* inlineFrameIter = methodState->inlineFrames;
9324 InlineFrame* const inlineFrameN = inlineFrameIter + methodState->inlineFrameCount;
9325
9326 while(inlineFrameIter != inlineFrameN) {
9327 inlineFrameIter->inlineInstructionOffset += crumbInstructionLength;
9328 inlineFrameIter->offset += crumbInstructionLength;
9329
9330 inlineFrameIter += 1;
9331 }
9332
9333 methodState->code = newCode;
9334 methodState->codeSize = newCodeSize;
9335 methodState->crumbled = true;
9336
9337 context->crumbles[context->crumbIdx++] = crumbFunction;
9338}
9339
9340///////////////////////////////////////////////////////////////////////
9341// EXECUTION
9342///////////////////////////////////////////////////////////////////////
9343
9344static Void initializeMethod(Context* const context, const Method* const method) {
9345 if(context->methodStates[method->index] == NULL) {
9346 PRINT_DEBUG("Initializing method %s state\n", method->signature);
9347 MethodState* const methodState = calloc(1, sizeof(MethodState));
9348
9349 if(methodState == NULL) {
9350 panic(context, "Out of memory");
9351 }
9352
9353 context->methodStates[method->index] = methodState;
9354 level1OptimizationPass(context, method, methodState);
9355 }
9356}
9357
9358#define INTERPRETER_BEGIN DISPATCH;
9359#define INTERPRETER_END
9360
9361#define OPCODE_REF(name) name##_lbl
9362#define OPCODE_IMPL(name) OPCODE_REF(name): \
9363 PRINT_DEBUG_EXEC("EXECUTING(%s): ", fp->fake ? "WRAPPER FRAME" : fp->method->signature); \
9364 PRINT_EXEC_INSTRUCTION(pc, pcStart); \
9365 PRINT_DEBUG_EXEC("\n");
9366
9367#ifndef COOKEE_INLINE_THREADING
9368 #define DISPATCH_BASE_SET_ENTRIES \
9369 case $OPCODE_NOOP: goto OPCODE_REF($OPCODE_NOOP); \
9370 case $OPCODE_GOTO: goto OPCODE_REF($OPCODE_GOTO); \
9371 case $OPCODE_GOTOIF: goto OPCODE_REF($OPCODE_GOTOIF); \
9372 case $OPCODE_GOTOIFNOT: goto OPCODE_REF($OPCODE_GOTOIFNOT); \
9373 case $OPCODE_IADD: goto OPCODE_REF($OPCODE_IADD); \
9374 case $OPCODE_LADD: goto OPCODE_REF($OPCODE_LADD); \
9375 case $OPCODE_FADD: goto OPCODE_REF($OPCODE_FADD); \
9376 case $OPCODE_DADD: goto OPCODE_REF($OPCODE_DADD); \
9377 case $OPCODE_ISUB: goto OPCODE_REF($OPCODE_ISUB); \
9378 case $OPCODE_LSUB: goto OPCODE_REF($OPCODE_LSUB); \
9379 case $OPCODE_FSUB: goto OPCODE_REF($OPCODE_FSUB); \
9380 case $OPCODE_DSUB: goto OPCODE_REF($OPCODE_DSUB); \
9381 case $OPCODE_IMUL: goto OPCODE_REF($OPCODE_IMUL); \
9382 case $OPCODE_LMUL: goto OPCODE_REF($OPCODE_LMUL); \
9383 case $OPCODE_FMUL: goto OPCODE_REF($OPCODE_FMUL); \
9384 case $OPCODE_DMUL: goto OPCODE_REF($OPCODE_DMUL); \
9385 case $OPCODE_IDIV: goto OPCODE_REF($OPCODE_IDIV); \
9386 case $OPCODE_LDIV: goto OPCODE_REF($OPCODE_LDIV); \
9387 case $OPCODE_FDIV: goto OPCODE_REF($OPCODE_FDIV); \
9388 case $OPCODE_DDIV: goto OPCODE_REF($OPCODE_DDIV); \
9389 case $OPCODE_I2B: goto OPCODE_REF($OPCODE_I2B); \
9390 case $OPCODE_I2L: goto OPCODE_REF($OPCODE_I2L); \
9391 case $OPCODE_I2F: goto OPCODE_REF($OPCODE_I2F); \
9392 case $OPCODE_I2D: goto OPCODE_REF($OPCODE_I2D); \
9393 case $OPCODE_L2B: goto OPCODE_REF($OPCODE_L2B); \
9394 case $OPCODE_L2I: goto OPCODE_REF($OPCODE_L2I); \
9395 case $OPCODE_L2F: goto OPCODE_REF($OPCODE_L2F); \
9396 case $OPCODE_L2D: goto OPCODE_REF($OPCODE_L2D); \
9397 case $OPCODE_F2B: goto OPCODE_REF($OPCODE_F2B); \
9398 case $OPCODE_F2I: goto OPCODE_REF($OPCODE_F2I); \
9399 case $OPCODE_F2L: goto OPCODE_REF($OPCODE_F2L); \
9400 case $OPCODE_F2D: goto OPCODE_REF($OPCODE_F2D); \
9401 case $OPCODE_D2B: goto OPCODE_REF($OPCODE_D2B); \
9402 case $OPCODE_D2I: goto OPCODE_REF($OPCODE_D2I); \
9403 case $OPCODE_D2L: goto OPCODE_REF($OPCODE_D2L); \
9404 case $OPCODE_D2F: goto OPCODE_REF($OPCODE_D2F); \
9405 case $OPCODE_NEW: goto OPCODE_REF($OPCODE_NEW); \
9406 case $OPCODE_OLD: goto OPCODE_REF($OPCODE_OLD); \
9407 case $OPCODE_TMP: goto OPCODE_REF($OPCODE_TMP); \
9408 case $OPCODE_IMOVE: goto OPCODE_REF($OPCODE_IMOVE); \
9409 case $OPCODE_LMOVE: goto OPCODE_REF($OPCODE_LMOVE); \
9410 case $OPCODE_FMOVE: goto OPCODE_REF($OPCODE_FMOVE); \
9411 case $OPCODE_DMOVE: goto OPCODE_REF($OPCODE_DMOVE); \
9412 case $OPCODE_OMOVE: goto OPCODE_REF($OPCODE_OMOVE); \
9413 case $OPCODE_IIS: goto OPCODE_REF($OPCODE_IIS); \
9414 case $OPCODE_LIS: goto OPCODE_REF($OPCODE_LIS); \
9415 case $OPCODE_FIS: goto OPCODE_REF($OPCODE_FIS); \
9416 case $OPCODE_DIS: goto OPCODE_REF($OPCODE_DIS); \
9417 case $OPCODE_OIS: goto OPCODE_REF($OPCODE_OIS); \
9418 case $OPCODE_IISNT: goto OPCODE_REF($OPCODE_IISNT); \
9419 case $OPCODE_LISNT: goto OPCODE_REF($OPCODE_LISNT); \
9420 case $OPCODE_FISNT: goto OPCODE_REF($OPCODE_FISNT); \
9421 case $OPCODE_DISNT: goto OPCODE_REF($OPCODE_DISNT); \
9422 case $OPCODE_OISNT: goto OPCODE_REF($OPCODE_OISNT); \
9423 case $OPCODE_OR: goto OPCODE_REF($OPCODE_OR); \
9424 case $OPCODE_AND: goto OPCODE_REF($OPCODE_AND); \
9425 case $OPCODE_ILT: goto OPCODE_REF($OPCODE_ILT); \
9426 case $OPCODE_LLT: goto OPCODE_REF($OPCODE_LLT); \
9427 case $OPCODE_FLT: goto OPCODE_REF($OPCODE_FLT); \
9428 case $OPCODE_DLT: goto OPCODE_REF($OPCODE_DLT); \
9429 case $OPCODE_ILTE: goto OPCODE_REF($OPCODE_ILTE); \
9430 case $OPCODE_LLTE: goto OPCODE_REF($OPCODE_LLTE); \
9431 case $OPCODE_FLTE: goto OPCODE_REF($OPCODE_FLTE); \
9432 case $OPCODE_DLTE: goto OPCODE_REF($OPCODE_DLTE); \
9433 case $OPCODE_IGT: goto OPCODE_REF($OPCODE_IGT); \
9434 case $OPCODE_LGT: goto OPCODE_REF($OPCODE_LGT); \
9435 case $OPCODE_FGT: goto OPCODE_REF($OPCODE_FGT); \
9436 case $OPCODE_DGT: goto OPCODE_REF($OPCODE_DGT); \
9437 case $OPCODE_IGTE: goto OPCODE_REF($OPCODE_IGTE); \
9438 case $OPCODE_LGTE: goto OPCODE_REF($OPCODE_LGTE); \
9439 case $OPCODE_FGTE: goto OPCODE_REF($OPCODE_FGTE); \
9440 case $OPCODE_DGTE: goto OPCODE_REF($OPCODE_DGTE); \
9441 case $OPCODE_CHKTYPE: goto OPCODE_REF($OPCODE_CHKTYPE); \
9442 case $OPCODE_GLOBAL: goto OPCODE_REF($OPCODE_GLOBAL); \
9443 case $OPCODE_TEXT: goto OPCODE_REF($OPCODE_TEXT); \
9444 case $OPCODE_NULL: goto OPCODE_REF($OPCODE_NULL); \
9445 case $OPCODE_FALSE: goto OPCODE_REF($OPCODE_FALSE); \
9446 case $OPCODE_TRUE: goto OPCODE_REF($OPCODE_TRUE); \
9447 case $OPCODE_CHAR: goto OPCODE_REF($OPCODE_CHAR); \
9448 case $OPCODE_INT: goto OPCODE_REF($OPCODE_INT); \
9449 case $OPCODE_LONG: goto OPCODE_REF($OPCODE_LONG); \
9450 case $OPCODE_DIRLONG: goto OPCODE_REF($OPCODE_DIRLONG); \
9451 case $OPCODE_FLOAT: goto OPCODE_REF($OPCODE_FLOAT); \
9452 case $OPCODE_DOUBLE: goto OPCODE_REF($OPCODE_DOUBLE); \
9453 case $OPCODE_DIRDOUBLE: goto OPCODE_REF($OPCODE_DIRDOUBLE); \
9454 case $OPCODE_INEG: goto OPCODE_REF($OPCODE_INEG); \
9455 case $OPCODE_LNEG: goto OPCODE_REF($OPCODE_LNEG); \
9456 case $OPCODE_FNEG: goto OPCODE_REF($OPCODE_FNEG); \
9457 case $OPCODE_DNEG: goto OPCODE_REF($OPCODE_DNEG); \
9458 case $OPCODE_NOT: goto OPCODE_REF($OPCODE_NOT); \
9459 case $OPCODE_IGETFIELD: goto OPCODE_REF($OPCODE_IGETFIELD); \
9460 case $OPCODE_LGETFIELD: goto OPCODE_REF($OPCODE_LGETFIELD); \
9461 case $OPCODE_FGETFIELD: goto OPCODE_REF($OPCODE_FGETFIELD); \
9462 case $OPCODE_DGETFIELD: goto OPCODE_REF($OPCODE_DGETFIELD); \
9463 case $OPCODE_OGETFIELD: goto OPCODE_REF($OPCODE_OGETFIELD); \
9464 case $OPCODE_ISETFIELD: goto OPCODE_REF($OPCODE_ISETFIELD); \
9465 case $OPCODE_LSETFIELD: goto OPCODE_REF($OPCODE_LSETFIELD); \
9466 case $OPCODE_FSETFIELD: goto OPCODE_REF($OPCODE_FSETFIELD); \
9467 case $OPCODE_DSETFIELD: goto OPCODE_REF($OPCODE_DSETFIELD); \
9468 case $OPCODE_OSETFIELD: goto OPCODE_REF($OPCODE_OSETFIELD); \
9469 case $OPCODE_INVOKE: goto OPCODE_REF($OPCODE_INVOKE); \
9470 case $OPCODE_AINVOKE: goto OPCODE_REF($OPCODE_AINVOKE); \
9471 case $OPCODE_INVOKESEQ: goto OPCODE_REF($OPCODE_INVOKESEQ); \
9472 case $OPCODE_AINVOKESEQ: goto OPCODE_REF($OPCODE_AINVOKESEQ); \
9473 case $OPCODE_IRETURN: goto OPCODE_REF($OPCODE_IRETURN); \
9474 case $OPCODE_LRETURN: goto OPCODE_REF($OPCODE_LRETURN); \
9475 case $OPCODE_FRETURN: goto OPCODE_REF($OPCODE_FRETURN); \
9476 case $OPCODE_DRETURN: goto OPCODE_REF($OPCODE_DRETURN); \
9477 case $OPCODE_ORETURN: goto OPCODE_REF($OPCODE_ORETURN); \
9478 case $OPCODE_RETURN: goto OPCODE_REF($OPCODE_RETURN); \
9479 case $OPCODE_INATIVE: goto OPCODE_REF($OPCODE_INATIVE); \
9480 case $OPCODE_LNATIVE: goto OPCODE_REF($OPCODE_LNATIVE); \
9481 case $OPCODE_FNATIVE: goto OPCODE_REF($OPCODE_FNATIVE); \
9482 case $OPCODE_DNATIVE: goto OPCODE_REF($OPCODE_DNATIVE); \
9483 case $OPCODE_ONATIVE: goto OPCODE_REF($OPCODE_ONATIVE); \
9484 case $OPCODE_NATIVESEQ: goto OPCODE_REF($OPCODE_NATIVESEQ); \
9485 case $OPCODE_UNIMPLEMENTED: goto OPCODE_REF($OPCODE_UNIMPLEMENTED);
9486
9487 #define DISPATCH_OPTIMIZATION_ENTRIES \
9488 case $OPCODE_EXIT_EXECUTE: goto OPCODE_REF($OPCODE_EXIT_EXECUTE); \
9489 case $OPCODE_GLOBAL_INITIALIZED: goto OPCODE_REF($OPCODE_GLOBAL_INITIALIZED); \
9490 case $OPCODE_INVOKE_INITIALIZED: goto OPCODE_REF($OPCODE_INVOKE_INITIALIZED); \
9491 case $OPCODE_INVOKESEQ_INITIALIZED: goto OPCODE_REF($OPCODE_INVOKESEQ_INITIALIZED); \
9492 case $OPCODE_INVOKE_INATIVE: goto OPCODE_REF($OPCODE_INVOKE_INATIVE); \
9493 case $OPCODE_INVOKE_LNATIVE: goto OPCODE_REF($OPCODE_INVOKE_LNATIVE); \
9494 case $OPCODE_INVOKE_FNATIVE: goto OPCODE_REF($OPCODE_INVOKE_FNATIVE); \
9495 case $OPCODE_INVOKE_DNATIVE: goto OPCODE_REF($OPCODE_INVOKE_DNATIVE); \
9496 case $OPCODE_INVOKE_ONATIVE: goto OPCODE_REF($OPCODE_INVOKE_ONATIVE); \
9497 case $OPCODE_INVOKE_NATIVESEQ: goto OPCODE_REF($OPCODE_INVOKE_NATIVESEQ); \
9498 case $OPCODE_CHKNULL_INLINE_INVOKE: goto OPCODE_REF($OPCODE_CHKNULL_INLINE_INVOKE); \
9499 case $OPCODE_INLINE_INVOKE: goto OPCODE_REF($OPCODE_INLINE_INVOKE); \
9500 case $OPCODE_EXECUTE_CRUMB: goto OPCODE_REF($OPCODE_EXECUTE_CRUMB); \
9501 case $OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT); \
9502 case $OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG); \
9503 case $OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX: goto OPCODE_REF($OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX); \
9504 case $OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX: goto OPCODE_REF($OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX); \
9505 case $OPCODE_LIB_BUILTINS_BITWISE_NOT_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_NOT_INT); \
9506 case $OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG); \
9507 case $OPCODE_LIB_BUILTINS_BITWISE_AND_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_AND_INT); \
9508 case $OPCODE_LIB_BUILTINS_BITWISE_AND_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_AND_LONG); \
9509 case $OPCODE_LIB_BUILTINS_BITWISE_OR_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_OR_INT); \
9510 case $OPCODE_LIB_BUILTINS_BITWISE_OR_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_OR_LONG); \
9511 case $OPCODE_LIB_BUILTINS_BITWISE_XOR_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_XOR_INT); \
9512 case $OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG); \
9513 case $OPCODE_LIB_BUILTINS_LSHIFT_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_LSHIFT_INT); \
9514 case $OPCODE_LIB_BUILTINS_LSHIFT_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_LSHIFT_LONG); \
9515 case $OPCODE_LIB_BUILTINS_RSHIFT_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_RSHIFT_INT); \
9516 case $OPCODE_LIB_BUILTINS_RSHIFT_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_RSHIFT_LONG); \
9517 case $OPCODE_LIB_BUILTINS_URSHIFT_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_URSHIFT_INT); \
9518 case $OPCODE_LIB_BUILTINS_URSHIFT_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_URSHIFT_LONG); \
9519 case $OPCODE_LIB_BUILTINS_ABS_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_INT); \
9520 case $OPCODE_LIB_BUILTINS_ABS_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_LONG); \
9521 case $OPCODE_LIB_BUILTINS_ABS_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_FLOAT); \
9522 case $OPCODE_LIB_BUILTINS_ABS_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_DOUBLE); \
9523 case $OPCODE_LIB_BUILTINS_MIN_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_INT); \
9524 case $OPCODE_LIB_BUILTINS_MIN_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_LONG); \
9525 case $OPCODE_LIB_BUILTINS_MIN_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_FLOAT); \
9526 case $OPCODE_LIB_BUILTINS_MIN_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_DOUBLE); \
9527 case $OPCODE_LIB_BUILTINS_MAX_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_INT); \
9528 case $OPCODE_LIB_BUILTINS_MAX_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_LONG); \
9529 case $OPCODE_LIB_BUILTINS_MAX_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_FLOAT); \
9530 case $OPCODE_LIB_BUILTINS_MAX_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_DOUBLE); \
9531 case $OPCODE_LIB_BUILTINS_REMAINER_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_INT); \
9532 case $OPCODE_LIB_BUILTINS_REMAINER_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_LONG); \
9533 case $OPCODE_LIB_BUILTINS_REMAINER_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_FLOAT); \
9534 case $OPCODE_LIB_BUILTINS_REMAINER_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_DOUBLE); \
9535 case $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT); \
9536 case $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG); \
9537 case $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT); \
9538 case $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE); \
9539 case $OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT); \
9540 case $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT); \
9541 case $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG); \
9542 case $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT); \
9543 case $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE); \
9544 case $OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT); \
9545 case $OPCODE_LIB_BUILTINS_ARRAY_INC_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_INT); \
9546 case $OPCODE_LIB_BUILTINS_ARRAY_INC_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_LONG); \
9547 case $OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT); \
9548 case $OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE); \
9549 case $OPCODE_LIB_BUILTINS_ARRAY_DEC_INT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_INT); \
9550 case $OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG); \
9551 case $OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT); \
9552 case $OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE: goto OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE);
9553
9554 #define DISPATCH switch(*pc) { \
9555 DISPATCH_BASE_SET_ENTRIES \
9556 DISPATCH_OPTIMIZATION_ENTRIES \
9557 default: abort(); \
9558 }
9559#else
9560 #define DISPATCH goto *LABELS[*pc]
9561#endif
9562
9563static Void execute(Context* const context) {
9564#ifdef COOKEE_INLINE_THREADING
9565 static const Void* const LABELS[INSTRUCTION_N] = {
9566 &&OPCODE_REF($OPCODE_NOOP),
9567 &&OPCODE_REF($OPCODE_GOTO),
9568 &&OPCODE_REF($OPCODE_GOTOIF),
9569 &&OPCODE_REF($OPCODE_GOTOIFNOT),
9570 &&OPCODE_REF($OPCODE_IADD),
9571 &&OPCODE_REF($OPCODE_LADD),
9572 &&OPCODE_REF($OPCODE_FADD),
9573 &&OPCODE_REF($OPCODE_DADD),
9574 &&OPCODE_REF($OPCODE_ISUB),
9575 &&OPCODE_REF($OPCODE_LSUB),
9576 &&OPCODE_REF($OPCODE_FSUB),
9577 &&OPCODE_REF($OPCODE_DSUB),
9578 &&OPCODE_REF($OPCODE_IMUL),
9579 &&OPCODE_REF($OPCODE_LMUL),
9580 &&OPCODE_REF($OPCODE_FMUL),
9581 &&OPCODE_REF($OPCODE_DMUL),
9582 &&OPCODE_REF($OPCODE_IDIV),
9583 &&OPCODE_REF($OPCODE_LDIV),
9584 &&OPCODE_REF($OPCODE_FDIV),
9585 &&OPCODE_REF($OPCODE_DDIV),
9586 &&OPCODE_REF($OPCODE_I2B),
9587 &&OPCODE_REF($OPCODE_I2L),
9588 &&OPCODE_REF($OPCODE_I2F),
9589 &&OPCODE_REF($OPCODE_I2D),
9590 &&OPCODE_REF($OPCODE_L2B),
9591 &&OPCODE_REF($OPCODE_L2I),
9592 &&OPCODE_REF($OPCODE_L2F),
9593 &&OPCODE_REF($OPCODE_L2D),
9594 &&OPCODE_REF($OPCODE_F2B),
9595 &&OPCODE_REF($OPCODE_F2I),
9596 &&OPCODE_REF($OPCODE_F2L),
9597 &&OPCODE_REF($OPCODE_F2D),
9598 &&OPCODE_REF($OPCODE_D2B),
9599 &&OPCODE_REF($OPCODE_D2I),
9600 &&OPCODE_REF($OPCODE_D2L),
9601 &&OPCODE_REF($OPCODE_D2F),
9602 &&OPCODE_REF($OPCODE_NEW),
9603 &&OPCODE_REF($OPCODE_OLD),
9604 &&OPCODE_REF($OPCODE_TMP),
9605 &&OPCODE_REF($OPCODE_IMOVE),
9606 &&OPCODE_REF($OPCODE_LMOVE),
9607 &&OPCODE_REF($OPCODE_FMOVE),
9608 &&OPCODE_REF($OPCODE_DMOVE),
9609 &&OPCODE_REF($OPCODE_OMOVE),
9610 &&OPCODE_REF($OPCODE_IIS),
9611 &&OPCODE_REF($OPCODE_LIS),
9612 &&OPCODE_REF($OPCODE_FIS),
9613 &&OPCODE_REF($OPCODE_DIS),
9614 &&OPCODE_REF($OPCODE_OIS),
9615 &&OPCODE_REF($OPCODE_IISNT),
9616 &&OPCODE_REF($OPCODE_LISNT),
9617 &&OPCODE_REF($OPCODE_FISNT),
9618 &&OPCODE_REF($OPCODE_DISNT),
9619 &&OPCODE_REF($OPCODE_OISNT),
9620 &&OPCODE_REF($OPCODE_OR),
9621 &&OPCODE_REF($OPCODE_AND),
9622 &&OPCODE_REF($OPCODE_ILT),
9623 &&OPCODE_REF($OPCODE_LLT),
9624 &&OPCODE_REF($OPCODE_FLT),
9625 &&OPCODE_REF($OPCODE_DLT),
9626 &&OPCODE_REF($OPCODE_ILTE),
9627 &&OPCODE_REF($OPCODE_LLTE),
9628 &&OPCODE_REF($OPCODE_FLTE),
9629 &&OPCODE_REF($OPCODE_DLTE),
9630 &&OPCODE_REF($OPCODE_IGT),
9631 &&OPCODE_REF($OPCODE_LGT),
9632 &&OPCODE_REF($OPCODE_FGT),
9633 &&OPCODE_REF($OPCODE_DGT),
9634 &&OPCODE_REF($OPCODE_IGTE),
9635 &&OPCODE_REF($OPCODE_LGTE),
9636 &&OPCODE_REF($OPCODE_FGTE),
9637 &&OPCODE_REF($OPCODE_DGTE),
9638 &&OPCODE_REF($OPCODE_CHKTYPE),
9639 &&OPCODE_REF($OPCODE_GLOBAL),
9640 &&OPCODE_REF($OPCODE_TEXT),
9641 &&OPCODE_REF($OPCODE_NULL),
9642 &&OPCODE_REF($OPCODE_FALSE),
9643 &&OPCODE_REF($OPCODE_TRUE),
9644 &&OPCODE_REF($OPCODE_CHAR),
9645 &&OPCODE_REF($OPCODE_INT),
9646 &&OPCODE_REF($OPCODE_LONG),
9647 &&OPCODE_REF($OPCODE_DIRLONG),
9648 &&OPCODE_REF($OPCODE_FLOAT),
9649 &&OPCODE_REF($OPCODE_DOUBLE),
9650 &&OPCODE_REF($OPCODE_DIRDOUBLE),
9651 &&OPCODE_REF($OPCODE_INEG),
9652 &&OPCODE_REF($OPCODE_LNEG),
9653 &&OPCODE_REF($OPCODE_FNEG),
9654 &&OPCODE_REF($OPCODE_DNEG),
9655 &&OPCODE_REF($OPCODE_NOT),
9656 &&OPCODE_REF($OPCODE_IGETFIELD),
9657 &&OPCODE_REF($OPCODE_LGETFIELD),
9658 &&OPCODE_REF($OPCODE_FGETFIELD),
9659 &&OPCODE_REF($OPCODE_DGETFIELD),
9660 &&OPCODE_REF($OPCODE_OGETFIELD),
9661 &&OPCODE_REF($OPCODE_ISETFIELD),
9662 &&OPCODE_REF($OPCODE_LSETFIELD),
9663 &&OPCODE_REF($OPCODE_FSETFIELD),
9664 &&OPCODE_REF($OPCODE_DSETFIELD),
9665 &&OPCODE_REF($OPCODE_OSETFIELD),
9666 &&OPCODE_REF($OPCODE_INVOKE),
9667 &&OPCODE_REF($OPCODE_AINVOKE),
9668 &&OPCODE_REF($OPCODE_INVOKESEQ),
9669 &&OPCODE_REF($OPCODE_AINVOKESEQ),
9670 &&OPCODE_REF($OPCODE_IRETURN),
9671 &&OPCODE_REF($OPCODE_LRETURN),
9672 &&OPCODE_REF($OPCODE_FRETURN),
9673 &&OPCODE_REF($OPCODE_DRETURN),
9674 &&OPCODE_REF($OPCODE_ORETURN),
9675 &&OPCODE_REF($OPCODE_RETURN),
9676 &&OPCODE_REF($OPCODE_INATIVE),
9677 &&OPCODE_REF($OPCODE_LNATIVE),
9678 &&OPCODE_REF($OPCODE_FNATIVE),
9679 &&OPCODE_REF($OPCODE_DNATIVE),
9680 &&OPCODE_REF($OPCODE_ONATIVE),
9681 &&OPCODE_REF($OPCODE_NATIVESEQ),
9682 &&OPCODE_REF($OPCODE_UNIMPLEMENTED),
9683
9684 &&OPCODE_REF($OPCODE_EXIT_EXECUTE),
9685 &&OPCODE_REF($OPCODE_GLOBAL_INITIALIZED),
9686 &&OPCODE_REF($OPCODE_INVOKE_INITIALIZED),
9687 &&OPCODE_REF($OPCODE_INVOKESEQ_INITIALIZED),
9688 &&OPCODE_REF($OPCODE_INVOKE_INATIVE),
9689 &&OPCODE_REF($OPCODE_INVOKE_LNATIVE),
9690 &&OPCODE_REF($OPCODE_INVOKE_FNATIVE),
9691 &&OPCODE_REF($OPCODE_INVOKE_DNATIVE),
9692 &&OPCODE_REF($OPCODE_INVOKE_ONATIVE),
9693 &&OPCODE_REF($OPCODE_INVOKE_NATIVESEQ),
9694 &&OPCODE_REF($OPCODE_CHKNULL_INLINE_INVOKE),
9695 &&OPCODE_REF($OPCODE_INLINE_INVOKE),
9696 &&OPCODE_REF($OPCODE_EXECUTE_CRUMB),
9697
9698 &&OPCODE_REF($OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT),
9699 &&OPCODE_REF($OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG),
9700 &&OPCODE_REF($OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX),
9701 &&OPCODE_REF($OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX),
9702 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_NOT_INT),
9703 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG),
9704 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_AND_INT),
9705 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_AND_LONG),
9706 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_OR_INT),
9707 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_OR_LONG),
9708 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_XOR_INT),
9709 &&OPCODE_REF($OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG),
9710 &&OPCODE_REF($OPCODE_LIB_BUILTINS_LSHIFT_INT),
9711 &&OPCODE_REF($OPCODE_LIB_BUILTINS_LSHIFT_LONG),
9712 &&OPCODE_REF($OPCODE_LIB_BUILTINS_RSHIFT_INT),
9713 &&OPCODE_REF($OPCODE_LIB_BUILTINS_RSHIFT_LONG),
9714 &&OPCODE_REF($OPCODE_LIB_BUILTINS_URSHIFT_INT),
9715 &&OPCODE_REF($OPCODE_LIB_BUILTINS_URSHIFT_LONG),
9716 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_INT),
9717 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_LONG),
9718 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_FLOAT),
9719 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ABS_DOUBLE),
9720 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_INT),
9721 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_LONG),
9722 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_FLOAT),
9723 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MIN_DOUBLE),
9724 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_INT),
9725 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_LONG),
9726 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_FLOAT),
9727 &&OPCODE_REF($OPCODE_LIB_BUILTINS_MAX_DOUBLE),
9728 &&OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_INT),
9729 &&OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_LONG),
9730 &&OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_FLOAT),
9731 &&OPCODE_REF($OPCODE_LIB_BUILTINS_REMAINER_DOUBLE),
9732 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT),
9733 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG),
9734 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT),
9735 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE),
9736 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT),
9737 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT),
9738 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG),
9739 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT),
9740 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE),
9741 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT),
9742 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_INT),
9743 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_LONG),
9744 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT),
9745 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE),
9746 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_INT),
9747 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG),
9748 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT),
9749 &&OPCODE_REF($OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE)
9750 };
9751#endif
9752
9753 // The locals have to be kept here because some compilers(clang)
9754 // removes the gotos when used without inline threading...
9755
9756 CookeeObject locObject1;
9757 CookeeObject locObject2;
9758
9759 CookeeDouble locDouble1;
9760 CookeeDouble locDouble2;
9761
9762 CookeeLong locLong1;
9763 CookeeLong locLong2;
9764
9765 register StackFrame* fp = context->currentFrame;
9766 register Code* pcStart = fp->pc;
9767 register Code* pc = fp->pc;
9768 register Uint8* locals = fp->locals;
9769
9770 const Data* const data = context->data;
9771 const Class* const classes = data->classes;
9772 const Method* const methods = data->methods;
9773
9774 const CookeeLong* const longLiterals = data->longLiterals;
9775 const CookeeDouble* const doubleLiterals = data->doubleLiterals;
9776 CookeeObject* const textLiterals = context->textLiteralTable;
9777
9778 MethodState** const methodStates = context->methodStates;
9779 MethodState* locMethodState;
9780
9781 const Class* locClass1;
9782 const Class* locClass2;
9783 const Method* locMethod;
9784 Void* locAttachment;
9785 Char* locStr;
9786
9787 CookeeEqualsFunction locEqualityFunction;
9788
9789 CookeeFloat locFloat1;
9790 CookeeFloat locFloat2;
9791
9792 Uint32 locIdx;
9793
9794 CookeeInt locInt1;
9795 CookeeInt locInt2;
9796
9797 register Code arg1;
9798 register Code arg2;
9799 register Code arg3;
9800 Code arg4; // 4th operand is not used often so no need to keep it in a register.
9801
9802 #define ENTER_FRAME_STUB() PRINT_DEBUG_EXEC("Entered frame %s\n", fp->method == NULL ? "?" : fp->method->signature);
9803 #define LEAVE_FRAME_STUB() PRINT_DEBUG_EXEC("Got back to frame %s\n", fp->method == NULL ? "?" : fp->method->signature);
9804
9805 #define SAVE_STATE() \
9806 fp->pc = pc; \
9807 fp->pcStart = pcStart; \
9808 fp->locals = locals; \
9809 context->currentFrame = fp; \
9810
9811 #define LOAD_STATE() \
9812 pcStart = fp->pcStart; \
9813 pc = fp->pc; \
9814 locals = fp->locals;
9815
9816 #define PUSH_FRAME(_this_, _method_) \
9817 fp->pc = pc; \
9818 fp->pcStart = pcStart; \
9819 fp->locals = locals; \
9820 \
9821 locals += fp->nextFrameOffset; \
9822 locMethod = _method_; \
9823 initializeMethod(context, locMethod); \
9824 locMethodState = methodStates[locMethod->index]; \
9825 \
9826 if(locals + locMethodState->stackSize > (Uint8*)(fp - 1)) { \
9827 SAVE_STATE(); \
9828 panic(context, "Stack overflow"); \
9829 } \
9830 \
9831 *((CookeeObject*) locals) = _this_; \
9832 \
9833 memset(locals + locMethod->parameterStackSize, 0, locMethodState->refLocals * sizeof(CookeeObject)); \
9834 \
9835 pc = locMethodState->code; \
9836 pcStart = pc; \
9837 \
9838 fp -= 1; \
9839 fp->method = locMethod; \
9840 fp->nextFrameOffset = locMethodState->nextFrameOffset; \
9841 fp->fake = false;
9842
9843 #define PUSH_FRAME_INITIALIZED(_this_, _method_) \
9844 fp->pc = pc; \
9845 fp->pcStart = pcStart; \
9846 fp->locals = locals; \
9847 \
9848 locals += fp->nextFrameOffset; \
9849 locMethod = _method_; \
9850 \
9851 assert(context->methodStates[locMethod->index] != NULL); \
9852 assert(context->methodStates[locMethod->index]->code != NULL); \
9853 \
9854 locMethodState = methodStates[locMethod->index]; \
9855 \
9856 if(locals + locMethodState->stackSize > (Uint8*)(fp - 1)) { \
9857 SAVE_STATE(); \
9858 panic(context, "Stack overflow"); \
9859 } \
9860 \
9861 *((CookeeObject*) locals) = _this_; \
9862 \
9863 memset(locals + locMethod->parameterStackSize, 0, locMethodState->refLocals * sizeof(CookeeObject)); \
9864 \
9865 pc = locMethodState->code; \
9866 pcStart = pc; \
9867 \
9868 fp -= 1; \
9869 fp->method = locMethod; \
9870 fp->nextFrameOffset = locMethodState->nextFrameOffset; \
9871 fp->fake = false;
9872
9873 // Faster when the arguments are loaded sequencially.
9874 #define LOAD0() pc += 1
9875 #define LOAD0_UNSAFE() pc += 2
9876 #define LOAD1() arg1 = pc[1]; pc += 2
9877 #define LOAD1_UNSAFE() arg1 = pc[1]; pc += 3
9878 #define LOAD2() arg1 = pc[1]; arg2 = pc[2]; pc += 3
9879 #define LOAD2_UNSAFE() arg1 = pc[1]; arg2 = pc[2]; pc += 4
9880 #define LOAD3() arg1 = pc[1]; arg2 = pc[2]; arg3 = pc[3]; pc += 4
9881 #define LOAD3_UNSAFE() arg1 = pc[1]; arg2 = pc[2]; arg3 = pc[3]; pc += 5
9882 #define LOAD4() arg1 = pc[1]; arg2 = pc[2]; arg3 = pc[3]; arg4 = pc[4]; pc += 5
9883 #define LOAD4_UNSAFE() arg1 = pc[1]; arg2 = pc[2]; arg3 = pc[3]; arg4 = pc[4]; pc += 6
9884
9885 #define LOCAL(type, offset) *((type*)(locals + (offset)))
9886 #define LOCAL_BOOL(offset) LOCAL(CookeeBool, offset)
9887 #define LOCAL_CHAR(offset) LOCAL(CookeeChar, offset)
9888 #define LOCAL_INT(offset) LOCAL(CookeeInt, offset)
9889 #define LOCAL_LONG(offset) LOCAL(CookeeLong, offset)
9890 #define LOCAL_FLOAT(offset) LOCAL(CookeeFloat, offset)
9891 #define LOCAL_DOUBLE(offset) LOCAL(CookeeDouble, offset)
9892 #define LOCAL_OBJECT(offset) LOCAL(CookeeObject, offset)
9893
9894 #define FIELD(type, source, offset) *((type*)((Uint8*)(source) + (offset)))
9895 #define FIELD_INT(source, offset) FIELD(CookeeInt, source, offset)
9896 #define FIELD_LONG(source, offset) FIELD(CookeeLong, source, offset)
9897 #define FIELD_FLOAT(source, offset) FIELD(CookeeFloat, source, offset)
9898 #define FIELD_DOUBLE(source, offset) FIELD(CookeeDouble, source, offset)
9899 #define FIELD_OBJECT(source, offset) FIELD(CookeeObject, source, offset)
9900
9901 #define ARRAY(type, source, index, pad) *((type*)((Uint8*)(source) + (pad)) + (index))
9902 #define ARRAY_INT(source, index) ARRAY(CookeeInt, source, index, COOKEE_INSTANCE_PARTITION_SIZE)
9903 #define ARRAY_LONG(source, index) ARRAY(CookeeLong, source, index, COOKEE_INSTANCE_PARTITION_SIZE)
9904 #define ARRAY_FLOAT(source, index) ARRAY(CookeeFloat, source, index, COOKEE_INSTANCE_PARTITION_SIZE)
9905 #define ARRAY_DOUBLE(source, index) ARRAY(CookeeDouble, source, index, COOKEE_INSTANCE_PARTITION_SIZE)
9906 #define ARRAY_OBJECT(source, index) ARRAY(CookeeObject, source, index, 0)
9907
9908
9909 INTERPRETER_BEGIN
9910
9911 OPCODE_IMPL($OPCODE_NOOP) LOAD0();
9912
9913 DISPATCH;
9914
9915
9916 OPCODE_IMPL($OPCODE_GOTO)
9917
9918 arg1 = pc[1];
9919 pc = pcStart + arg1;
9920
9921 DISPATCH;
9922
9923 OPCODE_IMPL($OPCODE_GOTOIF) LOAD2();
9924
9925 if(LOCAL_INT(arg1)) {
9926 pc = pcStart + arg2;
9927 }
9928
9929 DISPATCH;
9930
9931 OPCODE_IMPL($OPCODE_GOTOIFNOT) LOAD2();
9932
9933 if(!LOCAL_INT(arg1)) {
9934 pc = pcStart + arg2;
9935 }
9936
9937 DISPATCH;
9938
9939
9940 OPCODE_IMPL($OPCODE_IADD) LOAD3();
9941
9942 LOCAL_INT(arg3) = LOCAL_INT(arg1) + LOCAL_INT(arg2);
9943
9944 DISPATCH;
9945
9946 OPCODE_IMPL($OPCODE_LADD) LOAD3();
9947
9948 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) + LOCAL_LONG(arg2);
9949
9950 DISPATCH;
9951
9952 OPCODE_IMPL($OPCODE_FADD) LOAD3();
9953
9954 LOCAL_FLOAT(arg3) = LOCAL_FLOAT(arg1) + LOCAL_FLOAT(arg2);
9955
9956 DISPATCH;
9957
9958 OPCODE_IMPL($OPCODE_DADD) LOAD3();
9959
9960 LOCAL_DOUBLE(arg3) = LOCAL_DOUBLE(arg1) + LOCAL_DOUBLE(arg2);
9961
9962 DISPATCH;
9963
9964
9965 OPCODE_IMPL($OPCODE_ISUB) LOAD3();
9966
9967 LOCAL_INT(arg3) = LOCAL_INT(arg1) - LOCAL_INT(arg2);
9968
9969 DISPATCH;
9970
9971 OPCODE_IMPL($OPCODE_LSUB) LOAD3();
9972
9973 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) - LOCAL_LONG(arg2);
9974
9975 DISPATCH;
9976
9977 OPCODE_IMPL($OPCODE_FSUB) LOAD3();
9978
9979 LOCAL_FLOAT(arg3) = LOCAL_FLOAT(arg1) - LOCAL_FLOAT(arg2);
9980
9981 DISPATCH;
9982
9983 OPCODE_IMPL($OPCODE_DSUB) LOAD3();
9984
9985 LOCAL_DOUBLE(arg3) = LOCAL_DOUBLE(arg1) - LOCAL_DOUBLE(arg2);
9986
9987 DISPATCH;
9988
9989
9990 OPCODE_IMPL($OPCODE_IMUL) LOAD3();
9991
9992 LOCAL_INT(arg3) = LOCAL_INT(arg1) * LOCAL_INT(arg2);
9993
9994 DISPATCH;
9995
9996 OPCODE_IMPL($OPCODE_LMUL) LOAD3();
9997
9998 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) * LOCAL_LONG(arg2);
9999
10000 DISPATCH;
10001
10002 OPCODE_IMPL($OPCODE_FMUL) LOAD3();
10003
10004 LOCAL_FLOAT(arg3) = LOCAL_FLOAT(arg1) * LOCAL_FLOAT(arg2);
10005
10006 DISPATCH;
10007
10008 OPCODE_IMPL($OPCODE_DMUL) LOAD3();
10009
10010 LOCAL_DOUBLE(arg3) = LOCAL_DOUBLE(arg1) * LOCAL_DOUBLE(arg2);
10011
10012 DISPATCH;
10013
10014
10015 OPCODE_IMPL($OPCODE_IDIV) LOAD3_UNSAFE();
10016
10017 locInt1 = LOCAL_INT(arg1);
10018 locInt2 = LOCAL_INT(arg2);
10019
10020 if(locInt2 == 0) {
10021 SAVE_STATE();
10022 panic(context, "Division by 0");
10023 }
10024 else if(locInt1 == 0x80000000 && (locInt2 == -1)) {
10025 LOCAL_INT(arg3) = 0x80000000;
10026 }
10027 else {
10028 LOCAL_INT(arg3) = locInt1 / locInt2;
10029 }
10030
10031 DISPATCH;
10032
10033 OPCODE_IMPL($OPCODE_LDIV) LOAD3_UNSAFE();
10034
10035 locLong1 = LOCAL_LONG(arg1);
10036 locLong2 = LOCAL_LONG(arg2);
10037
10038 if(locLong2 == 0) {
10039 SAVE_STATE();
10040 panic(context, "Division by 0");
10041 }
10042 else if(locLong1 == 0x8000000000000000LL && locLong2 == -1) {
10043 LOCAL_LONG(arg3) = 0x8000000000000000LL;
10044 }
10045 else {
10046 LOCAL_LONG(arg3) = locLong1 / locLong2;
10047 }
10048
10049 DISPATCH;
10050
10051 OPCODE_IMPL($OPCODE_FDIV) LOAD3();
10052
10053 LOCAL_FLOAT(arg3) = LOCAL_FLOAT(arg1) / LOCAL_FLOAT(arg2);
10054
10055 DISPATCH;
10056
10057 OPCODE_IMPL($OPCODE_DDIV) LOAD3();
10058
10059 LOCAL_DOUBLE(arg3) = LOCAL_DOUBLE(arg1) / LOCAL_DOUBLE(arg2);
10060
10061 DISPATCH;
10062
10063
10064 OPCODE_IMPL($OPCODE_I2B) LOAD2();
10065
10066 LOCAL_BOOL(arg2) = (CookeeBool)(LOCAL_INT(arg1) != 0);
10067
10068 DISPATCH;
10069
10070 OPCODE_IMPL($OPCODE_I2L) LOAD2();
10071
10072 LOCAL_LONG(arg2) = (CookeeLong)(LOCAL_INT(arg1));
10073
10074 DISPATCH;
10075
10076 OPCODE_IMPL($OPCODE_I2F) LOAD2();
10077
10078 LOCAL_FLOAT(arg2) = (CookeeFloat)(LOCAL_INT(arg1));
10079
10080 DISPATCH;
10081
10082 OPCODE_IMPL($OPCODE_I2D) LOAD2();
10083
10084 LOCAL_DOUBLE(arg2) = (CookeeDouble)(LOCAL_INT(arg1));
10085
10086 DISPATCH;
10087
10088
10089 OPCODE_IMPL($OPCODE_L2B) LOAD2();
10090
10091 LOCAL_BOOL(arg2) = (CookeeBool)(LOCAL_LONG(arg1) != 0);
10092
10093 DISPATCH;
10094
10095 OPCODE_IMPL($OPCODE_L2I) LOAD2();
10096
10097 LOCAL_INT(arg2) = (CookeeInt)(LOCAL_LONG(arg1));
10098
10099 DISPATCH;
10100
10101 OPCODE_IMPL($OPCODE_L2F) LOAD2();
10102
10103 LOCAL_FLOAT(arg2) = (CookeeFloat)(LOCAL_LONG(arg1));
10104
10105 DISPATCH;
10106
10107 OPCODE_IMPL($OPCODE_L2D) LOAD2();
10108
10109 LOCAL_DOUBLE(arg2) = (CookeeDouble)(LOCAL_LONG(arg1));
10110
10111 DISPATCH;
10112
10113
10114 OPCODE_IMPL($OPCODE_F2B) LOAD2();
10115
10116 LOCAL_BOOL(arg2) = (CookeeBool)(LOCAL_FLOAT(arg1) != 0.0f);
10117
10118 DISPATCH;
10119
10120 OPCODE_IMPL($OPCODE_F2I) LOAD2();
10121
10122 LOCAL_INT(arg2) = (CookeeInt)(LOCAL_FLOAT(arg1));
10123
10124 DISPATCH;
10125
10126 OPCODE_IMPL($OPCODE_F2L) LOAD2();
10127
10128 LOCAL_LONG(arg2) = (CookeeLong)(LOCAL_FLOAT(arg1));
10129
10130 DISPATCH;
10131
10132 OPCODE_IMPL($OPCODE_F2D) LOAD2();
10133
10134 LOCAL_DOUBLE(arg2) = (CookeeDouble)(LOCAL_FLOAT(arg1));
10135
10136 DISPATCH;
10137
10138
10139 OPCODE_IMPL($OPCODE_D2B) LOAD2();
10140
10141 LOCAL_BOOL(arg2) = (CookeeBool)(LOCAL_DOUBLE(arg1) != 0.0);
10142
10143 DISPATCH;
10144
10145 OPCODE_IMPL($OPCODE_D2I) LOAD2();
10146
10147 LOCAL_INT(arg2) = (CookeeInt)(LOCAL_DOUBLE(arg1));
10148
10149 DISPATCH;
10150
10151 OPCODE_IMPL($OPCODE_D2L) LOAD2();
10152
10153 LOCAL_LONG(arg2) = (CookeeLong)(LOCAL_DOUBLE(arg1));
10154
10155 DISPATCH;
10156
10157 OPCODE_IMPL($OPCODE_D2F) LOAD2();
10158
10159 LOCAL_FLOAT(arg2) = (CookeeFloat)(LOCAL_DOUBLE(arg1));
10160
10161 DISPATCH;
10162
10163
10164 OPCODE_IMPL($OPCODE_NEW) LOAD2_UNSAFE();
10165
10166 SAVE_STATE();
10167 locObject1 = newObject(context, &classes[arg1]);
10168
10169 if(locObject1 == COOKEE_NULL) {
10170 panic(context, "Out of memory");
10171 }
10172
10173 LOCAL_OBJECT(arg2) = locObject1;
10174
10175 DISPATCH;
10176
10177 OPCODE_IMPL($OPCODE_OLD) LOAD2_UNSAFE();
10178
10179 SAVE_STATE();
10180 locObject1 = oldObject(context, &classes[arg1], context->classStates[arg1]);
10181
10182 if(locObject1 == COOKEE_NULL) {
10183 panic(context, "Out of memory");
10184 }
10185
10186 LOCAL_OBJECT(arg2) = locObject1;
10187
10188 DISPATCH;
10189
10190 OPCODE_IMPL($OPCODE_TMP) LOAD3_UNSAFE();
10191
10192 SAVE_STATE();
10193 locObject1 = tmpObject(context, &classes[arg1], context->classStates[arg1], arg2);
10194
10195 if(locObject1 == COOKEE_NULL) {
10196 panic(context, "Out of memory");
10197 }
10198
10199 LOCAL_OBJECT(arg3) = locObject1;
10200
10201 DISPATCH;
10202
10203
10204 OPCODE_IMPL($OPCODE_IMOVE) LOAD2();
10205
10206 LOCAL_INT(arg2) = LOCAL_INT(arg1);
10207
10208 DISPATCH;
10209
10210 OPCODE_IMPL($OPCODE_LMOVE) LOAD2();
10211
10212 LOCAL_LONG(arg2) = LOCAL_LONG(arg1);
10213
10214 DISPATCH;
10215
10216 OPCODE_IMPL($OPCODE_FMOVE) LOAD2();
10217
10218 LOCAL_FLOAT(arg2) = LOCAL_FLOAT(arg1);
10219
10220 DISPATCH;
10221
10222 OPCODE_IMPL($OPCODE_DMOVE) LOAD2();
10223
10224 LOCAL_DOUBLE(arg2) = LOCAL_DOUBLE(arg1);
10225
10226 DISPATCH;
10227
10228 OPCODE_IMPL($OPCODE_OMOVE) LOAD2();
10229
10230 LOCAL_OBJECT(arg2) = LOCAL_OBJECT(arg1);
10231
10232 DISPATCH;
10233
10234
10235 OPCODE_IMPL($OPCODE_IIS) LOAD3();
10236
10237 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) == LOCAL_INT(arg2));
10238
10239 DISPATCH;
10240
10241 OPCODE_IMPL($OPCODE_LIS) LOAD3();
10242
10243 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) == LOCAL_LONG(arg2));
10244
10245 DISPATCH;
10246
10247 OPCODE_IMPL($OPCODE_FIS) LOAD3();
10248
10249 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) == LOCAL_FLOAT(arg2));
10250
10251 DISPATCH;
10252
10253 OPCODE_IMPL($OPCODE_DIS) LOAD3();
10254
10255 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) == LOCAL_DOUBLE(arg2));
10256
10257 DISPATCH;
10258
10259 OPCODE_IMPL($OPCODE_OIS) LOAD3();
10260
10261 locObject1 = LOCAL_OBJECT(arg1);
10262 locObject2 = LOCAL_OBJECT(arg2);
10263
10264 if(locObject1 == locObject2) {
10265 LOCAL_BOOL(arg3) = COOKEE_TRUE;
10266 }
10267 else if(locObject1 != COOKEE_NULL && locObject2 != COOKEE_NULL) {
10268 locIdx = getObjectClassIndex(locObject1);
10269
10270 if(locIdx == getObjectClassIndex(locObject2)) {
10271 locEqualityFunction = classes[locIdx].equalityFunction;
10272
10273 if(locEqualityFunction != NULL) {
10274 locAttachment = context->currentBindingAttachment;
10275
10276 context->currentBindingAttachment = classes[locIdx].equalityFunctionAttachment;
10277 LOCAL_BOOL(arg3) = locEqualityFunction(context, locObject1, locObject2);
10278 context->currentBindingAttachment = locAttachment;
10279 }
10280 else {
10281 LOCAL_BOOL(arg3) = COOKEE_FALSE;
10282 }
10283 }
10284 else {
10285 LOCAL_BOOL(arg3) = COOKEE_FALSE;
10286 }
10287 }
10288 else {
10289 LOCAL_BOOL(arg3) = COOKEE_FALSE;
10290 }
10291
10292 DISPATCH;
10293
10294
10295 OPCODE_IMPL($OPCODE_IISNT) LOAD3();
10296
10297 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) != LOCAL_INT(arg2));
10298
10299 DISPATCH;
10300
10301 OPCODE_IMPL($OPCODE_LISNT) LOAD3();
10302
10303 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) != LOCAL_LONG(arg2));
10304
10305 DISPATCH;
10306
10307 OPCODE_IMPL($OPCODE_FISNT) LOAD3();
10308
10309 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) != LOCAL_FLOAT(arg2));
10310
10311 DISPATCH;
10312
10313 OPCODE_IMPL($OPCODE_DISNT) LOAD3();
10314
10315 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) != LOCAL_DOUBLE(arg2));
10316
10317 DISPATCH;
10318
10319 OPCODE_IMPL($OPCODE_OISNT) LOAD3();
10320
10321 locObject1 = LOCAL_OBJECT(arg1);
10322 locObject2 = LOCAL_OBJECT(arg2);
10323
10324 if(locObject1 != COOKEE_NULL && locObject2 != COOKEE_NULL) {
10325 locIdx = getObjectClassIndex(locObject1);
10326
10327 if(locIdx == getObjectClassIndex(locObject2)) {
10328 locEqualityFunction = classes[locIdx].equalityFunction;
10329
10330 if(locEqualityFunction != NULL) {
10331 locAttachment = context->currentBindingAttachment;
10332
10333 context->currentBindingAttachment = classes[locIdx].equalityFunctionAttachment;
10334 LOCAL_BOOL(arg3) = (CookeeBool) !locEqualityFunction(context, locObject1, locObject2);
10335 context->currentBindingAttachment = locAttachment;
10336 }
10337 else {
10338 LOCAL_BOOL(arg3) = (CookeeBool)(locObject1 != locObject2);
10339 }
10340 }
10341 else {
10342 LOCAL_BOOL(arg3) = COOKEE_TRUE;
10343 }
10344 }
10345 else if(locObject1 != locObject2) {
10346 LOCAL_BOOL(arg3) = COOKEE_TRUE;
10347 }
10348 else {
10349 LOCAL_BOOL(arg3) = COOKEE_FALSE;
10350 }
10351
10352 DISPATCH;
10353
10354
10355 OPCODE_IMPL($OPCODE_OR) LOAD3();
10356
10357 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_BOOL(arg1) || LOCAL_BOOL(arg2));
10358
10359 DISPATCH;
10360
10361 OPCODE_IMPL($OPCODE_AND) LOAD3();
10362
10363 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_BOOL(arg1) && LOCAL_BOOL(arg2));
10364
10365 DISPATCH;
10366
10367
10368 OPCODE_IMPL($OPCODE_ILT) LOAD3();
10369
10370 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) < LOCAL_INT(arg2));
10371
10372 DISPATCH;
10373
10374 OPCODE_IMPL($OPCODE_LLT) LOAD3();
10375
10376 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) < LOCAL_LONG(arg2));
10377
10378 DISPATCH;
10379
10380 OPCODE_IMPL($OPCODE_FLT) LOAD3();
10381
10382 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) < LOCAL_FLOAT(arg2));
10383
10384 DISPATCH;
10385
10386 OPCODE_IMPL($OPCODE_DLT) LOAD3();
10387
10388 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) < LOCAL_DOUBLE(arg2));
10389
10390 DISPATCH;
10391
10392
10393 OPCODE_IMPL($OPCODE_ILTE) LOAD3();
10394
10395 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) <= LOCAL_INT(arg2));
10396
10397 DISPATCH;
10398
10399 OPCODE_IMPL($OPCODE_LLTE) LOAD3();
10400
10401 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) <= LOCAL_LONG(arg2));
10402
10403 DISPATCH;
10404
10405 OPCODE_IMPL($OPCODE_FLTE) LOAD3();
10406
10407 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) <= LOCAL_FLOAT(arg2));
10408
10409 DISPATCH;
10410
10411 OPCODE_IMPL($OPCODE_DLTE) LOAD3();
10412
10413 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) <= LOCAL_DOUBLE(arg2));
10414
10415 DISPATCH;
10416
10417
10418 OPCODE_IMPL($OPCODE_IGT) LOAD3();
10419
10420 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) > LOCAL_INT(arg2));
10421
10422 DISPATCH;
10423
10424 OPCODE_IMPL($OPCODE_LGT) LOAD3();
10425
10426 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) > LOCAL_LONG(arg2));
10427
10428 DISPATCH;
10429
10430 OPCODE_IMPL($OPCODE_FGT) LOAD3();
10431
10432 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) > LOCAL_FLOAT(arg2));
10433
10434 DISPATCH;
10435
10436 OPCODE_IMPL($OPCODE_DGT) LOAD3();
10437
10438 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) > LOCAL_DOUBLE(arg2));
10439
10440 DISPATCH;
10441
10442
10443 OPCODE_IMPL($OPCODE_IGTE) LOAD3();
10444
10445 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_INT(arg1) >= LOCAL_INT(arg2));
10446
10447 DISPATCH;
10448
10449 OPCODE_IMPL($OPCODE_LGTE) LOAD3();
10450
10451 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_LONG(arg1) >= LOCAL_LONG(arg2));
10452
10453 DISPATCH;
10454
10455 OPCODE_IMPL($OPCODE_FGTE) LOAD3();
10456
10457 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_FLOAT(arg1) >= LOCAL_FLOAT(arg2));
10458
10459 DISPATCH;
10460
10461 OPCODE_IMPL($OPCODE_DGTE) LOAD3();
10462
10463 LOCAL_BOOL(arg3) = (CookeeBool)(LOCAL_DOUBLE(arg1) >= LOCAL_DOUBLE(arg2));
10464
10465 DISPATCH;
10466
10467
10468 OPCODE_IMPL($OPCODE_CHKTYPE) LOAD3_UNSAFE();
10469
10470 locObject1 = LOCAL_OBJECT(arg1);
10471
10472 if(locObject1 != COOKEE_NULL) {
10473 locClass1 = &classes[arg2]; // Cast to class
10474
10475 assert(!isArray(locObject1));
10476
10477 if(!classes[getObjectClassIndex(locObject1)].castingTable[arg2]) {
10478 locClass2 = &classes[getObjectClassIndex(locObject1)]; // Cast from class
10479
10480 SAVE_STATE();
10481
10482 // Compose the message and pass it as crash message.
10483 locStr = malloc((Uint32) strlen("Instance of class %s cannot be casted to %s") +
10484 (Uint32) strlen(locClass2->signature) +
10485 (Uint32) strlen(locClass1->signature) - 4);
10486
10487 if(locStr == NULL) {
10488 panic(context, "Invalid cast");
10489 }
10490 else {
10491 sprintf(locStr, "Instance of class %s cannot be casted to %s", locClass2->signature, locClass1->signature);
10492 panic(context, locStr);
10493 }
10494 }
10495 }
10496
10497 LOCAL_OBJECT(arg3) = locObject1;
10498
10499 DISPATCH;
10500
10501
10502 OPCODE_IMPL($OPCODE_GLOBAL) LOAD2_UNSAFE();
10503
10504 // Next time we execute this it will directly assign the global.
10505 *(pc - reflectInstruction($OPCODE_GLOBAL)->length) = $OPCODE_GLOBAL_INITIALIZED;
10506
10507 locObject1 = context->classStates[arg1]->globalInstance;
10508
10509 if(locObject1 == COOKEE_NULL) {
10510 locClass1 = &classes[arg1];
10511 locObject1 = newObject(context, locClass1);
10512
10513 if(locObject1 == COOKEE_NULL) {
10514 SAVE_STATE();
10515 panic(context, "Out of memory");
10516 }
10517
10518 context->classStates[arg1]->globalInstance = locObject1;
10519
10520 LOCAL_OBJECT(arg2) = locObject1;
10521
10522 if(locClass1->initializer != NULL) {
10523 PUSH_FRAME(locObject1, locClass1->initializer);
10524 ENTER_FRAME_STUB();
10525 }
10526 }
10527 else {
10528 LOCAL_OBJECT(arg2) = locObject1;
10529 }
10530
10531 DISPATCH;
10532
10533
10534 OPCODE_IMPL($OPCODE_TEXT) LOAD2();
10535
10536 assert(textLiterals[arg1] != COOKEE_NULL);
10537 LOCAL_OBJECT(arg2) = textLiterals[arg1];
10538
10539 DISPATCH;
10540
10541
10542 OPCODE_IMPL($OPCODE_FALSE) LOAD1();
10543
10544 LOCAL_BOOL(arg1) = COOKEE_FALSE;
10545
10546 DISPATCH;
10547
10548 OPCODE_IMPL($OPCODE_TRUE) LOAD1();
10549
10550 LOCAL_BOOL(arg1) = COOKEE_TRUE;
10551
10552 DISPATCH;
10553
10554
10555 OPCODE_IMPL($OPCODE_NULL) LOAD1();
10556
10557 LOCAL_OBJECT(arg1) = COOKEE_NULL;
10558
10559 DISPATCH;
10560
10561
10562 OPCODE_IMPL($OPCODE_CHAR) LOAD2();
10563
10564 LOCAL_CHAR(arg2) = (CookeeChar) arg1;
10565
10566 DISPATCH;
10567
10568 OPCODE_IMPL($OPCODE_INT) LOAD2();
10569
10570 LOCAL_INT(arg2) = (CookeeInt)((CodeValue) arg1);
10571
10572 DISPATCH;
10573
10574 OPCODE_IMPL($OPCODE_LONG) LOAD2();
10575
10576 LOCAL_LONG(arg2) = longLiterals[arg1];
10577
10578 DISPATCH;
10579
10580 OPCODE_IMPL($OPCODE_DIRLONG) LOAD2();
10581
10582 LOCAL_LONG(arg2) = (CookeeLong)((CodeValue) arg1);
10583
10584 DISPATCH;
10585
10586 OPCODE_IMPL($OPCODE_FLOAT) LOAD2();
10587
10588 LOCAL_FLOAT(arg2) = intBitsToFloat(arg1);
10589
10590 DISPATCH;
10591
10592 OPCODE_IMPL($OPCODE_DOUBLE) LOAD2();
10593
10594 LOCAL_DOUBLE(arg2) = doubleLiterals[arg1];
10595
10596 DISPATCH;
10597
10598 OPCODE_IMPL($OPCODE_DIRDOUBLE) LOAD2();
10599
10600 LOCAL_DOUBLE(arg2) = (CookeeDouble) intBitsToFloat(arg1);
10601
10602 DISPATCH;
10603
10604
10605 OPCODE_IMPL($OPCODE_INEG) LOAD2();
10606
10607 LOCAL_INT(arg2) = -LOCAL_INT(arg1);
10608
10609 DISPATCH;
10610
10611 OPCODE_IMPL($OPCODE_LNEG) LOAD2();
10612
10613 LOCAL_LONG(arg2) = -LOCAL_LONG(arg1);
10614
10615 DISPATCH;
10616
10617 OPCODE_IMPL($OPCODE_FNEG) LOAD2();
10618
10619 LOCAL_FLOAT(arg2) = -LOCAL_FLOAT(arg1);
10620
10621 DISPATCH;
10622
10623 OPCODE_IMPL($OPCODE_DNEG) LOAD2();
10624
10625 LOCAL_DOUBLE(arg2) = -LOCAL_DOUBLE(arg1);
10626
10627 DISPATCH;
10628
10629
10630 OPCODE_IMPL($OPCODE_NOT) LOAD2();
10631
10632 LOCAL_BOOL(arg2) = (CookeeBool)(!LOCAL_BOOL(arg1));
10633
10634 DISPATCH;
10635
10636
10637 OPCODE_IMPL($OPCODE_IGETFIELD) LOAD3_UNSAFE();
10638
10639 locObject1 = LOCAL_OBJECT(arg1);
10640
10641 if(locObject1 == COOKEE_NULL) {
10642 SAVE_STATE();
10643 panic(context, "Field access on null reference");
10644 }
10645
10646 LOCAL_INT(arg3) = *((CookeeInt*)((Uint8*) locObject1 + arg2));
10647
10648 DISPATCH;
10649
10650 OPCODE_IMPL($OPCODE_LGETFIELD) LOAD3_UNSAFE();
10651
10652 locObject1 = LOCAL_OBJECT(arg1);
10653
10654 if(locObject1 == COOKEE_NULL) {
10655 SAVE_STATE();
10656 panic(context, "Field access on null reference");
10657 }
10658
10659 LOCAL_LONG(arg3) = *((CookeeLong*)((Uint8*) locObject1 + arg2));
10660
10661 DISPATCH;
10662
10663 OPCODE_IMPL($OPCODE_FGETFIELD) LOAD3_UNSAFE();
10664
10665 locObject1 = LOCAL_OBJECT(arg1);
10666
10667 if(locObject1 == COOKEE_NULL) {
10668 SAVE_STATE();
10669 panic(context, "Field access on null reference");
10670 }
10671
10672 LOCAL_FLOAT(arg3) = *((CookeeFloat*)((Uint8*) locObject1 + arg2));
10673
10674 DISPATCH;
10675
10676 OPCODE_IMPL($OPCODE_DGETFIELD) LOAD3_UNSAFE();
10677
10678 locObject1 = LOCAL_OBJECT(arg1);
10679
10680 if(locObject1 == COOKEE_NULL) {
10681 SAVE_STATE();
10682 panic(context, "Field access on null reference");
10683 }
10684
10685 LOCAL_DOUBLE(arg3) = *((CookeeDouble*)((Uint8*) locObject1 + arg2));
10686
10687 DISPATCH;
10688
10689 OPCODE_IMPL($OPCODE_OGETFIELD) LOAD3_UNSAFE();
10690
10691 locObject1 = LOCAL_OBJECT(arg1);
10692
10693 if(locObject1 == COOKEE_NULL) {
10694 SAVE_STATE();
10695 panic(context, "Field access on null reference");
10696 }
10697
10698 LOCAL_OBJECT(arg3) = *((CookeeObject*)((Uint8*) locObject1 + arg2));
10699
10700 DISPATCH;
10701
10702
10703 OPCODE_IMPL($OPCODE_ISETFIELD) LOAD3_UNSAFE();
10704
10705 locObject1 = LOCAL_OBJECT(arg1);
10706
10707 if(locObject1 == COOKEE_NULL) {
10708 SAVE_STATE();
10709 panic(context, "Field access on null reference");
10710 }
10711
10712 *((CookeeInt*)((Uint8*) locObject1 + arg3)) = LOCAL_INT(arg2);
10713
10714 DISPATCH;
10715
10716 OPCODE_IMPL($OPCODE_LSETFIELD) LOAD3_UNSAFE();
10717
10718 locObject1 = LOCAL_OBJECT(arg1);
10719
10720 if(locObject1 == COOKEE_NULL) {
10721 SAVE_STATE();
10722 panic(context, "Field access on null reference");
10723 }
10724
10725 *((CookeeLong*)((Uint8*) locObject1 + arg3)) = LOCAL_LONG(arg2);
10726
10727 DISPATCH;
10728
10729 OPCODE_IMPL($OPCODE_FSETFIELD) LOAD3_UNSAFE();
10730
10731 locObject1 = LOCAL_OBJECT(arg1);
10732
10733 if(locObject1 == COOKEE_NULL) {
10734 SAVE_STATE();
10735 panic(context, "Field access on null reference");
10736 }
10737
10738 *((CookeeFloat*)((Uint8*) locObject1 + arg3)) = LOCAL_FLOAT(arg2);
10739
10740 DISPATCH;
10741
10742 OPCODE_IMPL($OPCODE_DSETFIELD) LOAD3_UNSAFE();
10743
10744 locObject1 = LOCAL_OBJECT(arg1);
10745
10746 if(locObject1 == COOKEE_NULL) {
10747 SAVE_STATE();
10748 panic(context, "Field access on null reference");
10749 }
10750
10751 *((CookeeDouble*)((Uint8*) locObject1 + arg3)) = LOCAL_DOUBLE(arg2);
10752
10753 DISPATCH;
10754
10755 OPCODE_IMPL($OPCODE_OSETFIELD) LOAD3_UNSAFE();
10756
10757 locObject1 = LOCAL_OBJECT(arg1);
10758
10759 if(locObject1 == COOKEE_NULL) {
10760 SAVE_STATE();
10761 panic(context, "Field access on null reference");
10762 }
10763
10764 *((CookeeObject*)((Uint8*) locObject1 + arg3)) = LOCAL_OBJECT(arg2);
10765
10766 DISPATCH;
10767
10768
10769 OPCODE_IMPL($OPCODE_INVOKE) LOAD2_UNSAFE();
10770
10771 // Next time we execute this invokation we will know that the method is initialized.
10772 *(pc - reflectInstruction($OPCODE_INVOKE)->length) = $OPCODE_INVOKE_INITIALIZED;
10773
10774 locObject1 = LOCAL_OBJECT(arg1);
10775
10776 if(locObject1 == COOKEE_NULL) {
10777 SAVE_STATE();
10778 panic(context, "Method call on null reference");
10779 }
10780
10781 PUSH_FRAME(locObject1, &methods[arg2]);
10782 ENTER_FRAME_STUB();
10783
10784 DISPATCH;
10785
10786 OPCODE_IMPL($OPCODE_AINVOKE) LOAD2_UNSAFE();
10787
10788 locObject1 = LOCAL_OBJECT(arg1);
10789
10790 if(locObject1 == COOKEE_NULL) {
10791 SAVE_STATE();
10792 panic(context, "Method call on null reference");
10793 }
10794
10795 PUSH_FRAME(locObject1, classes[getObjectClassIndex(locObject1)].surfaceMethods[arg2]);
10796 ENTER_FRAME_STUB();
10797
10798 DISPATCH;
10799
10800 OPCODE_IMPL($OPCODE_INVOKESEQ) LOAD3_UNSAFE();
10801
10802 // Next time we execute this invokation we will know that the method is initialized.
10803 *(pc - reflectInstruction($OPCODE_INVOKESEQ)->length) = $OPCODE_INVOKESEQ_INITIALIZED;
10804
10805 locObject1 = LOCAL_OBJECT(arg1);
10806
10807 if(locObject1 == COOKEE_NULL) {
10808 SAVE_STATE();
10809 panic(context, "Method call on null reference");
10810 }
10811
10812 PUSH_FRAME(locObject1, &methods[arg2]);
10813
10814 fp->sequenceIndex = instructionSequenceDataIndex(arg3);
10815 fp->sequenceLength = instructionSequenceDataLength(arg3);
10816
10817 ENTER_FRAME_STUB();
10818
10819 DISPATCH;
10820
10821 OPCODE_IMPL($OPCODE_AINVOKESEQ) LOAD3_UNSAFE();
10822
10823 locObject1 = LOCAL_OBJECT(arg1);
10824
10825 if(locObject1 == COOKEE_NULL) {
10826 SAVE_STATE();
10827 panic(context, "Method call on null reference");
10828 }
10829
10830 PUSH_FRAME(locObject1, classes[getObjectClassIndex(locObject1)].surfaceMethods[arg2]);
10831
10832 fp->sequenceIndex = instructionSequenceDataIndex(arg3);
10833 fp->sequenceLength = instructionSequenceDataLength(arg3);
10834
10835 ENTER_FRAME_STUB();
10836
10837 DISPATCH;
10838
10839 OPCODE_IMPL($OPCODE_IRETURN)
10840
10841 arg1 = pc[1];
10842
10843 LOCAL_INT(0) = LOCAL_INT(arg1);
10844
10845 fp += 1;
10846
10847 LOAD_STATE();
10848 LEAVE_FRAME_STUB();
10849
10850 DISPATCH;
10851
10852 OPCODE_IMPL($OPCODE_LRETURN)
10853
10854 arg1 = pc[1];
10855
10856 LOCAL_LONG(0) = LOCAL_LONG(arg1);
10857
10858 fp += 1;
10859
10860 LOAD_STATE();
10861 LEAVE_FRAME_STUB();
10862
10863 DISPATCH;
10864
10865 OPCODE_IMPL($OPCODE_FRETURN)
10866
10867 arg1 = pc[1];
10868
10869 LOCAL_FLOAT(0) = LOCAL_FLOAT(arg1);
10870
10871 fp += 1;
10872
10873 LOAD_STATE();
10874 LEAVE_FRAME_STUB();
10875
10876 DISPATCH;
10877
10878 OPCODE_IMPL($OPCODE_DRETURN)
10879
10880 arg1 = pc[1];
10881
10882 LOCAL_DOUBLE(0) = LOCAL_DOUBLE(arg1);
10883
10884 fp += 1;
10885
10886 LOAD_STATE();
10887 LEAVE_FRAME_STUB();
10888
10889 DISPATCH;
10890
10891 OPCODE_IMPL($OPCODE_ORETURN)
10892
10893 arg1 = pc[1];
10894
10895 LOCAL_OBJECT(0) = LOCAL_OBJECT(arg1);
10896
10897 fp += 1;
10898
10899 LOAD_STATE();
10900 LEAVE_FRAME_STUB();
10901
10902 DISPATCH;
10903
10904 OPCODE_IMPL($OPCODE_RETURN)
10905
10906 fp += 1;
10907
10908 LOAD_STATE();
10909 LEAVE_FRAME_STUB();
10910
10911 DISPATCH;
10912
10913 OPCODE_IMPL($OPCODE_INATIVE)
10914
10915 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
10916
10917 locMethod = fp->method;
10918 locAttachment = context->currentBindingAttachment;
10919
10920 context->currentBindingAttachment = locMethod->bindingAttachment;
10921
10922 locInt1 = ((CookeeIntMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
10923 (CookeeInt*) locMethod->parameterOffsets, (Char*) locals);
10924
10925 context->currentBindingAttachment = locAttachment;
10926
10927 LOCAL_INT(0) = locInt1;
10928
10929 fp += 1;
10930
10931 LOAD_STATE();
10932 LEAVE_FRAME_STUB();
10933
10934 DISPATCH;
10935
10936 OPCODE_IMPL($OPCODE_LNATIVE)
10937
10938 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
10939
10940 locMethod = fp->method;
10941 locAttachment = context->currentBindingAttachment;
10942
10943 context->currentBindingAttachment = locMethod->bindingAttachment;
10944
10945 locLong1 = ((CookeeLongMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
10946 (CookeeInt*) locMethod->parameterOffsets, (Char*) locals);
10947
10948 context->currentBindingAttachment = locAttachment;
10949
10950 LOCAL_LONG(0) = locLong1;
10951
10952 fp += 1;
10953
10954 LOAD_STATE();
10955 LEAVE_FRAME_STUB();
10956
10957 DISPATCH;
10958
10959 OPCODE_IMPL($OPCODE_FNATIVE)
10960
10961 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
10962
10963 locMethod = fp->method;
10964 locAttachment = context->currentBindingAttachment;
10965
10966 context->currentBindingAttachment = locMethod->bindingAttachment;
10967
10968 locFloat1 = ((CookeeFloatMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
10969 (CookeeInt*) locMethod->parameterOffsets, (Char*) locals);
10970
10971 context->currentBindingAttachment = locAttachment;
10972
10973 LOCAL_FLOAT(0) = locFloat1;
10974
10975 fp += 1;
10976
10977 LOAD_STATE();
10978 LEAVE_FRAME_STUB();
10979
10980 DISPATCH;
10981
10982 OPCODE_IMPL($OPCODE_DNATIVE)
10983
10984 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
10985
10986 locMethod = fp->method;
10987 locAttachment = context->currentBindingAttachment;
10988
10989 context->currentBindingAttachment = locMethod->bindingAttachment;
10990
10991 locDouble1 = ((CookeeDoubleMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
10992 (CookeeInt*) locMethod->parameterOffsets, (Char*) locals);
10993
10994 context->currentBindingAttachment = locAttachment;
10995
10996 LOCAL_DOUBLE(0) = locDouble1;
10997
10998 fp += 1;
10999
11000 LOAD_STATE();
11001 LEAVE_FRAME_STUB();
11002
11003 DISPATCH;
11004
11005 OPCODE_IMPL($OPCODE_ONATIVE)
11006
11007 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
11008
11009 locMethod = fp->method;
11010 locAttachment = context->currentBindingAttachment;
11011
11012 context->currentBindingAttachment = locMethod->bindingAttachment;
11013
11014 locObject1 = ((CookeeObjectMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
11015 (CookeeInt*) locMethod->parameterOffsets, (Char*) locals);
11016
11017 context->currentBindingAttachment = locAttachment;
11018
11019 LOCAL_OBJECT(0) = locObject1;
11020
11021 fp += 1;
11022
11023 LOAD_STATE();
11024 LEAVE_FRAME_STUB();
11025
11026 DISPATCH;
11027
11028 OPCODE_IMPL($OPCODE_NATIVESEQ)
11029
11030 context->currentFrame = fp + 1; // Make it look like we already exitted the frame.
11031
11032 locMethod = fp->method;
11033 locAttachment = context->currentBindingAttachment;
11034
11035 context->currentBindingAttachment = locMethod->bindingAttachment;
11036
11037 locObject1 = ((CookeeSequentialMethodBinding) locMethod->binding)(context, locMethod, LOCAL_OBJECT(0),
11038 (CookeeInt*) locMethod->parameterOffsets,
11039 (Char*) locals, fp->sequenceIndex,
11040 fp->sequenceLength);
11041
11042 context->currentBindingAttachment = locAttachment;
11043
11044 LOCAL_OBJECT(0) = locObject1;
11045
11046 fp += 1;
11047
11048 LOAD_STATE();
11049 LEAVE_FRAME_STUB();
11050
11051 DISPATCH;
11052
11053
11054 OPCODE_IMPL($OPCODE_UNIMPLEMENTED)
11055
11056 fp += 1;
11057 LOAD_STATE();
11058 SAVE_STATE();
11059
11060 panic(context, "Call of unimplemented method");
11061
11062 DISPATCH;
11063
11064
11065 OPCODE_IMPL($OPCODE_EXIT_EXECUTE) LOAD0();
11066
11067 SAVE_STATE();
11068 return;
11069
11070 OPCODE_IMPL($OPCODE_GLOBAL_INITIALIZED) LOAD2_UNSAFE();
11071
11072 assert(context->classStates[arg1]->globalInstance != COOKEE_NULL);
11073
11074 LOCAL_OBJECT(arg2) = context->classStates[arg1]->globalInstance;
11075
11076 DISPATCH;
11077
11078 OPCODE_IMPL($OPCODE_INVOKE_INITIALIZED) LOAD2_UNSAFE();
11079
11080 locObject1 = LOCAL_OBJECT(arg1);
11081
11082 if(locObject1 == COOKEE_NULL) {
11083 SAVE_STATE();
11084 panic(context, "Method call on null reference");
11085 }
11086
11087 PUSH_FRAME_INITIALIZED(locObject1, &methods[arg2]);
11088 ENTER_FRAME_STUB();
11089
11090 DISPATCH;
11091
11092 OPCODE_IMPL($OPCODE_INVOKESEQ_INITIALIZED) LOAD3_UNSAFE();
11093
11094 locObject1 = LOCAL_OBJECT(arg1);
11095
11096 if(locObject1 == COOKEE_NULL) {
11097 SAVE_STATE();
11098 panic(context, "Method call on null reference");
11099 }
11100
11101 PUSH_FRAME_INITIALIZED(locObject1, &methods[arg2]);
11102
11103 fp->sequenceIndex = instructionSequenceDataIndex(arg3);
11104 fp->sequenceLength = instructionSequenceDataLength(arg3);
11105
11106 ENTER_FRAME_STUB();
11107
11108 DISPATCH;
11109
11110 OPCODE_IMPL($OPCODE_INVOKE_INATIVE) LOAD3_UNSAFE();
11111
11112 SAVE_STATE();
11113
11114 locObject1 = LOCAL_OBJECT(arg1);
11115
11116 if(locObject1 == COOKEE_NULL) {
11117 panic(context, "Method call on null reference");
11118 }
11119
11120 locMethod = &methods[arg2];
11121 locAttachment = context->currentBindingAttachment;
11122
11123 context->currentBindingAttachment = locMethod->bindingAttachment;
11124
11125 locInt1 = ((CookeeIntMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11126 (CookeeInt*) locMethod->parameterOffsets,
11127 (Char*) locals + fp->nextFrameOffset);
11128
11129 context->currentBindingAttachment = locAttachment;
11130
11131 LOCAL_INT(arg3) = locInt1;
11132
11133 LEAVE_FRAME_STUB();
11134
11135 DISPATCH;
11136
11137 OPCODE_IMPL($OPCODE_INVOKE_LNATIVE) LOAD3_UNSAFE();
11138
11139 SAVE_STATE();
11140
11141 locObject1 = LOCAL_OBJECT(arg1);
11142
11143 if(locObject1 == COOKEE_NULL) {
11144 panic(context, "Method call on null reference");
11145 }
11146
11147 locMethod = &methods[arg2];
11148 locAttachment = context->currentBindingAttachment;
11149
11150 context->currentBindingAttachment = locMethod->bindingAttachment;
11151
11152 locLong1 = ((CookeeLongMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11153 (CookeeInt*) locMethod->parameterOffsets,
11154 (Char*) locals + fp->nextFrameOffset);
11155
11156 context->currentBindingAttachment = locAttachment;
11157
11158 LOCAL_LONG(arg3) = locLong1;
11159
11160 LEAVE_FRAME_STUB();
11161
11162 DISPATCH;
11163
11164 OPCODE_IMPL($OPCODE_INVOKE_FNATIVE) LOAD3_UNSAFE();
11165
11166 SAVE_STATE();
11167
11168 locObject1 = LOCAL_OBJECT(arg1);
11169
11170 if(locObject1 == COOKEE_NULL) {
11171 panic(context, "Method call on null reference");
11172 }
11173
11174 locMethod = &methods[arg2];
11175 locAttachment = context->currentBindingAttachment;
11176
11177 context->currentBindingAttachment = locMethod->bindingAttachment;
11178
11179 locFloat1 = ((CookeeFloatMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11180 (CookeeInt*) locMethod->parameterOffsets,
11181 (Char*) locals + fp->nextFrameOffset);
11182
11183 context->currentBindingAttachment = locAttachment;
11184
11185 LOCAL_FLOAT(arg3) = locFloat1;
11186
11187 LEAVE_FRAME_STUB();
11188
11189 DISPATCH;
11190
11191 OPCODE_IMPL($OPCODE_INVOKE_DNATIVE) LOAD3_UNSAFE();
11192
11193 SAVE_STATE();
11194
11195 locObject1 = LOCAL_OBJECT(arg1);
11196
11197 if(locObject1 == COOKEE_NULL) {
11198 panic(context, "Method call on null reference");
11199 }
11200
11201 locMethod = &methods[arg2];
11202 locAttachment = context->currentBindingAttachment;
11203
11204 context->currentBindingAttachment = locMethod->bindingAttachment;
11205
11206 locDouble1 = ((CookeeDoubleMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11207 (CookeeInt*) locMethod->parameterOffsets,
11208 (Char*) locals + fp->nextFrameOffset);
11209
11210 context->currentBindingAttachment = locAttachment;
11211
11212 LOCAL_DOUBLE(arg3) = locDouble1;
11213
11214 LEAVE_FRAME_STUB();
11215
11216 DISPATCH;
11217
11218 OPCODE_IMPL($OPCODE_INVOKE_ONATIVE) LOAD3_UNSAFE();
11219
11220 SAVE_STATE();
11221
11222 locObject1 = LOCAL_OBJECT(arg1);
11223
11224 if(locObject1 == COOKEE_NULL) {
11225 panic(context, "Method call on null reference");
11226 }
11227
11228 locMethod = &methods[arg2];
11229 locAttachment = context->currentBindingAttachment;
11230
11231 context->currentBindingAttachment = locMethod->bindingAttachment;
11232
11233 locObject1 = ((CookeeObjectMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11234 (CookeeInt*) locMethod->parameterOffsets,
11235 (Char*) locals + fp->nextFrameOffset);
11236
11237 context->currentBindingAttachment = locAttachment;
11238
11239 LOCAL_OBJECT(arg3) = locObject1;
11240
11241 LEAVE_FRAME_STUB();
11242
11243 DISPATCH;
11244
11245 OPCODE_IMPL($OPCODE_INVOKE_NATIVESEQ) LOAD4_UNSAFE();
11246
11247 SAVE_STATE();
11248
11249 locObject1 = LOCAL_OBJECT(arg1);
11250
11251 if(locObject1 == COOKEE_NULL) {
11252 panic(context, "Method call on null reference");
11253 }
11254
11255 locMethod = &methods[arg2];
11256 locAttachment = context->currentBindingAttachment;
11257
11258 context->currentBindingAttachment = locMethod->bindingAttachment;
11259
11260 locObject1 = ((CookeeSequentialMethodBinding) locMethod->binding)(context, locMethod, locObject1,
11261 (CookeeInt*) locMethod->parameterOffsets,
11262 (Char*) locals + fp->nextFrameOffset,
11263 instructionSequenceDataIndex(arg3),
11264 instructionSequenceDataLength(arg3));
11265
11266 context->currentBindingAttachment = locAttachment;
11267
11268 LOCAL_OBJECT(arg4) = locObject1;
11269
11270 LEAVE_FRAME_STUB();
11271
11272 DISPATCH;
11273
11274 OPCODE_IMPL($OPCODE_CHKNULL_INLINE_INVOKE) LOAD1_UNSAFE();
11275
11276 if(LOCAL_OBJECT(arg1) == COOKEE_NULL) {
11277 SAVE_STATE();
11278 panic(context, "Method call on null reference");
11279 }
11280
11281 DISPATCH;
11282
11283 OPCODE_IMPL($OPCODE_INLINE_INVOKE) LOAD0_UNSAFE();
11284
11285 // Nothing to do here...
11286
11287 DISPATCH;
11288
11289
11290 OPCODE_IMPL($OPCODE_EXECUTE_CRUMB) LOAD2_UNSAFE();
11291
11292 if(context->crumbles[arg1] != NULL) {
11293 SAVE_STATE();
11294 context->crumbles[arg1](context, (char*) locals, longLiterals, doubleLiterals);
11295 pc = pcStart + arg2;
11296
11297 if(arg2 == methodStates[fp->method->index]->codeSize) {
11298 fp += 1;
11299
11300 LOAD_STATE();
11301 LEAVE_FRAME_STUB();
11302 }
11303 }
11304
11305 DISPATCH;
11306
11307 OPCODE_IMPL($OPCODE_LIB_BUILTINS_UNSAFE_DIV_INT) LOAD3();
11308
11309 LOCAL_INT(arg3) = LOCAL_INT(arg1) / LOCAL_INT(arg2);
11310
11311 DISPATCH;
11312
11313 OPCODE_IMPL($OPCODE_LIB_BUILTINS_UNSAFE_DIV_LONG) LOAD3();
11314
11315 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) / LOCAL_LONG(arg2);
11316
11317 DISPATCH;
11318
11319 OPCODE_IMPL($OPCODE_LIB_BUILTINS_RANGE_CHECK_MIN_MAX) LOAD4();
11320
11321 locInt1 = LOCAL_INT(arg1);
11322 LOCAL_BOOL(arg4) = locInt1 >= LOCAL_INT(arg2) && locInt1 <= LOCAL_INT(arg3);
11323
11324 DISPATCH;
11325
11326 OPCODE_IMPL($OPCODE_LIB_BUILTINS_RANGE_CHECK_0_MAX) LOAD3();
11327
11328 locInt1 = LOCAL_INT(arg1);
11329 LOCAL_BOOL(arg3) = locInt1 >= 0 && locInt1 <= LOCAL_INT(arg2);
11330
11331 DISPATCH;
11332
11333 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_NOT_INT) LOAD2();
11334
11335 LOCAL_INT(arg2) = ~LOCAL_INT(arg1);
11336
11337 DISPATCH;
11338
11339 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_NOT_LONG) LOAD2();
11340
11341 LOCAL_LONG(arg2) = ~LOCAL_LONG(arg1);
11342
11343 DISPATCH;
11344
11345 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_AND_INT) LOAD3();
11346
11347 LOCAL_INT(arg3) = LOCAL_INT(arg1) & LOCAL_INT(arg2);
11348
11349 DISPATCH;
11350
11351 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_AND_LONG) LOAD3();
11352
11353 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) & LOCAL_LONG(arg2);
11354
11355 DISPATCH;
11356
11357 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_OR_INT) LOAD3();
11358
11359 LOCAL_INT(arg3) = LOCAL_INT(arg1) | LOCAL_INT(arg2);
11360
11361 DISPATCH;
11362
11363 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_OR_LONG) LOAD3();
11364
11365 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) | LOCAL_LONG(arg2);
11366
11367 DISPATCH;
11368
11369 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_XOR_INT) LOAD3();
11370
11371 LOCAL_INT(arg3) = LOCAL_INT(arg1) ^ LOCAL_INT(arg2);
11372
11373 DISPATCH;
11374
11375 OPCODE_IMPL($OPCODE_LIB_BUILTINS_BITWISE_XOR_LONG) LOAD3();
11376
11377 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) ^ LOCAL_LONG(arg2);
11378
11379 DISPATCH;
11380
11381 OPCODE_IMPL($OPCODE_LIB_BUILTINS_LSHIFT_INT) LOAD3();
11382
11383 LOCAL_INT(arg3) = LOCAL_INT(arg1) << (LOCAL_INT(arg2) & 0x1F);
11384
11385 DISPATCH;
11386
11387 OPCODE_IMPL($OPCODE_LIB_BUILTINS_LSHIFT_LONG) LOAD3();
11388
11389 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) << (LOCAL_LONG(arg2) & 0x3F);
11390
11391 DISPATCH;
11392
11393 OPCODE_IMPL($OPCODE_LIB_BUILTINS_RSHIFT_INT) LOAD3();
11394
11395 LOCAL_INT(arg3) = LOCAL_INT(arg1) >> (LOCAL_INT(arg2) & 0x1F);
11396
11397 DISPATCH;
11398
11399 OPCODE_IMPL($OPCODE_LIB_BUILTINS_RSHIFT_LONG) LOAD3();
11400
11401 LOCAL_LONG(arg3) = LOCAL_LONG(arg1) >> (LOCAL_LONG(arg2) & 0x3F);
11402
11403 DISPATCH;
11404
11405 OPCODE_IMPL($OPCODE_LIB_BUILTINS_URSHIFT_INT) LOAD3();
11406
11407 LOCAL_INT(arg3) = (Uint32) LOCAL_INT(arg1) >> (LOCAL_INT(arg2) & 0x1F);
11408
11409 DISPATCH;
11410
11411 OPCODE_IMPL($OPCODE_LIB_BUILTINS_URSHIFT_LONG) LOAD3();
11412
11413 LOCAL_LONG(arg3) = (Uint64) LOCAL_LONG(arg1) >> (LOCAL_LONG(arg2) & 0x3F);
11414
11415 DISPATCH;
11416
11417 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ABS_INT) LOAD2();
11418
11419 locInt1 = LOCAL_INT(arg1);
11420 LOCAL_INT(arg2) = locInt1 < 0 ? -locInt1 : locInt1;
11421
11422 DISPATCH;
11423
11424 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ABS_LONG) LOAD2();
11425
11426 locLong1 = LOCAL_LONG(arg1);
11427 LOCAL_LONG(arg2) = locLong1 < 0 ? -locLong1 : locLong1;
11428
11429 DISPATCH;
11430
11431 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ABS_FLOAT) LOAD2();
11432
11433 locFloat1 = LOCAL_FLOAT(arg1);
11434 LOCAL_FLOAT(arg2) = locFloat1 < 0 ? -locFloat1 : locFloat1;
11435
11436 DISPATCH;
11437
11438 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ABS_DOUBLE) LOAD2();
11439
11440 locDouble1 = LOCAL_DOUBLE(arg1);
11441 LOCAL_DOUBLE(arg2) = locDouble1 < 0 ? -locDouble1 : locDouble1;
11442
11443 DISPATCH;
11444
11445 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MIN_INT) LOAD3();
11446
11447 locInt1 = LOCAL_INT(arg1);
11448 locInt2 = LOCAL_INT(arg2);
11449
11450 LOCAL_INT(arg3) = locInt1 < locInt2 ? locInt1 : locInt2;
11451
11452 DISPATCH;
11453
11454 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MIN_LONG) LOAD3();
11455
11456 locLong1 = LOCAL_LONG(arg1);
11457 locLong2 = LOCAL_LONG(arg2);
11458
11459 LOCAL_LONG(arg3) = locLong1 < locLong2 ? locLong1 : locLong2;
11460
11461 DISPATCH;
11462
11463 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MIN_FLOAT) LOAD3();
11464
11465 locFloat1 = LOCAL_FLOAT(arg1);
11466 locFloat2 = LOCAL_FLOAT(arg2);
11467
11468 // check for NaN
11469 if(locFloat1 != locFloat1) {
11470 LOCAL_FLOAT(arg3) = locFloat1;
11471 }
11472 // no need to check if b is NaN; < will work correctly
11473 // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special
11474 else if(locFloat1 == 0 && locFloat2 == 0) {
11475 LOCAL_FLOAT(arg3) = -(-locFloat1 - locFloat2);
11476 }
11477 else {
11478 LOCAL_FLOAT(arg3) = (locFloat1 < locFloat2) ? locFloat1 : locFloat2;
11479 }
11480
11481 DISPATCH;
11482
11483 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MIN_DOUBLE) LOAD3();
11484
11485 locDouble1 = LOCAL_DOUBLE(arg1);
11486 locDouble2 = LOCAL_DOUBLE(arg2);
11487
11488 // check for NaN
11489 if(locDouble1 != locDouble1) {
11490 LOCAL_DOUBLE(arg3) = locDouble2;
11491 }
11492 // no need to check if b is NaN; < will work correctly
11493 // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special
11494 else if(locDouble1 == 0 && locDouble2 == 0) {
11495 LOCAL_DOUBLE(arg3) = -(-locDouble1 - locDouble2);
11496 }
11497 else {
11498 LOCAL_DOUBLE(arg3) = (locDouble1 < locDouble2) ? locDouble1 : locDouble2;
11499 }
11500
11501 DISPATCH;
11502
11503 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MAX_INT) LOAD3();
11504
11505 locInt1 = LOCAL_INT(arg1);
11506 locInt2 = LOCAL_INT(arg2);
11507
11508 LOCAL_INT(arg3) = locInt1 > locInt2 ? locInt1 : locInt2;
11509
11510 DISPATCH;
11511
11512 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MAX_LONG) LOAD3();
11513
11514 locLong1 = LOCAL_LONG(arg1);
11515 locLong2 = LOCAL_LONG(arg2);
11516
11517 LOCAL_LONG(arg3) = locLong1 > locLong2 ? locLong1 : locLong2;
11518
11519 DISPATCH;
11520
11521 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MAX_FLOAT) LOAD3();
11522
11523 locFloat1 = LOCAL_FLOAT(arg1);
11524 locFloat2 = LOCAL_FLOAT(arg2);
11525
11526 // check for NaN
11527 if(locFloat1 != locFloat1) {
11528 LOCAL_FLOAT(arg3) = locFloat1;
11529 }
11530 // no need to check if b is NaN; > will work correctly
11531 // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special
11532 else if(locFloat1 == 0 && locFloat2 == 0) {
11533 LOCAL_FLOAT(arg3) = locFloat1 - -locFloat2;
11534 }
11535 else {
11536 LOCAL_FLOAT(arg3) = locFloat1 > locFloat2 ? locFloat1 : locFloat2;
11537 }
11538
11539 DISPATCH;
11540
11541 OPCODE_IMPL($OPCODE_LIB_BUILTINS_MAX_DOUBLE) LOAD3();
11542
11543 locDouble1 = LOCAL_DOUBLE(arg1);
11544 locDouble2 = LOCAL_DOUBLE(arg2);
11545
11546 // check for NaN
11547 if(locDouble1 != locDouble1) {
11548 LOCAL_FLOAT(arg3) = locDouble2;
11549 }
11550 // no need to check if b is NaN; > will work correctly
11551 // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special
11552 else if(locDouble1 == 0 && locDouble2 == 0) {
11553 LOCAL_FLOAT(arg3) = locDouble1 - -locDouble2;
11554 }
11555 else {
11556 LOCAL_FLOAT(arg3) = locDouble1 > locDouble2 ? locDouble1 : locDouble2;
11557 }
11558
11559 DISPATCH;
11560
11561 OPCODE_IMPL($OPCODE_LIB_BUILTINS_REMAINER_INT) LOAD3_UNSAFE();
11562
11563 locInt1 = LOCAL_INT(arg1);
11564 locInt2 = LOCAL_INT(arg2);
11565
11566 if(locInt2 == 0) {
11567 panic(context, "Division by 0");
11568 }
11569 else if(locInt1 == 0x80000000 && locInt2 == -1) {
11570 LOCAL_INT(arg3) = 0;
11571 }
11572 else {
11573 LOCAL_INT(arg3) = locInt1 % locInt2;
11574 }
11575
11576 DISPATCH;
11577
11578 OPCODE_IMPL($OPCODE_LIB_BUILTINS_REMAINER_LONG) LOAD3_UNSAFE();
11579
11580 locLong1 = LOCAL_LONG(arg1);
11581 locLong2 = LOCAL_LONG(arg2);
11582
11583 if(locLong2 == 0) {
11584 panic(context, "Division by 0");
11585 }
11586 else if(locLong1 == 0x8000000000000000LL && locLong2 == -1) {
11587 LOCAL_LONG(arg3) = 0;
11588 }
11589 else {
11590 LOCAL_LONG(arg3) = locLong1 % locLong2;
11591 }
11592
11593 DISPATCH;
11594
11595 OPCODE_IMPL($OPCODE_LIB_BUILTINS_REMAINER_FLOAT) LOAD3();
11596
11597 locFloat1 = LOCAL_DOUBLE(arg1);
11598 locFloat2 = LOCAL_DOUBLE(arg2);
11599
11600 LOCAL_FLOAT(arg3) = locFloat2 == 0.0 ? NAN : fmodf(locFloat1, locFloat2);
11601
11602 DISPATCH;
11603
11604 OPCODE_IMPL($OPCODE_LIB_BUILTINS_REMAINER_DOUBLE) LOAD3();
11605
11606 locDouble1 = LOCAL_DOUBLE(arg1);
11607 locDouble2 = LOCAL_DOUBLE(arg2);
11608
11609 LOCAL_DOUBLE(arg3) = locDouble2 == 0.0 ? NAN : fmod(locDouble1, locDouble2);
11610
11611 DISPATCH;
11612
11613 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_INT) LOAD3_UNSAFE();
11614
11615 locObject1 = LOCAL_OBJECT(arg1);
11616 locInt1 = LOCAL_INT(arg2);
11617
11618 if(locObject1 == COOKEE_NULL) {
11619 SAVE_STATE();
11620 panic(context, "null array access");
11621 }
11622 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11623 SAVE_STATE();
11624 panic(context, "index is out of bounds");
11625 }
11626
11627 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11628 assert(locObject2 != COOKEE_NULL);
11629
11630 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11631
11632 LOCAL_INT(arg3) = ARRAY_INT(locObject2, locInt1 + locInt2);
11633
11634 DISPATCH;
11635
11636 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_LONG) LOAD3_UNSAFE();
11637
11638 locObject1 = LOCAL_OBJECT(arg1);
11639 locInt1 = LOCAL_INT(arg2);
11640
11641 if(locObject1 == COOKEE_NULL) {
11642 SAVE_STATE();
11643 panic(context, "null array access");
11644 }
11645 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11646 SAVE_STATE();
11647 panic(context, "index is out of bounds");
11648 }
11649
11650 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11651 assert(locObject2 != COOKEE_NULL);
11652
11653 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11654
11655 LOCAL_LONG(arg3) = ARRAY_LONG(locObject2, locInt1 + locInt2);
11656
11657 DISPATCH;
11658
11659 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_FLOAT) LOAD3_UNSAFE();
11660
11661 locObject1 = LOCAL_OBJECT(arg1);
11662 locInt1 = LOCAL_INT(arg2);
11663
11664 if(locObject1 == COOKEE_NULL) {
11665 SAVE_STATE();
11666 panic(context, "null array access");
11667 }
11668 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11669 SAVE_STATE();
11670 panic(context, "index is out of bounds");
11671 }
11672
11673 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11674 assert(locObject2 != COOKEE_NULL);
11675
11676 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11677
11678 LOCAL_FLOAT(arg3) = ARRAY_FLOAT(locObject2, locInt1 + locInt2);
11679
11680 DISPATCH;
11681
11682 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_DOUBLE) LOAD3_UNSAFE();
11683
11684 locObject1 = LOCAL_OBJECT(arg1);
11685 locInt1 = LOCAL_INT(arg2);
11686
11687 if(locObject1 == COOKEE_NULL) {
11688 SAVE_STATE();
11689 panic(context, "null array access");
11690 }
11691 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11692 SAVE_STATE();
11693 panic(context, "index is out of bounds");
11694 }
11695
11696 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11697 assert(locObject2 != COOKEE_NULL);
11698
11699 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11700
11701 LOCAL_DOUBLE(arg3) = ARRAY_DOUBLE(locObject2, locInt1 + locInt2);
11702
11703 DISPATCH;
11704
11705 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_GET_OBJECT) LOAD3_UNSAFE();
11706
11707 locObject1 = LOCAL_OBJECT(arg1);
11708 locInt1 = LOCAL_INT(arg2);
11709
11710 if(locObject1 == COOKEE_NULL) {
11711 SAVE_STATE();
11712 panic(context, "null array access");
11713 }
11714 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11715 SAVE_STATE();
11716 panic(context, "index is out of bounds");
11717 }
11718
11719 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11720 assert(locObject2 != COOKEE_NULL);
11721
11722 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11723
11724 LOCAL_OBJECT(arg3) = ARRAY_OBJECT(locObject2, locInt1 + locInt2);
11725
11726 DISPATCH;
11727
11728 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_INT) LOAD3_UNSAFE();
11729
11730 locObject1 = LOCAL_OBJECT(arg1);
11731 locInt1 = LOCAL_INT(arg2);
11732
11733 if(locObject1 == COOKEE_NULL) {
11734 SAVE_STATE();
11735 panic(context, "null array access");
11736 }
11737 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11738 SAVE_STATE();
11739 panic(context, "index is out of bounds");
11740 }
11741
11742 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11743 assert(locObject2 != COOKEE_NULL);
11744
11745 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11746
11747 ARRAY_INT(locObject2, locInt1 + locInt2) = LOCAL_INT(arg3);
11748
11749 DISPATCH;
11750
11751 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_LONG) LOAD3_UNSAFE();
11752
11753 locObject1 = LOCAL_OBJECT(arg1);
11754 locInt1 = LOCAL_INT(arg2);
11755
11756 if(locObject1 == COOKEE_NULL) {
11757 SAVE_STATE();
11758 panic(context, "null array access");
11759 }
11760 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11761 SAVE_STATE();
11762 panic(context, "index is out of bounds");
11763 }
11764
11765 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11766 assert(locObject2 != COOKEE_NULL);
11767
11768 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11769
11770 ARRAY_LONG(locObject2, locInt1 + locInt2) = LOCAL_LONG(arg3);
11771
11772 DISPATCH;
11773
11774 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_FLOAT) LOAD3_UNSAFE();
11775
11776 locObject1 = LOCAL_OBJECT(arg1);
11777 locInt1 = LOCAL_INT(arg2);
11778
11779 if(locObject1 == COOKEE_NULL) {
11780 SAVE_STATE();
11781 panic(context, "null array access");
11782 }
11783 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11784 SAVE_STATE();
11785 panic(context, "index is out of bounds");
11786 }
11787
11788 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11789 assert(locObject2 != COOKEE_NULL);
11790
11791 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11792
11793 ARRAY_FLOAT(locObject2, locInt1 + locInt2) = LOCAL_FLOAT(arg3);
11794
11795 DISPATCH;
11796
11797 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_DOUBLE) LOAD3_UNSAFE();
11798
11799 locObject1 = LOCAL_OBJECT(arg1);
11800 locInt1 = LOCAL_INT(arg2);
11801
11802 if(locObject1 == COOKEE_NULL) {
11803 SAVE_STATE();
11804 panic(context, "null array access");
11805 }
11806 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11807 SAVE_STATE();
11808 panic(context, "index is out of bounds");
11809 }
11810
11811 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11812 assert(locObject2 != COOKEE_NULL);
11813
11814 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11815
11816 ARRAY_DOUBLE(locObject2, locInt1 + locInt2) = LOCAL_DOUBLE(arg3);
11817
11818 DISPATCH;
11819
11820 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_AT_SET_OBJECT) LOAD3_UNSAFE();
11821
11822 locObject1 = LOCAL_OBJECT(arg1);
11823 locInt1 = LOCAL_INT(arg2);
11824
11825 if(locObject1 == COOKEE_NULL) {
11826 SAVE_STATE();
11827 panic(context, "null array access");
11828 }
11829 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11830 SAVE_STATE();
11831 panic(context, "index is out of bounds");
11832 }
11833
11834 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11835 assert(locObject2 != COOKEE_NULL);
11836
11837 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11838
11839 locObject1 = LOCAL_OBJECT(arg3);
11840
11841 if(locObject1 != COOKEE_NULL && isHeaderMarkedUnmanaged(objectToHeader(locObject1))) {
11842 if(!isHeaderMarkedUnmanaged(objectToHeader(locObject2))) {
11843 SAVE_STATE();
11844 panic(context, "Managed reference assignment to unmanaged array");
11845 }
11846 }
11847
11848 ARRAY_OBJECT(locObject2, locInt1 + locInt2) = locObject1;
11849
11850 DISPATCH;
11851
11852 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_INC_INT) LOAD3_UNSAFE();
11853
11854 locObject1 = LOCAL_OBJECT(arg1);
11855 locInt1 = LOCAL_INT(arg2);
11856
11857 if(locObject1 == COOKEE_NULL) {
11858 SAVE_STATE();
11859 panic(context, "null array access");
11860 }
11861 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11862 SAVE_STATE();
11863 panic(context, "index is out of bounds");
11864 }
11865
11866 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11867 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11868
11869 ARRAY_INT(locObject2, locInt1 + locInt2) += LOCAL_INT(arg3);
11870
11871 DISPATCH;
11872
11873 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_INC_LONG) LOAD3_UNSAFE();
11874
11875 locObject1 = LOCAL_OBJECT(arg1);
11876 locInt1 = LOCAL_INT(arg2);
11877
11878 if(locObject1 == COOKEE_NULL) {
11879 SAVE_STATE();
11880 panic(context, "null array access");
11881 }
11882 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11883 SAVE_STATE();
11884 panic(context, "index is out of bounds");
11885 }
11886
11887 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11888 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11889
11890 ARRAY_LONG(locObject2, locInt1 + locInt2) += LOCAL_LONG(arg3);
11891
11892 DISPATCH;
11893
11894 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_INC_FLOAT) LOAD3_UNSAFE();
11895
11896 locObject1 = LOCAL_OBJECT(arg1);
11897 locInt1 = LOCAL_INT(arg2);
11898
11899 if(locObject1 == COOKEE_NULL) {
11900 SAVE_STATE();
11901 panic(context, "null array access");
11902 }
11903 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11904 SAVE_STATE();
11905 panic(context, "index is out of bounds");
11906 }
11907
11908 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11909 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11910
11911 ARRAY_FLOAT(locObject2, locInt1 + locInt2) += LOCAL_FLOAT(arg3);
11912
11913 DISPATCH;
11914
11915 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_INC_DOUBLE) LOAD3_UNSAFE();
11916
11917 locObject1 = LOCAL_OBJECT(arg1);
11918 locInt1 = LOCAL_INT(arg2);
11919
11920 if(locObject1 == COOKEE_NULL) {
11921 SAVE_STATE();
11922 panic(context, "null array access");
11923 }
11924 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11925 SAVE_STATE();
11926 panic(context, "index is out of bounds");
11927 }
11928
11929 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11930 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11931
11932 ARRAY_DOUBLE(locObject2, locInt1 + locInt2) += LOCAL_DOUBLE(arg3);
11933
11934 DISPATCH;
11935
11936 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_DEC_INT) LOAD3_UNSAFE();
11937
11938 locObject1 = LOCAL_OBJECT(arg1);
11939 locInt1 = LOCAL_INT(arg2);
11940
11941 if(locObject1 == COOKEE_NULL) {
11942 SAVE_STATE();
11943 panic(context, "null array access");
11944 }
11945 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11946 SAVE_STATE();
11947 panic(context, "index is out of bounds");
11948 }
11949
11950 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11951 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11952
11953 ARRAY_INT(locObject2, locInt1 + locInt2) -= LOCAL_INT(arg3);
11954
11955 DISPATCH;
11956
11957 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_DEC_LONG) LOAD3_UNSAFE();
11958
11959 locObject1 = LOCAL_OBJECT(arg1);
11960 locInt1 = LOCAL_INT(arg2);
11961
11962 if(locObject1 == COOKEE_NULL) {
11963 SAVE_STATE();
11964 panic(context, "null array access");
11965 }
11966 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11967 SAVE_STATE();
11968 panic(context, "index is out of bounds");
11969 }
11970
11971 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11972 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11973
11974 ARRAY_LONG(locObject2, locInt1 + locInt2) -= LOCAL_LONG(arg3);
11975
11976 DISPATCH;
11977
11978 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_DEC_FLOAT) LOAD3_UNSAFE();
11979
11980 locObject1 = LOCAL_OBJECT(arg1);
11981 locInt1 = LOCAL_INT(arg2);
11982
11983 if(locObject1 == COOKEE_NULL) {
11984 SAVE_STATE();
11985 panic(context, "null array access");
11986 }
11987 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
11988 SAVE_STATE();
11989 panic(context, "index is out of bounds");
11990 }
11991
11992 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
11993 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
11994
11995 ARRAY_FLOAT(locObject2, locInt1 + locInt2) -= LOCAL_FLOAT(arg3);
11996
11997 DISPATCH;
11998
11999 OPCODE_IMPL($OPCODE_LIB_BUILTINS_ARRAY_DEC_DOUBLE) LOAD3_UNSAFE();
12000
12001 locObject1 = LOCAL_OBJECT(arg1);
12002 locInt1 = LOCAL_INT(arg2);
12003
12004 if(locObject1 == COOKEE_NULL) {
12005 SAVE_STATE();
12006 panic(context, "null array access");
12007 }
12008 else if(locInt1 < 0 || locInt1 > FIELD_INT(locObject1, LIB_ARRAY_FIELD_LENGTH)) {
12009 SAVE_STATE();
12010 panic(context, "index is out of bounds");
12011 }
12012
12013 locObject2 = FIELD_OBJECT(locObject1, LIB_ARRAY_FIELD_RAW_ARRAY);
12014 locInt2 = FIELD_INT(locObject1, LIB_ARRAY_FIELD_OFFSET);
12015
12016 ARRAY_DOUBLE(locObject2, locInt1 + locInt2) -= LOCAL_DOUBLE(arg3);
12017
12018 DISPATCH;
12019
12020
12021 INTERPRETER_END
12022
12023
12024 #undef ENTER_FRAME_STUB
12025 #undef LEAVE_FRAME_STUB
12026
12027 #undef SAVE_STATE
12028 #undef LOAD_STATE
12029
12030 #undef PUSH_FRAME
12031 #undef PUSH_FRAME_INITIALIZED
12032
12033 #undef LOAD0
12034 #undef LOAD0_UNSAFE
12035 #undef LOAD1
12036 #undef LOAD1_UNSAFE
12037 #undef LOAD2
12038 #undef LOAD2_UNSAFE
12039 #undef LOAD3
12040 #undef LOAD3_UNSAFE
12041 #undef LOAD4
12042 #undef LOAD4_UNSAFE
12043
12044 #undef LOCAL
12045 #undef LOCAL_BOOL
12046 #undef LOCAL_CHAR
12047 #undef LOCAL_INT
12048 #undef LOCAL_LONG
12049 #undef LOCAL_FLOAT
12050 #undef LOCAL_DOUBLE
12051 #undef LOCAL_OBJECT
12052
12053 #undef FIELD
12054 #undef FIELD_INT
12055 #undef FIELD_LONG
12056 #undef FIELD_FLOAT
12057 #undef FIELD_DOUBLE
12058 #undef FIELD_OBJECT
12059
12060 #undef ARRAY
12061 #undef ARRAY_INT
12062 #undef ARRAY_LONG
12063 #undef ARRAY_FLOAT
12064 #undef ARRAY_DOUBLE
12065 #undef ARRAY_OBJECT
12066}
12067
12068#undef INTERPRETER_BEGIN
12069#undef INTERPRETER_END
12070
12071#undef OPCODE_REF
12072#undef OPCODE_IMPL
12073
12074#ifndef COOKEE_INLINE_THREADING
12075 #undef DISPATCH_BASE_SET_ENTRIES
12076 #undef DISPATCH_VM_ENTRIES
12077 #undef DISPATCH_OPTIMIZATION_ENTRIES
12078#endif
12079
12080#undef DISPATCH
12081
12082static Void executeInvoke(Context* const context,
12083 const Instruction* const instruction,
12084 const CookeeObject this,
12085 const CookeeInt invokedMethodIndex,
12086 const Uint32 sequenceData) {
12087
12088 static Code buffer[MAX_INVOCATION_INSTRUCTION_LENGTH];
12089
12090 assert(reflectInstruction($OPCODE_EXIT_EXECUTE)->length == 1);
12091 assert(INVOCATION_INSTRUCTION_SEQUENCE_DATA_OPERAND + 1 < instruction->length);
12092
12093 Code* const code = buffer;
12094
12095 code[0] = instruction->opcode;
12096 code[INVOCATION_INSTRUCTION_SOURCE_OFFSET_OPERAND + 1] = 0;
12097 code[INVOCATION_INSTRUCTION_METHOD_INDEX_OPERAND + 1] = invokedMethodIndex;
12098 code[INVOCATION_INSTRUCTION_SEQUENCE_DATA_OPERAND + 1] = sequenceData;
12099 code[instruction->length] = $OPCODE_EXIT_EXECUTE;
12100
12101 StackFrame* const currentFrame = context->currentFrame;
12102 Uint8* const fakeLocals = currentFrame->locals + currentFrame->nextFrameOffset;
12103
12104 *((CookeeObject*)(fakeLocals)) = this;
12105
12106 StackFrame* const newFrame = currentFrame - 1;
12107
12108 newFrame->pc = code;
12109 newFrame->pcStart = code;
12110 newFrame->nextFrameOffset = 0;
12111 newFrame->locals = fakeLocals;
12112 newFrame->fake = true;
12113
12114 context->currentFrame = newFrame;
12115
12116 execute(context);
12117
12118 context->currentFrame += 1;
12119}
12120
12121static Void crumbPanic(Void* const ctx, const Char* const message, const Uint32 pc) {
12122 Context* const context = ctx;
12123 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12124 panic(context, message);
12125}
12126
12127static CookeeObject crumbNew(Void* const ctx, const Uint32 classIndex, const Uint32 pc) {
12128 Context* const context = ctx;
12129 const CookeeObject object = newObject(context, &context->data->classes[classIndex]);
12130
12131 if(object == COOKEE_NULL) {
12132 crumbPanic(context, "Out of memory", pc);
12133 }
12134
12135 return object;
12136}
12137
12138static CookeeObject crumbOld(Void* const ctx, const Uint32 classIndex, const Uint32 pc) {
12139 Context* const context = ctx;
12140 const CookeeObject object = oldObject(context, &context->data->classes[classIndex], context->classStates[classIndex]);
12141
12142 if(object == COOKEE_NULL) {
12143 crumbPanic(context, "Out of memory", pc);
12144 }
12145
12146 return object;
12147}
12148
12149static CookeeObject crumbTmp(Void* const ctx, const Uint32 classIndex, const Uint32 tmpIndex, const Uint32 pc) {
12150 Context* const context = ctx;
12151 const CookeeObject object = tmpObject(context, &context->data->classes[classIndex], context->classStates[classIndex],
12152 tmpIndex);
12153
12154 if(object == COOKEE_NULL) {
12155 crumbPanic(context, "Out of memory", pc);
12156 }
12157
12158 return object;
12159}
12160
12161static CookeeBool crumbIs(Void* const ctx, const CookeeObject object1, const CookeeObject object2, const Uint32 pc) {
12162 Context* const context = ctx;
12163
12164 if(object1 == object2) {
12165 return COOKEE_TRUE;
12166 }
12167 else if(object1 != COOKEE_NULL && object2 != COOKEE_NULL) {
12168 const Uint32 object1ClassIndex = getObjectClassIndex(object1);
12169
12170 if(object1ClassIndex == getObjectClassIndex(object2)) {
12171 CookeeEqualsFunction const equalityFunc = context->data->classes[object1ClassIndex].equalityFunction;
12172
12173 if(equalityFunc != NULL) {
12174 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12175 Void* const attachmentBackup = context->currentBindingAttachment;
12176
12177 lockGc(context->gc);
12178
12179 context->currentBindingAttachment = context->data->classes[object1ClassIndex].equalityFunctionAttachment;
12180 const CookeeBool retVal = equalityFunc(context, object1, object2);
12181 context->currentBindingAttachment = attachmentBackup;
12182
12183 unlockGc(context->gc);
12184
12185 return retVal;
12186 }
12187 }
12188 }
12189
12190 return COOKEE_FALSE;
12191}
12192
12193static CookeeBool crumbIsnt(Void* const ctx, const CookeeObject object1, const CookeeObject object2, const Uint32 pc) {
12194 Context* const context = ctx;
12195
12196 if(object1 != COOKEE_NULL && object2 != COOKEE_NULL) {
12197 const Uint32 object1ClassIndex = getObjectClassIndex(object1);
12198
12199 if(object1ClassIndex == getObjectClassIndex(object2)) {
12200 CookeeEqualsFunction const equalityFunc = context->data->classes[object1ClassIndex].equalityFunction;
12201
12202 if(equalityFunc != NULL) {
12203 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12204
12205 Void* const attachmentBackup = context->currentBindingAttachment;
12206
12207 lockGc(context->gc);
12208 context->currentBindingAttachment = context->data->classes[object1ClassIndex].equalityFunctionAttachment;
12209 const CookeeBool retVal = !equalityFunc(context, object1, object2);
12210 context->currentBindingAttachment = attachmentBackup;
12211 unlockGc(context->gc);
12212
12213 return retVal;
12214 }
12215 }
12216 else {
12217 return COOKEE_TRUE;
12218 }
12219 }
12220
12221 return object1 != object2;
12222}
12223
12224static Void crumbChktype(Void* const ctx, const CookeeObject object, const Uint32 classIndex, const Uint32 pc) {
12225 if(object != COOKEE_NULL) {
12226 Context* const context = ctx;
12227 const Class* const class = &context->data->classes[classIndex];
12228
12229 if(!context->data->classes[getObjectClassIndex(object)].castingTable[classIndex]) {
12230 const Class* const fromClass = &context->data->classes[getObjectClassIndex(object)];
12231
12232 Char* const str = malloc((Uint32) strlen("Instance of class %s cannot be casted to %s") +
12233 (Uint32) strlen(fromClass->signature) +
12234 (Uint32) strlen(class->signature) - 4);
12235
12236 if(str == NULL) {
12237 crumbPanic(context, "Invalid cast", pc);
12238 }
12239 else {
12240 sprintf(str, "Instance of class %s cannot be casted to %s", fromClass->signature, class->signature);
12241 crumbPanic(context, str, pc);
12242 }
12243 }
12244 }
12245}
12246
12247static CookeeObject crumbGlobal(Void* const ctx, const Uint32 classIndex, const Uint32 pc) {
12248 Context* const context = ctx;
12249 CookeeObject global = context->classStates[classIndex]->globalInstance;
12250
12251 if(global == COOKEE_NULL) {
12252 const Class* const class = &context->data->classes[classIndex];
12253 global = newObject(context, class);
12254
12255 if(global == COOKEE_NULL) {
12256 crumbPanic(context, "Out of memory", pc);
12257 }
12258
12259 context->classStates[classIndex]->globalInstance = global;
12260
12261 if(class->initializer != NULL) {
12262 // Panic can happen inside so the position needs to be saved.
12263 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12264
12265 executeInvoke(context, reflectInstruction($OPCODE_INVOKE_INITIALIZED), global, class->initializer->index, 0);
12266
12267 // GC could have happened so global needs to be refetched.
12268 global = context->classStates[classIndex]->globalInstance;
12269 }
12270 }
12271
12272 return global;
12273}
12274
12275static CookeeObject crumbText(Void* const ctx, const Uint32 literalIndex, const Uint32 pc) {
12276 return ((Context*) ctx)->textLiteralTable[literalIndex];
12277}
12278
12279static Void crumbInvoke(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12280 assert(this != COOKEE_NULL);
12281
12282 Context* const context = ctx;
12283
12284 // Panic can happen inside so the position needs to be saved.
12285 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12286
12287 executeInvoke(context, reflectInstruction($OPCODE_INVOKE_INITIALIZED), this, methodIndex, 0);
12288}
12289
12290static Void crumbAinvoke(Void* const ctx, const CookeeObject this, const Uint32 surfaceMethodIndex, const Uint32 pc) {
12291 assert(this != COOKEE_NULL);
12292
12293 Context* const context = ctx;
12294
12295 // Panic can happen inside so the position needs to be saved.
12296 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12297
12298 executeInvoke(context, reflectInstruction($OPCODE_AINVOKE), this, surfaceMethodIndex, 0);
12299}
12300
12301static Void crumbInvokeSeq(Void* const ctx,
12302 const CookeeObject this,
12303 const Uint32 methodIndex,
12304 const Uint32 sequenceIndex,
12305 const Uint32 sequenceLength,
12306 const Uint32 pc) {
12307
12308 assert(this != COOKEE_NULL);
12309
12310 Context* const context = ctx;
12311
12312 // Panic can happen inside so the position needs to be saved.
12313 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12314
12315 executeInvoke(context, reflectInstruction($OPCODE_INVOKESEQ_INITIALIZED), this, methodIndex,
12316 instructionSequenceData(sequenceIndex, sequenceLength));
12317}
12318
12319static Void crumbAinvokeSeq(Void* const ctx, const
12320 CookeeObject this,
12321 const Uint32 surfaceMethodIndex,
12322 const Uint32 sequenceIndex,
12323 const Uint32 sequenceLength,
12324 const Uint32 pc) {
12325
12326 assert(this != COOKEE_NULL);
12327
12328 Context* const context = ctx;
12329
12330 // Panic can happen inside so the position needs to be saved.
12331 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12332
12333 executeInvoke(context, reflectInstruction($OPCODE_AINVOKESEQ), this, surfaceMethodIndex,
12334 instructionSequenceData(sequenceIndex, sequenceLength));
12335}
12336
12337static CookeeInt crumbInvokeInative(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12338 assert(this != COOKEE_NULL);
12339
12340 Context* const context = ctx;
12341 Void* const attachmentBackup = context->currentBindingAttachment;
12342 const Method* const method = &context->data->methods[methodIndex];
12343
12344 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12345 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12346
12347 // Panic can happen inside so the position needs to be saved.
12348 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12349 context->currentBindingAttachment = method->bindingAttachment;
12350
12351 const CookeeInt retVal = ((CookeeIntMethodBinding) method->binding)(context, method, this, parameters, arguments);
12352
12353 context->currentBindingAttachment = attachmentBackup;
12354
12355 return retVal;
12356}
12357
12358static CookeeLong crumbInvokeLnative(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12359 assert(this != COOKEE_NULL);
12360
12361 Context* const context = ctx;
12362 Void* const attachmentBackup = context->currentBindingAttachment;
12363 const Method* const method = &context->data->methods[methodIndex];
12364
12365 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12366 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12367
12368 // Panic can happen inside so the position needs to be saved.
12369 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12370 context->currentBindingAttachment = method->bindingAttachment;
12371
12372 const CookeeLong retVal = ((CookeeLongMethodBinding) method->binding)(context, method, this, parameters, arguments);
12373
12374 context->currentBindingAttachment = attachmentBackup;
12375
12376 return retVal;
12377}
12378
12379static CookeeFloat crumbInvokeFnative(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12380 assert(this != COOKEE_NULL);
12381
12382 Context* const context = ctx;
12383 Void* const attachmentBackup = context->currentBindingAttachment;
12384 const Method* const method = &context->data->methods[methodIndex];
12385
12386 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12387 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12388
12389 // Panic can happen inside so the position needs to be saved.
12390 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12391 context->currentBindingAttachment = method->bindingAttachment;
12392
12393 const CookeeFloat retVal = ((CookeeFloatMethodBinding) method->binding)(context, method, this, parameters, arguments);
12394
12395 context->currentBindingAttachment = attachmentBackup;
12396
12397 return retVal;
12398}
12399
12400static CookeeDouble crumbInvokeDnative(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12401 assert(this != COOKEE_NULL);
12402
12403 Context* const context = ctx;
12404 Void* const attachmentBackup = context->currentBindingAttachment;
12405 const Method* const method = &context->data->methods[methodIndex];
12406
12407 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12408 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12409
12410 // Panic can happen inside so the position needs to be saved.
12411 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12412 context->currentBindingAttachment = method->bindingAttachment;
12413
12414 const CookeeDouble retVal = ((CookeeDoubleMethodBinding) method->binding)(context, method, this, parameters, arguments);
12415
12416 context->currentBindingAttachment = attachmentBackup;
12417
12418 return retVal;
12419}
12420
12421static CookeeObject crumbInvokeOnative(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12422 assert(this != COOKEE_NULL);
12423
12424 Context* const context = ctx;
12425 Void* const attachmentBackup = context->currentBindingAttachment;
12426 const Method* const method = &context->data->methods[methodIndex];
12427
12428 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12429 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12430
12431 // Panic can happen inside so the position needs to be saved.
12432 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12433 context->currentBindingAttachment = method->bindingAttachment;
12434
12435 const CookeeObject retVal = ((CookeeObjectMethodBinding) method->binding)(context, method, this, parameters, arguments);
12436
12437 context->currentBindingAttachment = attachmentBackup;
12438
12439 return retVal;
12440}
12441
12442static CookeeObject crumbInvokeNativeSeq(Void* const ctx,
12443 const CookeeObject this,
12444 const Uint32 methodIndex,
12445 const Uint32 sequenceIndex,
12446 const Uint32 sequenceLength,
12447 const Uint32 pc) {
12448 assert(this != COOKEE_NULL);
12449
12450 Context* const context = ctx;
12451 Void* const attachmentBackup = context->currentBindingAttachment;
12452 const Method* const method = &context->data->methods[methodIndex];
12453
12454 const CookeeInt* const parameters = (const CookeeInt*) method->parameterOffsets;
12455 Char* const arguments = (Char*) context->currentFrame->locals + context->currentFrame->nextFrameOffset;
12456
12457 // Panic can happen inside so the position needs to be saved.
12458 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12459 context->currentBindingAttachment = method->bindingAttachment;
12460
12461 const CookeeObject retVal = ((CookeeSequentialMethodBinding) method->binding)(context, method, this, parameters, arguments,
12462 sequenceIndex, sequenceLength);
12463
12464 context->currentBindingAttachment = attachmentBackup;
12465
12466 return retVal;
12467}
12468
12469static CookeeFloat crumbFsqrt(const CookeeFloat value) {
12470 return sqrtf(value);
12471}
12472
12473static CookeeDouble crumbDsqrt(const CookeeDouble value) {
12474 return sqrt(value);
12475}
12476
12477static Void crumbPushFrame(Void* const ctx, const CookeeObject this, const Uint32 methodIndex, const Uint32 pc) {
12478 Context* const context = ctx;
12479 StackFrame* const currentFrame = context->currentFrame;
12480
12481 const Method* const method = &context->data->methods[methodIndex];
12482 const MethodState* const methodState = context->methodStates[methodIndex];
12483
12484 Uint8* const newLocals = currentFrame->locals + currentFrame->nextFrameOffset;
12485
12486 if(newLocals + methodState->stackSize > (Uint8*)(currentFrame - 1)) {
12487 context->currentFrame->pc = context->currentFrame->pcStart + pc;
12488 panic(context, "Stack overflow");
12489 }
12490
12491 *((CookeeObject*) newLocals) = this;
12492
12493 memset(newLocals + method->parameterStackSize, 0, methodState->refLocals * sizeof(CookeeObject));
12494
12495 StackFrame* const newFrame = currentFrame - 1;
12496
12497 newFrame->pc = methodState->code;
12498 newFrame->pcStart = methodState->code;
12499 newFrame->locals = newLocals;
12500 newFrame->method = method;
12501 newFrame->nextFrameOffset = methodState->nextFrameOffset;
12502 newFrame->fake = false;
12503
12504 context->currentFrame = newFrame;
12505}
12506
12507static Void crumbPopFrame(Void* const ctx) {
12508 ((Context*) ctx)->currentFrame += 1;
12509}
12510
12511///////////////////////////////////////////////////////////////////////
12512// INTERFACE
12513///////////////////////////////////////////////////////////////////////
12514
12515// Data interface.
12516
12517CookeeData* CookeeLoad(const Char* const bytes, const Char* const endPtr) {
12518 if(bytes == NULL) {
12519 return NULL;
12520 }
12521
12522 Data* const data = calloc(1, sizeof(Data));
12523
12524 if(data == NULL) {
12525 return NULL;
12526 }
12527
12528 if(!loadData(data, bytes, endPtr)) {
12529 free(data);
12530 return NULL;
12531 }
12532
12533 return data;
12534}
12535
12536CookeeBool CookeeIsDataInUse(CookeeData* const dataHandle) {
12537 return ((Data*) dataHandle)->contexts != 0;
12538}
12539
12540Void CookeeUnload(CookeeData* dataHandle) {
12541 Data* const data = (Data*) dataHandle;
12542
12543 if(data->contexts != 0) {
12544 fprintf(stderr, "Data cannot be unloaded because it's in use\n");
12545 }
12546 else {
12547 purgeData(data);
12548 free(data);
12549 }
12550}
12551
12552CookeeClass* CookeeFindClass(CookeeData* const dataHandle, const Char* const signature) {
12553 return findClass(dataHandle, signature);
12554}
12555
12556CookeeField* CookeeFindField(CookeeData* const dataHandle, const Char* const signature) {
12557 return findField(dataHandle, signature);
12558}
12559
12560CookeeMethod* CookeeFindMethod(CookeeData* const dataHandle, const Char* const signature) {
12561 return findMethod(dataHandle, signature);
12562}
12563
12564CookeeField* CookeeFindClassFieldByName(CookeeData* const dataHandle,
12565 CookeeClass* const class,
12566 const Char* const name) {
12567
12568 return findClassFieldByName(class, name);
12569}
12570
12571CookeeField* CookeeFindClassField(CookeeData* const dataHandle,
12572 CookeeClass* const class,
12573 const Char* const signature) {
12574
12575 return findClassField(class, signature);
12576}
12577
12578CookeeMethod* CookeeFindClassMethod(CookeeData* const dataHandle,
12579 CookeeClass* const class,
12580 const Char* const signature) {
12581
12582 return findClassMethod(class, signature);
12583}
12584
12585CookeeInt CookeeClassCount(CookeeData* const dataHandle) {
12586 return ((Data*) dataHandle)->classCount - 1; // -1 because the first one is NULL.
12587}
12588
12589CookeeClass* CookeeClassAtIndex(CookeeData* const dataHandle,
12590 const CookeeInt index) {
12591
12592 return &((Data*) dataHandle)->classes[index + 1]; // +1 because the first one is NULL.
12593}
12594
12595CookeeInt CookeeFieldCount(CookeeData* const dataHandle) {
12596 return ((Data*) dataHandle)->fieldCount - 1; // -1 because the first one is NULL.
12597}
12598
12599CookeeField* CookeeFieldAtIndex(CookeeData* const dataHandle, const CookeeInt index) {
12600 return &((Data*) dataHandle)->fields[index + 1]; // +1 because the first one is NULL.
12601}
12602
12603CookeeInt CookeeMethodCount(CookeeData* const dataHandle) {
12604 return ((Data*) dataHandle)->methodCount - 1; // -1 because the first one is NULL.
12605}
12606
12607CookeeMethod* CookeeMethodAtIndex(CookeeData* const dataHandle, const CookeeInt index) {
12608 return &((Data*) dataHandle)->methods[index + 1]; // +1 because the first one is NULL.
12609}
12610
12611CookeeInt CookeeClassIndex(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12612 return ((Class*) classHandle)->index - 1; // -1 because the first one is NULL.
12613}
12614
12615const Char* CookeeClassSignature(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12616 return ((Class*) classHandle)->signature;
12617}
12618
12619const Char* CookeeClassName(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12620 return ((Class*) classHandle)->name;
12621}
12622
12623CookeeClass* CookeeClassSuper(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12624 Class* const class = classHandle;
12625
12626 if(class->superClassIndex == 0) {
12627 return NULL;
12628 }
12629
12630 return &((Data*) dataHandle)->classes[class->superClassIndex];
12631}
12632
12633CookeeMethod* CookeeClassInitializer(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12634 return ((Class*) classHandle)->initializer;
12635}
12636
12637CookeeInt CookeeClassFieldCount(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12638 return ((Class*) classHandle)->fieldCount;
12639}
12640
12641CookeeField* CookeeClassFieldAtIndex(CookeeData* const dataHandle, CookeeClass* const classHandle, const CookeeInt index) {
12642 return ((Class*) classHandle)->fields[index];
12643}
12644
12645CookeeInt CookeeClassMethodCount(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12646 return ((Class*) classHandle)->methodCount;
12647}
12648
12649CookeeMethod* CookeeClassMethodAtIndex(CookeeData* const dataHandle, CookeeClass* const classHandle, const CookeeInt index) {
12650 return ((Class*) classHandle)->methods[index];
12651}
12652
12653CookeeInt CookeeClassTmpInstanceCount(CookeeData* const dataHandle, CookeeClass* const classHandle) {
12654 return ((Class*) classHandle)->temporaryInstanceCount;
12655}
12656
12657CookeeBool CookeeIsClassCompatible(CookeeClass* const dataHandle,
12658 CookeeClass* const classHandle,
12659 CookeeClass* const checkedClass) {
12660
12661 return ((Class*) classHandle)->castingTable[((Class*) checkedClass)->index] != 0;
12662}
12663
12664CookeeInt CookeeFieldIndex(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12665 return ((Field*) fieldHandle)->index - 1; // -1 because the first one is NULL.
12666}
12667
12668CookeeClass* CookeeFieldParent(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12669 return &((Data*) dataHandle)->classes[((Field*) fieldHandle)->parentClassIndex];
12670}
12671
12672const Char* CookeeFieldSignature(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12673 return ((Field*) fieldHandle)->signature;
12674}
12675
12676const Char* CookeeFieldName(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12677 return ((Field*) fieldHandle)->name;
12678}
12679
12680CookeeType CookeeFieldType(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12681 return ((Field*) fieldHandle)->type;
12682}
12683
12684CookeeClass* CookeeFieldTypeClass(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12685 return &((Data*) dataHandle)->classes[((Field*) fieldHandle)->typeClassIndex];
12686}
12687
12688CookeeInt CookeeFieldOffset(CookeeData* const dataHandle, CookeeField* const fieldHandle) {
12689 return ((Field*) fieldHandle)->offset;
12690}
12691
12692CookeeInt CookeeMethodIndex(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12693 return ((Method*) methodHandle)->index - 1; // -1 because the first one is NULL.
12694}
12695
12696CookeeClass* CookeeMethodParent(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12697 return &((Data*) dataHandle)->classes[((Method*) methodHandle)->parentClassIndex];
12698}
12699
12700const Char* CookeeMethodSignature(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12701 return ((Method*) methodHandle)->signature;
12702}
12703
12704const Char* CookeeMethodName(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12705 return ((Method*) methodHandle)->name;
12706}
12707
12708CookeeType CookeeMethodReturnType(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12709 return ((Method*) methodHandle)->returnType;
12710}
12711
12712CookeeClass* CookeeMethodReturnTypeClass(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12713 const Uint32 classIndex = ((Method*) methodHandle)->returnTypeClassIndex;
12714
12715 if(classIndex == 0) {
12716 return &((Data*) dataHandle)->classes[((Method*) methodHandle)->parentClassIndex];
12717 }
12718 else {
12719 return &((Data*) dataHandle)->classes[classIndex];
12720 }
12721}
12722
12723CookeeBool CookeeMethodReturnsSelf(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12724 return ((Method*) methodHandle)->returnTypeClassIndex == 0;
12725}
12726
12727CookeeMethodBinding CookeeMethodBindedFunction(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12728 return ((Method*) methodHandle)->binding;
12729}
12730
12731Void* CookeeMethodBindedAttachment(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12732 return ((Method*) methodHandle)->bindingAttachment;
12733}
12734
12735CookeeMethod* CookeeMethodSuper(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12736 const CookeeInt overridedMethodIndex = ((Method*) methodHandle)->overridedMethodIndex;
12737
12738 if(overridedMethodIndex == 0) {
12739 return NULL;
12740 }
12741 else {
12742 return &((Data*) dataHandle)->methods[overridedMethodIndex];
12743 }
12744}
12745
12746CookeeParameter* CookeeMethodFindParameter(CookeeData* const dataHandle,
12747 CookeeMethod* const methodHandle,
12748 const Char* const name) {
12749
12750 return findMethodParameter(methodHandle, name);
12751}
12752
12753CookeeInt CookeeMethodParameterCount(CookeeData* const dataHandle, CookeeMethod* const methodHandle) {
12754 return ((Method*) methodHandle)->parameterCount;
12755}
12756
12757CookeeParameter* CookeeMethodParameterAtIndex(CookeeData* const dataHandle,
12758 CookeeMethod* const methodHandle,
12759 const CookeeInt index) {
12760
12761 return &((Method*) methodHandle)->parameters[index];
12762}
12763
12764
12765const Char* CookeeParameterName(CookeeData* const dataHandle, CookeeParameter* const variableHandle) {
12766 return ((Parameter*) variableHandle)->name;
12767}
12768
12769CookeeType CookeeParameterType(CookeeData* const dataHandle, CookeeParameter* const variableHandle) {
12770 return ((Parameter*) variableHandle)->type;
12771}
12772
12773CookeeClass* CookeeParameterTypeClass(CookeeData* const dataHandle, CookeeParameter* const variableHandle) {
12774 return &((Data*) dataHandle)->classes[((Parameter*) variableHandle)->typeClassIndex];
12775}
12776
12777CookeeInt CookeeParameterOffset(CookeeData* const dataHandle, CookeeParameter* const variableHandle) {
12778 return ((Parameter*) variableHandle)->offset;
12779}
12780
12781
12782// Gc interface.
12783
12784CookeeGc* CookeeCreateGc(const CookeeInt minHeapSize,
12785 const CookeeInt maxHeapSize,
12786 const CookeeInt expectedHeapSize,
12787 const CookeeInt maxLocalReferences) {
12788
12789 Gc* const gc = calloc(1, sizeof(Gc));
12790
12791 if(gc == NULL) {
12792 return NULL;
12793 }
12794
12795 if(!initializeGc(gc, minHeapSize, maxHeapSize, expectedHeapSize, maxLocalReferences)) {
12796 free(gc);
12797 return NULL;
12798 }
12799
12800 return gc;
12801}
12802
12803CookeeBool CookeeIsGcInUse(CookeeGc* const gc) {
12804 return ((Gc*) gc)->contexts != 0;
12805}
12806
12807Void CookeeDestroyGc(CookeeGc* const gcHandle) {
12808 Gc* const gc = (Gc*) gcHandle;
12809
12810 if(gc->contexts != 0) {
12811 fprintf(stderr, "Gc cannot be destroyed because it's in use\n");
12812 }
12813 else {
12814 purgeGc(gc);
12815 free(gc);
12816 }
12817}
12818
12819Void CookeeSetGcCycleFunction(CookeeGc* const gc, CookeeGcCycleFunction const cycleFunction) {
12820 ((Gc*) gc)->cycleFunction = cycleFunction;
12821}
12822
12823CookeeInt CookeeGetAllocatedBytes(CookeeContext* const context) {
12824 return getAllocatedBytes(((Context*) context)->gc);
12825}
12826
12827CookeeInt CookeeGetFreeBytes(CookeeContext* const context) {
12828 return getTotalFreeBytes(((Context*) context)->gc);
12829}
12830
12831CookeeInt CookeeGetHeapSize(CookeeContext* const context) {
12832 return getMaxUsableHeapSize(((Context*) context)->gc);
12833}
12834
12835Void CookeeTriggerGc(CookeeContext* const context) {
12836 collectGarbage(((Context*) context)->gc);
12837}
12838
12839Void CookeeShrinkHeap(CookeeContext* const context) {
12840 trimGc(((Context*) context)->gc);
12841}
12842
12843Void CookeeLockGc(CookeeContext* const context) {
12844 lockGc(((Context*) context)->gc);
12845}
12846
12847Void CookeeUnlockGc(CookeeContext* const context) {
12848 unlockGc(((Context*) context)->gc);
12849}
12850
12851CookeeBool CookeeIsGcLocked(CookeeContext* const context) {
12852 return isGcLocked(((Context*) context)->gc);
12853}
12854
12855Void CookeePushLocalRef(CookeeContext* const context, CookeeObject* const slot) {
12856 return pushLocalRef(((Context*) context)->gc, slot);
12857}
12858
12859Void CookeePopLocalRef(CookeeContext* const context) {
12860 popLocalRef(((Context*) context)->gc);
12861}
12862
12863Void CookeePopLocalRefs(CookeeContext* const context, const CookeeInt amount) {
12864 popLocalRefs(((Context*) context)->gc, amount);
12865}
12866
12867// Context interface.
12868
12869CookeeContext* CookeeCreateContext(CookeeData* const data,
12870 CookeeGc* const gc,
12871 const Char* const starterClassSignature,
12872 CookeeInt const stackSize) {
12873
12874 if(data == NULL || gc == NULL) {
12875 return NULL;
12876 }
12877
12878 Context* const context = calloc(1, sizeof(Context));
12879
12880 if(context == NULL) {
12881 return NULL;
12882 }
12883
12884 if(!initializeContext(context, data, gc, starterClassSignature, stackSize)) {
12885 free(context);
12886 return NULL;
12887 }
12888
12889 return context;
12890}
12891
12892CookeeBool CookeeExecuteContext(CookeeContext* const contextHandle) {
12893 Context* const context = (Context*) contextHandle;
12894
12895 if(context == NULL) {
12896 printf("Context cannot be NULL\n");
12897 abort();
12898 }
12899
12900 if(!validateContext(context)) {
12901 return false;
12902 }
12903
12904 if(context->executing) {
12905 execute(context);
12906 return true;
12907 }
12908 else {
12909 // If the initial class had no initializer the context does nothing.
12910 if(context->currentFrame == NULL) {
12911 return true;
12912 }
12913
12914 context->executing = true;
12915
12916 if(!setjmp(context->panicJmp)) {
12917 if(context->currentFrame->method != NULL) {
12918 const CookeeObject this = *((CookeeObject*) context->currentFrame->locals);
12919 assert(this != COOKEE_NULL);
12920
12921 context->currentFrame->nextFrameOffset = sizeof(CookeeObject);
12922
12923 executeInvoke(context, reflectInstruction($OPCODE_INVOKE), this, context->currentFrame->method->index, 0);
12924 }
12925
12926 context->executing = false;
12927 return true;
12928 }
12929 else {
12930 context->executing = false;
12931 return false;
12932 }
12933 }
12934}
12935
12936Void CookeePanic(CookeeContext* const contextHandle, const Char* const message, ...) {
12937 Context* const context = (Context*) contextHandle;
12938
12939 if(context->panicked) {
12940 return;
12941 }
12942
12943 VaList args;
12944 va_start(args, message);
12945
12946 const Int32 bufferLength = 1024;
12947 Char* str = malloc(bufferLength);
12948
12949 if(str != NULL) {
12950 const Int32 strLength = vsnprintf(str, bufferLength, message, args);
12951
12952 // We only need to resize the buffer if the length returned by vsnprintf is greater than the default buffer length.
12953 // In other case we just return the already formatted string even if it has some free space left.
12954 if(strLength >= bufferLength) {
12955 free(str);
12956 str = malloc(strLength + 1);
12957
12958 if(str != NULL) {
12959 if(vsprintf(str, message, args) < 0) {
12960 free(str);
12961 panic(context, message);
12962 }
12963 else {
12964 panic(context, str);
12965 }
12966 }
12967 else {
12968 panic(context, message);
12969 }
12970 }
12971 // vsnprintf returns a negative integer if there was an error.
12972 else if(strLength < 0) {
12973 free(str);
12974 panic(context, message);
12975 }
12976 else {
12977 panic(context, str);
12978 }
12979 }
12980 else {
12981 panic(context, message);
12982 }
12983
12984 va_end(args);
12985}
12986
12987CookeeBool CookeeIsContextCrashed(CookeeContext* const context) {
12988 return ((Context*) context)->panicked;
12989}
12990
12991const Char* CookeeGetCrashMessage(CookeeContext* const context) {
12992 return ((Context*) context)->panicMessage;
12993}
12994
12995CookeeData* CookeeContextData(CookeeContext* const context) {
12996 return ((Context*) context)->data;
12997}
12998
12999CookeeGc* CookeeContextGc(CookeeContext* const context) {
13000 return ((Context*) context)->gc;
13001}
13002
13003Void CookeeDestroyContext(CookeeContext* const context) {
13004 purgeContext(context);
13005 free(context);
13006}
13007
13008// Binding interface.
13009
13010Void CookeeBindCreateTextFunction(CookeeData* const dataHandle,
13011 CookeeCreateTextFunction const createTextFunction,
13012 Void* const attachment) {
13013
13014 Data* const data = (Data*) dataHandle;
13015
13016 if(data->contexts != 0) {
13017 return;
13018 }
13019
13020 data->createTextFunction = createTextFunction;
13021 data->createTextFunctionAttachment = attachment;
13022}
13023
13024Void CookeeBindEqualsFunction(CookeeData* const data,
13025 CookeeClass* const class,
13026 CookeeEqualsFunction const equalityFunction,
13027 Void* const attachment) {
13028
13029 if(((Data*) data)->contexts != 0) {
13030 return;
13031 }
13032
13033 ((Class*) class)->equalityFunction = equalityFunction;
13034 ((Class*) class)->equalityFunctionAttachment = attachment;
13035}
13036
13037Void CookeeUnbindCreateTextFunction(CookeeData* const dataHandle) {
13038 Data* const data = (Data*) dataHandle;
13039
13040 if(data->contexts != 0) {
13041 return;
13042 }
13043
13044 data->createTextFunction = NULL;
13045 data->createTextFunctionAttachment = NULL;
13046}
13047
13048Void CookeeUnbindEqualsFunction(CookeeData* const data, CookeeClass* const class) {
13049 if(((Data*) data)->contexts != 0) {
13050 return;
13051 }
13052
13053 ((Class*) class)->equalityFunction = NULL;
13054 ((Class*) class)->equalityFunctionAttachment = NULL;
13055}
13056
13057Void CookeeBindMethod(CookeeData* const data,
13058 CookeeMethod* const method,
13059 CookeeMethodBinding const binding,
13060 Void* const bindingAttachment) {
13061
13062 assert(data != NULL);
13063 assert(method != NULL);
13064
13065 if(((Data*) data)->contexts != 0) {
13066 return;
13067 }
13068 bindMethodImplementation(method, binding, bindingAttachment);
13069}
13070
13071Void CookeeBindBoolMethod(CookeeData* const data,
13072 CookeeMethod* const method,
13073 CookeeBoolMethodBinding const binding,
13074 Void* const bindingAttachment) {
13075
13076 if(((Data*) data)->contexts != 0) {
13077 return;
13078 }
13079 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13080}
13081
13082Void CookeeBindCharMethod(CookeeData* const data,
13083 CookeeMethod* const method,
13084 CookeeCharMethodBinding const binding,
13085 Void* const bindingAttachment) {
13086
13087 if(((Data*) data)->contexts != 0) {
13088 return;
13089 }
13090 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13091}
13092
13093Void CookeeBindIntMethod(CookeeData* const data,
13094 CookeeMethod* const method,
13095 CookeeIntMethodBinding const binding,
13096 Void* const bindingAttachment) {
13097
13098 if(((Data*) data)->contexts != 0) {
13099 return;
13100 }
13101 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13102}
13103
13104Void CookeeBindLongMethod(CookeeData* const data,
13105 CookeeMethod* const method,
13106 CookeeLongMethodBinding const binding,
13107 Void* const bindingAttachment) {
13108
13109 if(((Data*) data)->contexts != 0) {
13110 return;
13111 }
13112 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13113}
13114
13115Void CookeeBindFloatMethod(CookeeData* const data,
13116 CookeeMethod* const method,
13117 CookeeFloatMethodBinding const binding,
13118 Void* const bindingAttachment) {
13119
13120 if(((Data*) data)->contexts != 0) {
13121 return;
13122 }
13123 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13124}
13125
13126Void CookeeBindDoubleMethod(CookeeData* const data,
13127 CookeeMethod* const method,
13128 CookeeDoubleMethodBinding const binding,
13129 Void* const bindingAttachment) {
13130
13131 if(((Data*) data)->contexts != 0) {
13132 return;
13133 }
13134 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13135}
13136
13137Void CookeeBindObjectMethod(CookeeData* const data,
13138 CookeeMethod* const method,
13139 CookeeObjectMethodBinding const binding,
13140 Void* const bindingAttachment) {
13141
13142 if(((Data*) data)->contexts != 0) {
13143 return;
13144 }
13145 bindMethodImplementation(method, (CookeeMethodBinding) binding, bindingAttachment);
13146}
13147
13148Void CookeeUnbindMethod(CookeeData* const data, CookeeMethod* const method) {
13149 if(((Data*) data)->contexts != 0) {
13150 return;
13151 }
13152 unbindMethodImplementation(method);
13153}
13154
13155Void* CookeeAttachment(CookeeContext* const context) {
13156 return ((Context*) context)->currentBindingAttachment;
13157}
13158
13159Void CookeePushNativeFrame(CookeeContext* const contextHandle,
13160 const CookeeMethod* const methodHandle,
13161 const CookeeObject thisHandle) {
13162
13163 Context* const context = contextHandle;
13164 const Method* const method = methodHandle;
13165 StackFrame* const currentFrame = context->currentFrame;
13166 StackFrame* const nextFrame = currentFrame - 1;
13167
13168 Uint8* const nextFrameLocals = currentFrame->locals + currentFrame->nextFrameOffset;
13169
13170 if(nextFrameLocals + method->stackSize > (Uint8*) nextFrame) {
13171 panic(context, "Stack overflow");
13172 }
13173
13174 *((CookeeObject*) nextFrameLocals) = thisHandle;
13175
13176 nextFrame->pc = method->code;
13177 nextFrame->pcStart = method->code;
13178 nextFrame->locals = nextFrameLocals;
13179 nextFrame->method = method;
13180 nextFrame->nextFrameOffset = method->nextFrameOffset;
13181
13182 context->currentFrame = nextFrame;
13183}
13184
13185Void CookeePushNativeSequentialFrame(CookeeContext* const contextHandle,
13186 const CookeeMethod* const methodHandle,
13187 const CookeeObject thisHandle,
13188 const CookeeInt sqi,
13189 const CookeeInt sql) {
13190
13191 Context* const context = contextHandle;
13192 const Method* const method = methodHandle;
13193 StackFrame* const currentFrame = context->currentFrame;
13194 StackFrame* const nextFrame = currentFrame - 1;
13195
13196 Uint8* const nextFrameLocals = currentFrame->locals + currentFrame->nextFrameOffset;
13197
13198 if(nextFrameLocals + method->stackSize > (Uint8*) nextFrame) {
13199 panic(context, "Stack overflow");
13200 }
13201
13202 *((CookeeObject*) nextFrameLocals) = thisHandle;
13203
13204 nextFrame->pc = method->code;
13205 nextFrame->pcStart = method->code;
13206 nextFrame->locals = nextFrameLocals;
13207 nextFrame->method = method;
13208 nextFrame->nextFrameOffset = method->nextFrameOffset;
13209 nextFrame->sequenceIndex = sqi;
13210 nextFrame->sequenceLength = sql;
13211
13212 context->currentFrame = nextFrame;
13213}
13214
13215Void CookeePopNativeFrame(CookeeContext* const contextHandle) {
13216 ((Context*) contextHandle)->currentFrame -= 1;
13217}
13218
13219// Stack frame interface.
13220
13221// Structure used to save information for correctly crawling through stack since some of the frame will be inlined.
13222typedef struct StackCrawler StackCrawler;
13223struct StackCrawler {
13224
13225 // Pointer to the frame the stack crawler is currently in.
13226 StackFrame* fp;
13227
13228 // The index of the inline frame that the stack crawler is currently in.
13229 // The indexing is done starting from one, 0 indicating that we are not inside an inline frame.
13230 Uint32 ifp;
13231
13232};
13233
13234static inline Bool isPcInFrame(const InlineFrame* const frame, const Uint32 pc) {
13235 return pc > frame->offset && pc < frame->offset + frame->length;
13236}
13237
13238static StackFrame* skipFrameIfFake(Context* const context, StackFrame* const frame) {
13239 StackFrame* frameI = frame;
13240 StackFrame* const frameN = (StackFrame*) context->stackMax;
13241
13242 while(frameI != frameN && frameI->fake) {
13243 frameI += 1;
13244 }
13245
13246 return frameI;
13247}
13248
13249static Uint32 resolveCurrentInlineFrameIndex(Context* const context, StackFrame* const frame) {
13250 const Uint32 pcOffset = (Uint32)(frame->pc - frame->pcStart);
13251 Uint32 ifp = 0;
13252
13253 MethodState* const frameMethodState = context->methodStates[frame->method->index];
13254 const Uint32 n = frameMethodState->inlineFrameCount;
13255
13256 for(Uint32 i = 0; i < n; i += 1) {
13257 const InlineFrame* const iter = &frameMethodState->inlineFrames[i];
13258
13259 if(isPcInFrame(iter, pcOffset)) {
13260 ifp += 1;
13261 }
13262 else {
13263 if(pcOffset < iter->offset) {
13264 break;
13265 }
13266 }
13267 }
13268
13269 return ifp;
13270}
13271
13272static InlineFrame* resolveInlineFrame(Context* const context, StackFrame* const frame, const Uint32 ifp) {
13273 const Uint32 pcOffset = (Uint32)(frame->pc - frame->pcStart);
13274 Uint32 currentDepth = 1; // We start from one since 0 indicates not an inline frame.
13275
13276 MethodState* const frameMethodState = context->methodStates[frame->method->index];
13277 const Uint32 n = frameMethodState->inlineFrameCount;
13278
13279 for(Uint32 i = 0; i < n; i += 1) {
13280 const InlineFrame* const iter = &frameMethodState->inlineFrames[i];
13281
13282 if(isPcInFrame(iter, pcOffset)) {
13283 if(currentDepth == ifp) {
13284 return (InlineFrame*) iter;
13285 }
13286 currentDepth += 1;
13287 }
13288 else {
13289 if(pcOffset < iter->offset) {
13290 break;
13291 }
13292 }
13293 }
13294
13295 return NULL;
13296}
13297
13298static Bool initCrawler(Context* const context, StackCrawler* const stackCrawler) {
13299 stackCrawler->fp = skipFrameIfFake(context, context->currentFrame);
13300
13301 // Check if the frame is not the very top of the stack(invalid).
13302 if((Uint8*) stackCrawler->fp == context->stackMax) {
13303 return false;
13304 }
13305
13306 stackCrawler->ifp = resolveCurrentInlineFrameIndex(context, stackCrawler->fp);
13307 return true;
13308}
13309
13310CookeeStackCrawler* CookeeNewStackCrawler(CookeeContext* const contextHandle) {
13311 assert(contextHandle != NULL);
13312 Context* const context = contextHandle;
13313 StackCrawler* const stackCrawler = malloc(sizeof(stackCrawler));
13314
13315 if(stackCrawler == NULL) {
13316 return NULL;
13317 }
13318
13319 if(!initCrawler(context, stackCrawler)) {
13320 free(stackCrawler);
13321 return NULL;
13322 }
13323
13324 return stackCrawler;
13325}
13326
13327Void CookeeDeleteStackCrawler(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13328 assert(contextHandle != NULL);
13329 assert(crawlerHandle != NULL);
13330 free(crawlerHandle);
13331}
13332
13333CookeeBool CookeeCrawlUp(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13334 assert(contextHandle != NULL);
13335 assert(crawlerHandle != NULL);
13336
13337 Context* const context = contextHandle;
13338 StackCrawler* const stackCrawler = crawlerHandle;
13339
13340 if(stackCrawler->ifp == 0) {
13341 StackFrame* const newFrame = skipFrameIfFake(context, stackCrawler->fp + 1);
13342
13343 // Check if did not reach the top of the stack(invalid).
13344 if((Uint8*) newFrame == context->stackMax) {
13345 return COOKEE_FALSE;
13346 }
13347
13348 stackCrawler->fp = newFrame;
13349 stackCrawler->ifp = resolveCurrentInlineFrameIndex(context, newFrame);
13350 }
13351 else {
13352 stackCrawler->ifp -= 1;
13353 }
13354
13355 return COOKEE_TRUE;
13356}
13357
13358CookeeMethod* CookeeFrameMethod(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13359 assert(contextHandle != NULL);
13360 assert(crawlerHandle != NULL);
13361
13362 Context* const context = contextHandle;
13363 StackCrawler* const stackCrawler = crawlerHandle;
13364
13365 if(stackCrawler->ifp == 0) {
13366 return (Method*) stackCrawler->fp->method;
13367 }
13368 else {
13369 InlineFrame* const inlineFrame = resolveInlineFrame(context, stackCrawler->fp, stackCrawler->ifp);
13370 assert(inlineFrame != NULL);
13371 return (Method*) inlineFrame->method;
13372 }
13373}
13374
13375CookeeInt CookeeFrameLocation(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13376 assert(contextHandle != NULL);
13377 assert(crawlerHandle != NULL);
13378
13379 StackCrawler* const stackCrawler = crawlerHandle;
13380
13381 Uint32 iter = resolveCurrentInlineFrameIndex(contextHandle, stackCrawler->fp);
13382 const Uint32 iterN = stackCrawler->ifp;
13383 const Code* pc = stackCrawler->fp->pc - 1;
13384
13385 while(iter != iterN) {
13386 const InlineFrame* const frame = resolveInlineFrame(contextHandle, stackCrawler->fp, iter);
13387 pc = stackCrawler->fp->pcStart + frame->offset - 1;
13388 iter -= 1;
13389 }
13390
13391 return *pc;
13392}
13393
13394CookeeInt CookeeFrameSequenceIndex(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13395 assert(contextHandle != NULL);
13396 assert(crawlerHandle != NULL);
13397
13398 Context* const context = contextHandle;
13399 StackCrawler* const stackCrawler = crawlerHandle;
13400
13401 if(stackCrawler->ifp == 0) {
13402 return stackCrawler->fp->sequenceIndex;
13403 }
13404 else {
13405 InlineFrame* const inlineFrame = resolveInlineFrame(context, stackCrawler->fp, stackCrawler->ifp);
13406 assert(inlineFrame != NULL);
13407 return inlineFrame->sequenceIndex;
13408 }
13409}
13410
13411CookeeInt CookeeFrameSequenceLength(CookeeContext* const contextHandle, CookeeStackCrawler* const crawlerHandle) {
13412 assert(contextHandle != NULL);
13413 assert(crawlerHandle != NULL);
13414
13415 Context* const context = contextHandle;
13416 StackCrawler* const stackCrawler = crawlerHandle;
13417
13418 if(stackCrawler->ifp == 0) {
13419 return stackCrawler->fp->sequenceLength;
13420 }
13421 else {
13422 InlineFrame* const inlineFrame = resolveInlineFrame(context, stackCrawler->fp, stackCrawler->ifp);
13423 assert(inlineFrame != NULL);
13424 return inlineFrame->sequenceLength;
13425 }
13426}
13427
13428CookeeInt CookeeSequenceIndex(CookeeContext* const contextHandle) {
13429 assert(contextHandle != NULL);
13430
13431 StackCrawler crawler;
13432
13433 #ifdef COOKEE_DEBUG
13434 assert(initCrawler(contextHandle, &crawler));
13435 #else
13436 initCrawler(contextHandle, &crawler);
13437 #endif
13438
13439 return CookeeFrameSequenceIndex(contextHandle, &crawler);
13440}
13441
13442CookeeInt CookeeSequenceLength(CookeeContext* const contextHandle) {
13443 assert(contextHandle != NULL);
13444
13445 StackCrawler crawler;
13446
13447 #ifdef COOKEE_DEBUG
13448 assert(initCrawler(contextHandle, &crawler));
13449 #else
13450 initCrawler(contextHandle, &crawler);
13451 #endif
13452
13453 return CookeeFrameSequenceLength(contextHandle, &crawler);
13454}
13455
13456
13457// Field interface.
13458
13459
13460Void CookeeSetBoolFieldValue(CookeeContext* const context,
13461 CookeeField* const field,
13462 const CookeeObject object,
13463 const CookeeBool value) {
13464
13465 assert(((Field*) field)->type == $COOKEE_TYPE_BOOL);
13466 *(CookeeBool*)((Uint8*) object + ((Field*) field)->offset) = value;
13467}
13468
13469Void CookeeSetCharFieldValue(CookeeContext* const context,
13470 CookeeField* const field,
13471 const CookeeObject object,
13472 const CookeeChar value) {
13473
13474 assert(((Field*) field)->type == $COOKEE_TYPE_CHAR);
13475 *(CookeeChar*)((Uint8*) object + ((Field*) field)->offset) = value;
13476}
13477
13478Void CookeeSetIntFieldValue(CookeeContext* const context,
13479 CookeeField* const field,
13480 const CookeeObject object,
13481 const CookeeInt value) {
13482
13483 assert(((Field*) field)->type == $COOKEE_TYPE_INT);
13484 *(CookeeInt*)((Uint8*) object + ((Field*) field)->offset) = value;
13485}
13486
13487Void CookeeSetLongFieldValue(CookeeContext* const context,
13488 CookeeField* const field,
13489 const CookeeObject object,
13490 const CookeeLong value) {
13491
13492 assert(((Field*) field)->type == $COOKEE_TYPE_LONG);
13493 *(CookeeLong*)((Uint8*) object + ((Field*) field)->offset) = value;
13494}
13495
13496Void CookeeSetFloatFieldValue(CookeeContext* const context,
13497 CookeeField* const field,
13498 const CookeeObject object,
13499 const CookeeFloat value) {
13500
13501 assert(((Field*) field)->type == $COOKEE_TYPE_FLOAT);
13502 *(CookeeFloat*)((Uint8*) object + ((Field*) field)->offset) = value;
13503}
13504
13505Void CookeeSetDoubleFieldValue(CookeeContext* const context,
13506 CookeeField* const field,
13507 const CookeeObject object,
13508 const CookeeDouble value) {
13509
13510 assert(((Field*) field)->type == $COOKEE_TYPE_DOUBLE);
13511 *(CookeeDouble*)((Uint8*) object + ((Field*) field)->offset) = value;
13512}
13513
13514Void CookeeSetObjectFieldValue(CookeeContext* const context,
13515 CookeeField* const field,
13516 const CookeeObject object,
13517 const CookeeObject value) {
13518
13519 assert(((Field*) field)->type == $COOKEE_TYPE_OBJECT);
13520 *(CookeeObject*)((Uint8*) object + ((Field*) field)->offset) = value;
13521}
13522
13523CookeeBool CookeeGetBoolFieldValue(CookeeContext* const context,
13524 CookeeField* const field,
13525 const CookeeObject object) {
13526
13527 assert(((Field*) field)->type == $COOKEE_TYPE_BOOL);
13528 return *(CookeeBool*)((Uint8*) object + ((Field*) field)->offset);
13529}
13530
13531CookeeChar CookeeGetCharFieldValue(CookeeContext* const context,
13532 CookeeField* const field,
13533 const CookeeObject object) {
13534
13535 assert(((Field*) field)->type == $COOKEE_TYPE_CHAR);
13536 return *(CookeeChar*)((Uint8*) object + ((Field*) field)->offset);
13537}
13538
13539CookeeInt CookeeGetIntFieldValue(CookeeContext* const context,
13540 CookeeField* const field,
13541 const CookeeObject object) {
13542
13543 assert(((Field*) field)->type == $COOKEE_TYPE_INT);
13544 return *(CookeeInt*)((Uint8*) object + ((Field*) field)->offset);
13545}
13546
13547CookeeLong CookeeGetLongFieldValue(CookeeContext* const context,
13548 CookeeField* const field,
13549 const CookeeObject object) {
13550
13551 assert(((Field*) field)->type == $COOKEE_TYPE_LONG);
13552 return *(CookeeLong*)((Uint8*) object + ((Field*) field)->offset);
13553}
13554
13555CookeeFloat CookeeGetFloatFieldValue(CookeeContext* const context,
13556 CookeeField* const field,
13557 const CookeeObject object) {
13558
13559 assert(((Field*) field)->type == $COOKEE_TYPE_FLOAT);
13560 return *(CookeeFloat*)((Uint8*) object + ((Field*) field)->offset);
13561}
13562
13563CookeeDouble CookeeGetDoubleFieldValue(CookeeContext* const context,
13564 CookeeField* const field,
13565 const CookeeObject object) {
13566
13567 assert(((Field*) field)->type == $COOKEE_TYPE_DOUBLE);
13568 return *(CookeeDouble*)((Uint8*) object + ((Field*) field)->offset);
13569}
13570
13571CookeeObject CookeeGetObjectFieldValue(CookeeContext* const context,
13572 CookeeField* const field,
13573 const CookeeObject object) {
13574
13575 assert(((Field*) field)->type == $COOKEE_TYPE_OBJECT);
13576 return *(CookeeObject*)((Uint8*) object + ((Field*) field)->offset);
13577}
13578
13579// Method interface.
13580
13581char* CookeeGenerateCrumbCode(CookeeContext* const contextHandle,
13582 CookeeMethod* const methodHandle,
13583 const Char* const bindFunctionName,
13584 const Char* const executeFunctionName,
13585 const CookeeBool generateTypedefs,
13586 const CookeeBool includeCalls) {
13587
13588 Context* const context = contextHandle;
13589 Method* const method = methodHandle;
13590
13591 initializeMethod(context, method);
13592
13593 abort();
13594}
13595
13596void CookeeBindCrumb(CookeeContext* const contextHandle,
13597 CookeeMethod* const methodHandle,
13598 Void(* const crumbBindFunc)(),
13599 CookeeCrumbFunction const crumbExecuteFunction) {
13600
13601 Context* const context = contextHandle;
13602 Method* const method = methodHandle;
13603
13604 initializeMethod(context, method);
13605
13606 crumbBindFunc(crumbPanic, crumbNew, crumbOld, crumbTmp, crumbIs, crumbIsnt, crumbChktype, crumbGlobal, crumbText,
13607 crumbInvoke, crumbAinvoke, crumbInvokeSeq, crumbAinvokeSeq, crumbInvokeInative, crumbInvokeLnative,
13608 crumbInvokeFnative, crumbInvokeDnative, crumbInvokeOnative, crumbInvokeNativeSeq, crumbFsqrt, crumbDsqrt,
13609 crumbPushFrame, crumbPopFrame);
13610
13611 bindCrumbFunction(context, method, context->methodStates[method->index], crumbExecuteFunction);
13612}
13613
13614// Class interface.
13615
13616CookeeObject CookeeGlobalVariable(CookeeContext* const contextHandle, CookeeClass* const classHandle) {
13617 Context* const context = contextHandle;
13618 const Class* const class = classHandle;
13619
13620 ensureClassState(context, class->index);
13621
13622 CookeeObject global = context->classStates[class->index]->globalInstance;
13623
13624 if(global == COOKEE_NULL) {
13625 global = newObject(context, class);
13626
13627 if(global == COOKEE_NULL) {
13628 panic(context, "Out of memory");
13629 }
13630
13631 context->classStates[class->index]->globalInstance = global;
13632
13633 if(class->initializer != NULL) {
13634 executeInvoke(context, reflectInstruction($OPCODE_INVOKE), global, class->initializer->index, 0);
13635
13636 // GC could have happened so global needs to be refetched.
13637 global = context->classStates[class->index]->globalInstance;
13638 }
13639 }
13640
13641 return global;
13642}
13643
13644CookeeBool CookeeIsInstanceOf(CookeeContext* const contextHandle, CookeeClass* const classHandle, const CookeeObject object) {
13645 if(object == COOKEE_NULL) {
13646 return COOKEE_FALSE;
13647 }
13648 return ((Context*) contextHandle)->data->classes[getObjectClassIndex(object)].castingTable[((Class*) classHandle)->index];
13649}
13650
13651CookeeEqualsFunction CookeeClassEqualsFunction(CookeeContext* const contextHandle, CookeeClass* const classHandle) {
13652 return ((Class*) classHandle)->equalityFunction;
13653}
13654
13655Void* CookeeClassEqualsFunctionAttachment(CookeeContext* const contextHandle, CookeeClass* const classHandle) {
13656 return ((Class*) classHandle)->equalityFunctionAttachment;
13657}
13658
13659// Object interface.
13660
13661CookeeClass* CookeeObjectClass(CookeeContext* const contextHandle, const CookeeObject object) {
13662 return &((Context*) contextHandle)->data->classes[getObjectClassIndex(object)];
13663}
13664
13665CookeeObject CookeeNewObject(CookeeContext* const contextHandle, CookeeClass* const classHandle) {
13666 return newObject(contextHandle, classHandle);
13667}
13668
13669CookeeObject CookeeOldObject(CookeeContext* const contextHandle, CookeeClass* const classHandle) {
13670 Context* const context = contextHandle;
13671 const Class* const class = classHandle;
13672
13673 return oldObject(context, class, ensureClassState(context, class->index));
13674}
13675
13676CookeeInt CookeeUnmanagedObjectSize(CookeeClass* const classHandle) {
13677 return ((Class*) classHandle)->fullInstanceSize;
13678}
13679
13680CookeeObject CookeeInitUnmanagedObject(CookeeClass* const classHandle, void* const ptr) {
13681
13682 const Class* const class = classHandle;
13683 const Uint32 fullInstanceSize = class->fullInstanceSize;
13684
13685 Uint8* const header = ptr;
13686 const CookeeObject object = headerToObject(header);
13687
13688 initHeader(header, 0, fullInstanceSize);
13689 initInstance(object, fullInstanceSize, $COOKEE_ALLOCATION_TYPE_UNMANAGED, class->index);
13690 markHeaderUnmanaged(header);
13691
13692 return object;
13693}
13694
13695CookeeObject CookeeMallocObject(CookeeClass* const classHandle) {
13696 const Class* const class = classHandle;
13697 const Uint32 fullInstanceSize = class->fullInstanceSize;
13698
13699 Uint8* const header = malloc(fullInstanceSize);
13700
13701 if(header == NULL) {
13702 return COOKEE_NULL;
13703 }
13704
13705 const CookeeObject object = headerToObject(header);
13706
13707 initHeader(header, 0, fullInstanceSize);
13708 initInstance(object, fullInstanceSize, $COOKEE_ALLOCATION_TYPE_UNMANAGED, class->index);
13709 markHeaderUnmanaged(header);
13710
13711 return object;
13712}
13713
13714CookeeObject CookeeCallocObject(CookeeClass* const classHandle) {
13715 const Class* const class = classHandle;
13716 const Uint32 fullInstanceSize = class->fullInstanceSize;
13717
13718 Uint8* const header = calloc(1, fullInstanceSize);
13719
13720 if(header == NULL) {
13721 return COOKEE_NULL;
13722 }
13723
13724 const CookeeObject object = headerToObject(header);
13725
13726 initHeader(header, 0, fullInstanceSize);
13727 initInstance(object, fullInstanceSize, $COOKEE_ALLOCATION_TYPE_UNMANAGED, class->index);
13728 markHeaderUnmanaged(header);
13729
13730 return object;
13731}
13732
13733CookeeBool CookeeFreeObject(CookeeContext* const contextHandle, const CookeeObject object) {
13734 if(object == COOKEE_NULL) {
13735 return COOKEE_FALSE;
13736 }
13737
13738 const CookeeAllocationType allocationType = getObjectAllocationType(object);
13739
13740 switch(allocationType) {
13741 case $COOKEE_ALLOCATION_TYPE_OLD:
13742 return freeOldObject(contextHandle, object);
13743
13744 case $COOKEE_ALLOCATION_TYPE_UNMANAGED:
13745 free(objectToHeader(object));
13746 return COOKEE_NULL;
13747
13748 default:
13749 return false;
13750 }
13751}
13752
13753CookeeBool CookeeFreeUnmanaged(const CookeeObject instance) {
13754 if(instance == COOKEE_NULL) {
13755 return false;
13756 }
13757
13758 Uint8* const header = objectToHeader(instance);
13759
13760 if(isHeaderMarkedUnmanaged(header)) {
13761 free(header);
13762 return true;
13763 }
13764
13765 return false;
13766}
13767
13768CookeeBool CookeeObjectIs(CookeeContext* const contextHandle, const CookeeObject object1, const CookeeObject object2) {
13769 Context* const context = contextHandle;
13770
13771 if(object1 == object2) {
13772 return COOKEE_TRUE;
13773 }
13774 else if(object1 != COOKEE_NULL && object2 != COOKEE_NULL) {
13775 const Uint32 classIndex = getObjectClassIndex(object1);
13776
13777 if(classIndex == getObjectClassIndex(object2)) {
13778 Class* const class = &context->data->classes[classIndex];
13779 CookeeEqualsFunction const equalityFunction = class->equalityFunction;
13780
13781 if(equalityFunction != NULL) {
13782 Void* const attachmentBackup = context->currentBindingAttachment;
13783
13784 lockGc(context->gc);
13785
13786 context->currentBindingAttachment = class->equalityFunctionAttachment;
13787 const CookeeBool retVal = equalityFunction(context, object1, object2);
13788 context->currentBindingAttachment = attachmentBackup;
13789
13790 unlockGc(context->gc);
13791
13792 return retVal;
13793 }
13794 }
13795 }
13796
13797 return COOKEE_FALSE;
13798}
13799
13800CookeeBool CookeeObjectIsnt(CookeeContext* const contextHandle, const CookeeObject object1, const CookeeObject object2) {
13801 Context* const context = contextHandle;
13802
13803 if(object1 != COOKEE_NULL && object2 != COOKEE_NULL) {
13804 const Uint32 classIndex = getObjectClassIndex(object1);
13805
13806 if(classIndex == getObjectClassIndex(object2)) {
13807 Class* const class = &context->data->classes[classIndex];
13808 CookeeEqualsFunction const equalityFunction = class->equalityFunction;
13809
13810 if(equalityFunction != NULL) {
13811 Void* const attachmentBackup = context->currentBindingAttachment;
13812
13813 lockGc(context->gc);
13814
13815 context->currentBindingAttachment = class->equalityFunctionAttachment;
13816 const CookeeBool retVal = (CookeeBool) !equalityFunction(context, object1, object2);
13817 context->currentBindingAttachment = attachmentBackup;
13818
13819 unlockGc(context->gc);
13820
13821 return retVal;
13822 }
13823 }
13824 else {
13825 return COOKEE_TRUE;
13826 }
13827 }
13828
13829 return object1 != object2;
13830}
13831
13832
13833// Array interface.
13834
13835CookeeObject CookeeNewArray(CookeeContext* const contextHandle, const CookeeType itemType, const CookeeInt length) {
13836 return newArray(contextHandle, itemType, length);
13837}
13838
13839CookeeInt CookeeUnmanagedArraySize(const CookeeType itemType, const CookeeInt length) {
13840 return formatInstanceSize(length * CookeeTypeSize(itemType));
13841}
13842
13843CookeeObject CookeeInitUnmanagedArray(const CookeeType itemType,
13844 const CookeeInt length,
13845 void* const ptr) {
13846
13847 const Uint32 size = formatInstanceSize(length * CookeeTypeSize(itemType));
13848
13849 Uint8* const header = ptr;
13850 const CookeeObject object = headerToObject(header);
13851
13852 initHeader(header, 0, size);
13853 initInstance(object, size, itemType, length | ARRAY_CATEGORY_FLAG);
13854 markHeaderUnmanaged(header);
13855
13856 return object;
13857}
13858
13859CookeeObject CookeeMallocArray(const CookeeType itemType, const CookeeInt length) {
13860 const Uint32 size = formatInstanceSize(length * CookeeTypeSize(itemType));
13861
13862 Uint8* const header = malloc(size);
13863
13864 if(header == NULL) {
13865 return COOKEE_NULL;
13866 }
13867
13868 const CookeeObject object = headerToObject(header);
13869
13870 initHeader(header, 0, size);
13871 initInstance(object, size, itemType, length | ARRAY_CATEGORY_FLAG);
13872 markHeaderUnmanaged(header);
13873
13874 return object;
13875}
13876
13877CookeeObject CookeeCallocArray(const CookeeType itemType, const CookeeInt length) {
13878 const Uint32 size = formatInstanceSize(length * CookeeTypeSize(itemType));
13879
13880 Uint8* const header = calloc(1, size);
13881
13882 if(header == NULL) {
13883 return COOKEE_NULL;
13884 }
13885
13886 const CookeeObject object = headerToObject(header);
13887
13888 initHeader(header, 0, size);
13889 initInstance(object, size, itemType, length | ARRAY_CATEGORY_FLAG);
13890 markHeaderUnmanaged(header);
13891
13892 return object;
13893}
13894
13895CookeeBool CookeeIsArray(CookeeContext* const context, const CookeeObject instance) {
13896 return isArray(instance);
13897}
13898
13899CookeeType CookeeArrayType(CookeeContext* const context, const CookeeObject array) {
13900 return getArrayItemType(array);
13901}
13902
13903CookeeInt CookeeArrayLength(CookeeContext* const context, const CookeeObject array) {
13904 return getArrayLength(array);
13905}
13906
13907Void CookeeArrayLock(CookeeContext* const context, const CookeeObject array) {
13908 setArrayLockIndicator(array);
13909}
13910
13911CookeeBool CookeeArrayLocked(CookeeContext* const context, const CookeeObject array) {
13912 return isArrayLocked(array);
13913}
13914
13915Char* CookeeArrayContent(CookeeContext* const contextHandle, const CookeeObject array) {
13916 if(getArrayItemType(array) == $COOKEE_TYPE_OBJECT) {
13917 return (Char*) array;
13918 }
13919 else {
13920 return (Char*) array + COOKEE_INSTANCE_PARTITION_SIZE;
13921 }
13922}