forked from Terraspace/UASM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoo.inc
559 lines (442 loc) · 14.7 KB
/
oo.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
; Allocate an array of structs (using their actual size) or an array of object pointers (8bytes per pointer).
$ARRAY MACRO arrType:REQ,sizeArr:REQ
cdef TEXTEQU <__&arrType&_def> ; If the type exists as a class/object then we allocate the array based on a pointer, otherwise normal structs allocate to their true size.
% IFDEF cdef
mov r8,8
ELSE
mov r8,sizeof(arrType)
ENDIF
imul r8,sizeArr
invoke HeapAlloc,RV(GetProcessHeap),0,rax
exitm<rax>
ENDM
; Delete an array previously allocated with $ARRAY.
$DELETEARRAY MACRO arrPtr:REQ
;mov rax,arrPtr
invoke HeapFree,RV(GetProcessHeap),0,arrPtr ;rax
ENDM
curClass TEXTEQU <> ; During declaration of classes and methods we need to track which one we're currently in.
curMethod TEXTEQU <>
CSTATIC TEXTEQU <CMETHOD> ; Todo later: we can check that cstatic type method?
INTERFACE MACRO CName:REQ
curClass TEXTEQU <CName>
@CatStr(CName, < STRUCT >)
__0 dq 0 ; These are placeholders as no interface can actually be invoked/instantiated, so this is effectively a dummy vtable.
__1 dq 0 ; These first 4 entries relate to ctor, dtor, release and refCount.
__2 dq 0 ; Further interface methods are added with CVIRTUAL.
__3 dq 0
ENDM
ENDINTERFACE MACRO
curClass ENDS
ENDM
CVIRTUAL MACRO method:REQ, protoDef:VARARG
LOCAL sz1, sz2
pDef TEXTEQU <TYPEDEF PROTO thisPtr:QWORD>
IFNB <protoDef>
pDef CATSTR pDef,<,>,<&protoDef>
ENDIF
sz2 CATSTR <_>, curClass, <_&method>, <Pto> ;_curClass_methodPto
% &sz2 &pDef
% sz1 typedef PTR &sz2
% method sz1 0 ; set to 0 as its virtual and cannot be invoked directly on an interface. (This creates a vtable entry with 0 as it's value).
ENDM
CLASS MACRO CName:REQ
% __&CName&_def EQU 1
curClass TEXTEQU <CName>
@CatStr(CName, < STRUCT >)
ctorS TEXTEQU <ctor dq offset _&CName&_Init>
dtorS TEXTEQU <dtor dq offset _&CName&_Destroy>
relS TEXTEQU <release dq offset _&CName&_Release>
ctorS
dtorS
relS
_refCount dq 0
ENDM
ENDCLASS MACRO
curClass ENDS
.code
align 16
rproc TEXTEQU <_&curClass&_Release PROC FRAME thisPtr:QWORD>
% rproc
assume rcx:ptr curClass
dec [rcx]._refCount
assume rcx:nothing
ret
rproce TEXTEQU <_&curClass&_Release ENDP>
% rproce
.data
align 16
% _stat&curClass& curClass <> ; We create a static version of the class template STRUCT to allow for assembly/generation of labels, addresses and static values.
; These can be copied to an instance via NEW. This also populates method pointers in vtbl and correct prototypes for function pointers.
; We use this to create a PTR to Class type, so thisPtr can be properly typed as first argument to methods.
ptrDefS TEXTEQU <psr>
ptrDefS CATSTR ptrDefS,<&curClass&>,< TYPEDEF PTR >,<&curClass&>
% ptrDefS
.code
; We assume methods will follow class definition.
ENDM
CMETHOD MACRO method:REQ
LOCAL sz1, sz2
sz2 CATSTR <_>, curClass, <_&method>, <Pto>
% sz1 typedef PTR &sz2
% method sz1 offset _&curClass&_&method& ; By default the vtable entry points to the address of the actual method procedure.
ENDM
METHOD MACRO className:REQ, method:REQ, usesStr:REQ, args:VARARG
curClass TEXTEQU <className>
curMethod TEXTEQU <method>
;Direct invocation proto.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,< PROTO thisPtr:psr>,<&className&>
IFNB <args>
fnex CATSTR fnex,<,>,<&args&>
ELSE
ENDIF
fnex
;vtbl invocation proto.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,<Pto TYPEDEF PROTO thisPtr:psr>,<&className&>
IFNB <args>
fnex CATSTR fnex,<,>,<&args&>
ELSE
ENDIF
fnex
;Method proc header.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,< PROC FRAME >,<&usesStr&>, < thisPtr:psr>,<&className&>
IFNB <args>
fnex CATSTR fnex,<,>,<&args&>
ELSE
ENDIF
assume rcx:ptr curClass
align 16
fnex
ENDM
STATICMETHOD MACRO className:REQ, method:REQ, args:VARARG
curClass TEXTEQU <className>
curMethod TEXTEQU <method>
;Direct invocation proto.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,< PROTO>
IFNB <args>
fnex CATSTR fnex,< >,<&args&>
ELSE
ENDIF
fnex
;vtbl invocation proto.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,<Pto TYPEDEF PROTO>
IFNB <args>
fnex CATSTR fnex,< >,<&args&>
ELSE
ENDIF
fnex
;Method proc header.
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex CATSTR fnex,< PROC FRAME USES rsi rdi rbx r10>
IFNB <args>
fnex CATSTR fnex,< >,<&args&>
ELSE
ENDIF
assume rcx:ptr curClass
align 16
fnex
ENDM
ENDMETHOD MACRO
assume rcx:nothing
fnex TEXTEQU <_>
fnex CATSTR fnex,curClass
fnex CATSTR fnex,<_>
fnex CATSTR fnex,curMethod
fnex CATSTR fnex,< ENDP>
fnex
ENDM
; Replacement for LOCAL directive when declaring an object pointer
; -> This allows declaration of a generic type like List<String> with <> supported (macros remove these .. whereas normal LOCAL wont accept it)
$DECLARE MACRO varName:REQ, typeName:VARARG
ldef TEXTEQU <LOCAL &varName&>
ldef CATSTR ldef,<:>
ldef CATSTR ldef,<typeName>
% ldef
ENDM
; Used inside a static method code-body to acquire a reference to the static class (it's backing struct).
$STATICREF MACRO reg:REQ
% lea reg,_stat&curClass&
ENDM
$ACQUIRE MACRO objPtr
mov rax,objPtr
inc qword ptr [rax+24] ; Increment instance' ref count.
ENDM
$RELEASE MACRO objPtr
mov rax,objPtr
dec qword ptr [rax+24] ; Decrement instance' ref count.
ENDM
$NEW MACRO className:REQ, ctorArgs:VARARG
mov r15,sizeof(className)+16
invoke HeapAlloc,RV(GetProcessHeap),0,r15
MEMALIGN rax,16 ; Ensure the object pointer is allocated to be 16byte aligned. This allows use of XMM types as properties/members etc.
.if(rax != 0)
mov rdi,rax
lea rsi,_stat&className
movdqa xmm0,[rsi] ; All objects are at least 32bytes.. dtor/ctor/release/refcount.
movdqa xmm1,[rsi+16]
movdqa [rdi],xmm0
movdqa [rdi+16],xmm1
add rsi,32
add rdi,32
mov rcx,sizeof(className)-32 ; Transfer balance of objects statics.
rep movsb
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<Init>
IFNB <ctorArgs>
fnex2 TEXTEQU <invoke fnex,rax,ctorArgs>
ELSE
fnex2 TEXTEQU <invoke fnex,rax>
ENDIF
fnex2
.endif
exitm<rax>
ENDM
$RBXNEW MACRO className:REQ, ctorArgs:VARARG
mov r15,sizeof(className)+16
invoke HeapAlloc,RV(GetProcessHeap),0,r15
MEMALIGN rax,16 ; Ensure the object pointer is allocated to be 16byte aligned. This allows use of XMM types as properties/members etc.
.if(rax != 0)
mov rdi,rax
lea rsi,_stat&className
movdqa xmm0,[rsi] ; All objects are at least 32bytes.. dtor/ctor/release/refcount.
movdqa xmm1,[rsi+16]
movdqa [rdi],xmm0
movdqa [rdi+16],xmm1
add rsi,32
add rdi,32
mov rcx,sizeof(className)-32 ; Transfer balance of objects statics.
rep movsb
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<Init>
IFNB <ctorArgs>
fnex2 TEXTEQU <invoke fnex,rax,ctorArgs>
ELSE
fnex2 TEXTEQU <invoke fnex,rax>
ENDIF
fnex2
mov rbx,rax
.endif
exitm<rbx>
ENDM
A number of classes need to implement an iterator of sorts. As we have no way to utilize they array [] operators so a class internally implements a method "Items" which performs
a bounds checked return of the correct type (ptr,dword,word etc).
However the system can lead to ugly looking code when used inline $v(objPtr,List,Items,0) instead of objPtr[0]. To clean this up we have 2 options, a piece of code that directly probes the internal
array (this would be fast, but requires all objects to ensure their internal array type has the same name and item size would need to be accounted.. which isn't great..
for Lists of any type it's itemsPtr) or we can just wrap the Items call with a sneaky macro? $_(objPtr,0) ..
To allow this to work without a type specified the Items method MUST BE THE FIRST so we can use the IteratorInterface type ptr.
$ITEM MACRO objPtr:REQ,idx:REQ
exitm<[$v(objPtr,Iterator,Items,idx)]>
ENDM
$ITEMR MACRO objPtr:REQ,idx:REQ
exitm<$v(objPtr,Iterator,Items,idx)>
ENDM
; Non Inline Direct Method Call.
$INVOKE MACRO className:REQ, method:REQ, objPtr:REQ, args:VARARG
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
IFNB <args>
fnex2 TEXTEQU <invoke fnex,&objPtr&,&args&>
ELSE
fnex2 TEXTEQU <invoke fnex,&objPtr&>
ENDIF
fnex2
ENDM
Non Inline Vtable indirect method call.
$VINVOKE MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov r15, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <r15>
.ERR <r15 is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [r15].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [r15].&Interface.&Function), pInterface
ENDIF
ENDIF
ENDM
$V MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov r15, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <r15>
.ERR <r15 is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [r15].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [r15].&Interface.&Function), pInterface
ENDIF
ENDIF
exitm<rax>
ENDM
$VD MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov rax, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <rax>
.ERR <rax is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface
ENDIF
ENDIF
exitm<eax>
ENDM
$VW MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov rax, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <rax>
.ERR <rax is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface
ENDIF
ENDIF
exitm<ax>
ENDM
$VB MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov rax, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <rax>
.ERR <rax is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface
ENDIF
ENDIF
exitm<al>
ENDM
$VF MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
InterfacePtr TEXTEQU <_>
InterfacePtr CATSTR InterfacePtr,<&Interface>,<_>,<&Function>,<Pto>
IF (OPATTR (pInterface)) AND 00010000b
IFNB <args>
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [&pInterface].&Interface.&Function), pInterface
ENDIF
ELSE
mov rax, pInterface
IFNB <args>
FOR arg, <args>
IFIDNI <&arg>, <rax>
.ERR <rax is not allowed as a Method parameter with indirect object label>
ENDIF
ENDM
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface, &args
ELSE
invoke (InterfacePtr PTR [rax].&Interface.&Function), pInterface
ENDIF
ENDIF
exitm<xmm0>
ENDM
; Allow inline call of a direct method. MOV RAX,$I(String,Parse,CStr("test"))
$I MACRO className:REQ, method:REQ, objPtr:REQ, args:VARARG
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex2 TEXTEQU <invoke fnex,&objPtr&,&args&>
fnex2
exitm<rax>
ENDM
; Allow inline call of a static method.
$STATIC MACRO className:REQ, method:REQ, args:VARARG
fnex TEXTEQU <_>
fnex CATSTR fnex,<&className&>
fnex CATSTR fnex,<_>
fnex CATSTR fnex,<&method&>
fnex2 TEXTEQU <invoke fnex,&args&>
fnex2
exitm<rax>
ENDM
; Delete an object.
$DELETE MACRO objPtr:REQ
mov rax,objPtr
call qword ptr [rax+8] ; Call destructor.
invoke HeapFree,RV(GetProcessHeap),0,objPtr ; Free memory.
ENDM