uasm 1.0.9+2.57

A library to build the UASM compiler, for usage in build scripts.
Documentation
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