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 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
|
/**
\page doc_adv_jit How to build a JIT compiler
AngelScript doesn't provide a built-in JIT compiler, instead it permits an external JIT compiler to be implemented
through a public interface.
To use JIT compilation, the scripts must be compiled with a few extra instructions that provide hints to the JIT compiler
and also entry points so that the VM will know when to pass control to the JIT compiled function. By default this is
turned off, and must thus be turned on by setting the engine property \ref asEP_INCLUDE_JIT_INSTRUCTIONS.
If the application sets the \ref asIJITCompiler "JIT compiler" with \ref asIScriptEngine::SetJITCompiler "SetJITCompiler"
AngelScript will automatically invoke it to provide the \ref asJITFunction "JIT functions" with each compilation or
\ref doc_adv_precompile "loading of pre-compiled bytecode".
\section doc_adv_jit_3 The structure of the JIT function
The \ref asJITFunction "JIT compiled function" must follow certain rules in order to behave well with the virtual machine. The intention
is that the VM will pass the control to the JIT function, and when the execution is to be suspended the JIT function
returns the control to the VM, updating the internal state of the VM so that the VM can resume the execution when
requested. Each time the JIT function returns control to the VM it must make sure that the \ref asSVMRegisters "VM registers" and stack values
have been updated according to the code that was executed.
The byte code will have a special instruction, \ref asBC_JitEntry "JitEntry", which defines the positions where the VM
can pass the control to the JIT function. These are usually placed for every script statement, and after each instruction
that calls another function. This implies that the JIT compiled function needs to be able to start the execution at
different points based on the argument in the JitEntry instruction. The value of the argument is defined by the JIT compiler
and how it is interpreted is also up to the JIT compiler, with the exception of 0 that means that the control should not be
passed to the JIT function.
Some byte code instructions are not meant to be converted into native code. These are usually the ones that have a more
global effect on the VM, e.g. the instructions that setup a call to a new script function, or that return from a previous
instruction. When these functions are encountered, the JIT function should return the control to the VM, and then the VM
will execute the instruction.
Other byte code instructions may be partially implemented by the JIT function, for example those that can throw an exception
based on specific conditions. One such example is the instructions for divisions, if the divider is 0 the VM will set
an exception and abort the execution. For these instructions the JIT compiler should preferrably implement the condition
that doesn't throw an exception, and if an exception is to be thrown the JIT function will instead break out to the VM.
The following shows a possible structure of a JIT compiled function:
<pre>
void jitCompiledFunc(asSVMRegisters *regs, asPWORD jitArg)
{
Read desired VM registers into CPU registers.
Jump to the current position of the function based on the 'jitArg' argument.
1:
Execute code in block 1.
Jump to exit if an illegal operation is done, e.g. divide by zero.
Jump to exit if block ends with an instruction that should not be executed by JIT function.
2:
...
3:
...
exit:
Update the VM registers before returning control to VM.
If necessary the function can invoke the methods of the context informed
in the regs, e.g. to suspend the execution, or to set a script exception.
}
</pre>
\section doc_adv_jit_2 Traversing the byte code
\code
int CJITCompiler::CompileFunction(asIScriptFunction *func, asJITFunction *output)
{
bool success = StartNewCompilation();
// Get the script byte code
asUINT length;
asDWORD *byteCode = func->GetByteCode(&length);
asDWORD *end = byteCode + length;
while( byteCode < end )
{
// Determine the instruction
asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode);
switch( op )
{
// Translate each byte code instruction into native code.
// The codes that cannot be translated should return the control
// to the VM, so that it can continue the processing. When
// the VM encounters the next JitEntry instruction it will
// transfer the control back to the JIT function.
...
case asBC_JitEntry:
// Update the argument for the JitEntry instruction with
// the argument that should be sent to the jit function.
// Remember that 0 means that the VM should not pass
// control to the JIT function.
asBC_PTRARG(byteCode) = DetermineJitEntryArg();
break;
}
// Move to next instruction
byteCode += asBCTypeSize[asBCInfo[op].type];
}
if( success )
{
*output = GetCompiledFunction();
return 0;
}
return -1;
}
\endcode
The following macros should be used to read the arguments from the bytecode instruction.
The layout of the arguments is determined from the \ref asBCInfo array.
- \ref asBC_DWORDARG
- \ref asBC_INTARG
- \ref asBC_QWORDARG
- \ref asBC_FLOATARG
- \ref asBC_PTRARG
- \ref asBC_WORDARG0
- \ref asBC_WORDARG1
- \ref asBC_SWORDARG0
- \ref asBC_SWORDARG1
- \ref asBC_SWORDARG2
What each \ref asEBCInstr "byte code" instruction does is described in \ref doc_adv_jit_1, but the exact
implementation of each byte code instruction is best determined from the implementation
in the VM, i.e. the asCScriptContext::ExecuteNext method.
\page doc_adv_jit_1 Byte code instructions
This page gives a brief description of each of the byte code instructions that the virtual machine has.
- \ref doc_adv_jit_1_1
- \ref doc_adv_jit_1_2
- \ref doc_adv_jit_1_3
- \ref doc_adv_jit_1_4
- \ref doc_adv_jit_1_5
- \ref doc_adv_jit_1_6
- \ref doc_adv_jit_1_7
- \ref doc_adv_jit_1_8
- \ref doc_adv_jit_1_9
- \ref doc_adv_jit_1_10
\section doc_adv_jit_1_1 Object management
Perform a bitwise copy of a memory buffer to another
- \ref asBC_COPY
Push the address and length of a string on the stack
- \ref asBC_STR
Allocate the memory for an object and setup the VM to execute the constructor
- \ref asBC_ALLOC
Release the memory of an object or list buffer
- \ref asBC_FREE
Move the address in an object variable to the object register. The address in the variable is then cleared.
- \ref asBC_LOADOBJ
Move the address from the object register to an object variable. The address in the object register is then cleared.
- \ref asBC_STOREOBJ
Copy the object handle from one address to another. The reference count of the object is updated to reflect the copy.
- \ref asBC_REFCPY
Copy the object handle on stack to a handle in a variable. The reference count of the object is updated to reflect the copy.
- \ref asBC_RefCpyV
Push the pointer of an object type on the stack
- \ref asBC_OBJTYPE
Push the type id on the stack
- \ref asBC_TYPEID
Pop an address to a script object from the stack. If the desired cast can be made store the address in the object register.
- \ref asBC_Cast
Push the function pointer on the stack
- \ref asBC_FuncPtr
Load the address to a property of the object into the value register. Substitutes the sequence PshV4/8, ADDSi, PopRPtr.
- \ref asBC_LoadThisR
- \ref asBC_LoadRObjR
Load the address to a property of a value object into the value register. Substitutes the sequence PSF, ADDSi, PopRPtr.
- \ref asBC_LoadVObjR
\section doc_adv_jit_1_2 Math instructions
Negate the value in the variable. The original value is overwritten.
- \ref asBC_NEGi
- \ref asBC_NEGf
- \ref asBC_NEGd
- \ref asBC_NEGi64
Perform the operation with the value of two variables and store the result in a third variable.
- \ref asBC_ADDi
- \ref asBC_SUBi
- \ref asBC_MULi
- \ref asBC_DIVi
- \ref asBC_MODi
- \ref asBC_POWi
- \ref asBC_POWu
- \ref asBC_ADDf
- \ref asBC_SUBf
- \ref asBC_MULf
- \ref asBC_DIVf
- \ref asBC_MODf
- \ref asBC_POWf
- \ref asBC_ADDd
- \ref asBC_SUBd
- \ref asBC_MULd
- \ref asBC_DIVd
- \ref asBC_MODd
- \ref asBC_POWd
- \ref asBC_POWdi
- \ref asBC_ADDi64
- \ref asBC_SUBi64
- \ref asBC_MULi64
- \ref asBC_DIVi64
- \ref asBC_MODi64
- \ref asBC_POWi64
- \ref asBC_POWu64
Perform the operation with a constant value and the value of the variable. The original value is overwritten.
- \ref asBC_ADDIi
- \ref asBC_SUBIi
- \ref asBC_MULIi
- \ref asBC_ADDIf
- \ref asBC_SUBIf
- \ref asBC_MULIf
\section doc_adv_jit_1_3 Bitwise instructions
Perform a boolean not operation on the value in the variable. The original value is overwritten.
- \ref asBC_NOT
Perform a bitwise complement on the value in the variable. The original value is overwritten.
- \ref asBC_BNOT
- \ref asBC_BNOT64
Perform the operation with the value of two variables and store the result in a third variable.
- \ref asBC_BAND
- \ref asBC_BOR
- \ref asBC_BXOR
- \ref asBC_BAND64
- \ref asBC_BOR64
- \ref asBC_BXOR64
- \ref asBC_BSLL
- \ref asBC_BSRL
- \ref asBC_BSRA
- \ref asBC_BSLL64
- \ref asBC_BSRL64
- \ref asBC_BSRA64
\section doc_adv_jit_1_4 Comparisons
Compare the value of two variables and store the result in the value register.
- \ref asBC_CMPi
- \ref asBC_CMPu
- \ref asBC_CMPf
- \ref asBC_CMPd
- \ref asBC_CMPi64
- \ref asBC_CMPu64
- \ref asBC_CmpPtr
Compare the value of a variable with a constant and store the result in the value register.
- \ref asBC_CMPIi
- \ref asBC_CMPIu
- \ref asBC_CMPIf
Test the value in the value register. Update the value register according to the result.
- \ref asBC_TZ
- \ref asBC_TNZ
- \ref asBC_TS
- \ref asBC_TNS
- \ref asBC_TP
- \ref asBC_TNP
\section doc_adv_jit_1_5 Type conversions
Convert the value in the variable. The original value is overwritten.
- \ref asBC_iTOb
- \ref asBC_iTOw
- \ref asBC_sbTOi
- \ref asBC_swTOi
- \ref asBC_ubTOi
- \ref asBC_uwTOi
- \ref asBC_iTOf
- \ref asBC_fTOi
- \ref asBC_uTOf
- \ref asBC_fTOu
- \ref asBC_dTOi64
- \ref asBC_dTOu64
- \ref asBC_i64TOd
- \ref asBC_u64TOd
Convert the value of a variable and store the result in another variable.
- \ref asBC_dTOi
- \ref asBC_dTOu
- \ref asBC_dTOf
- \ref asBC_iTOd
- \ref asBC_uTOd
- \ref asBC_fTOd
- \ref asBC_i64TOi
- \ref asBC_i64TOf
- \ref asBC_u64TOf
- \ref asBC_uTOi64
- \ref asBC_iTOi64
- \ref asBC_fTOi64
- \ref asBC_fTOu64
\section doc_adv_jit_1_6 Increment and decrement
Increment or decrement the value pointed to by the address in the value register.
- \ref asBC_INCi8
- \ref asBC_DECi8
- \ref asBC_INCi16
- \ref asBC_DECi16
- \ref asBC_INCi
- \ref asBC_DECi
- \ref asBC_INCi64
- \ref asBC_DECi64
- \ref asBC_INCf
- \ref asBC_DECf
- \ref asBC_INCd
- \ref asBC_DECd
Increment or decrement the value in the variable.
- \ref asBC_IncVi
- \ref asBC_DecVi
\section doc_adv_jit_1_7 Flow control
Setup the VM to begin execution of the other script function
- \ref asBC_CALL
- \ref asBC_CALLINTF
- \ref asBC_CALLBND
- \ref asBC_CallPtr
Setup the VM to return to the calling function
- \ref asBC_RET
Make an unconditional jump to a relative position
- \ref asBC_JMP
Make a jump to a relative position depending on the value in the value register
- \ref asBC_JZ
- \ref asBC_JNZ
- \ref asBC_JS
- \ref asBC_JNS
- \ref asBC_JP
- \ref asBC_JNP
- \ref asBC_JMPP
- \ref asBC_JLowZ
- \ref asBC_JLowNZ
Call an application registered function
- \ref asBC_CALLSYS
- \ref asBC_Thiscall1
Save the state and suspend execution, then return control to the application
- \ref asBC_SUSPEND
Give control of execution to the JIT compiled function
- \ref asBC_JitEntry
\section doc_adv_jit_1_8 Stack and data management
Push a constant value on the stack.
- \ref asBC_PshC4
- \ref asBC_PshC8
- \ref asBC_PshNull
Push the stack frame pointer on the stack.
- \ref asBC_PSF
Swap the top values on the stack.
- \ref asBC_SwapPtr
Dereference top pointer on stack. Raises exception if pointer is null.
- \ref asBC_RDSPtr
Add an offset to the top address on the stack. Raises exception if address is null.
- \ref asBC_ADDSi
Push the value of a variable on the stack.
- \ref asBC_PshV4
- \ref asBC_PshV8
- \ref asBC_PshVPtr
Initialize the value of a variable with a constant.
- \ref asBC_SetV1
- \ref asBC_SetV2
- \ref asBC_SetV4
- \ref asBC_SetV8
- \ref asBC_ClrVPtr
Copy the value of one variable to another.
- \ref asBC_CpyVtoV4
- \ref asBC_CpyVtoV8
Validate that an expected pointer is not null.
- \ref asBC_CHKREF
- \ref asBC_ChkRefS
- \ref asBC_ChkNullV
- \ref asBC_ChkNullS
Push the variable index with the size of a pointer on the stack.
- \ref asBC_VAR
Replace a variable index on the stack with an address.
- \ref asBC_GETREF
- \ref asBC_GETOBJ
- \ref asBC_GETOBJREF
Pop and discard an address from the stack.
- \ref asBC_PopPtr
Pop or push an address to or from the value register.
- \ref asBC_PopRPtr
- \ref asBC_PshRPtr
Copy a value between value register and a variable.
- \ref asBC_CpyVtoR4
- \ref asBC_CpyVtoR8
- \ref asBC_CpyRtoV4
- \ref asBC_CpyRtoV8
Copy a value from a variable to the address held in the value register
- \ref asBC_WRTV1
- \ref asBC_WRTV2
- \ref asBC_WRTV4
- \ref asBC_WRTV8
Copy a value from the address held in the value register to a variable
- \ref asBC_RDR1
- \ref asBC_RDR2
- \ref asBC_RDR4
- \ref asBC_RDR8
Load the address of the variable into the value register
- \ref asBC_LDV
Clear the upper bytes of the value register
- \ref asBC_ClrHi
\section doc_adv_jit_1_9 Global variables
Push the value of a global variable on the stack
- \ref asBC_PshG4
- \ref asBC_PshGPtr
Load the address of a global variable into the value register
- \ref asBC_LDG
Load the address of a global variable into the value register and copy the value of the global variable to local variable
- \ref asBC_LdGRdR4
Copy a value between local variable and global variable.
- \ref asBC_CpyVtoG4
- \ref asBC_CpyGtoV4
Push the address of the global variable on the stack.
- \ref asBC_PGA
Initialize the variable of a global variable with a constant.
- \ref asBC_SetG4
\section doc_adv_jit_1_10 Initialization list management
Allocates the memory for the initialization list buffer
- \ref asBC_AllocMem
Sets the number of elements that will be repeated afterwards
- \ref asBC_SetListSize
Sets the type of the next element
- \ref asBC_SetListType
Pushes the address of the list element on the stack
- \ref asBC_PshListElmnt
*/
|