2 * D binding for the JIT library.
4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd.
5 * Copyright (C) 2016 Ketmar Dark
7 * The libjit library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation, either version 2.1 of
10 * the License, or (at your option) any later version.
12 * The libjit library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with the libjit library. If not, see
19 * <http://www.gnu.org/licenses/>.
21 module iv
.libjit
.d
/*is aliced*/;
24 public import iv
.libjit
;
27 // ////////////////////////////////////////////////////////////////////////// //
28 public class JitException
: Exception
{
29 //private import std.exception : basicExceptionCtors;
30 //mixin basicExceptionCtors;
31 this (int aresult
, string file
= __FILE__
, usize line
= __LINE__
, Throwable next
= null) pure nothrow @safe @nogc { result
= aresult
; super("libjit error", file
, line
, next
); }
32 this (int aresult
, Throwable next
, string file
= __FILE__
, usize line
= __LINE__
) pure nothrow @safe @nogc { result
= aresult
; super("libjit error", file
, line
, next
); }
36 static string
result2str (int res
) {
39 case JIT_RESULT_OK
: return "no error";
40 case JIT_RESULT_OVERFLOW
: return "overflow";
41 case JIT_RESULT_ARITHMETIC
: return "arithmetic";
42 case JIT_RESULT_DIVISION_BY_ZERO
: return "division by zero";
43 case JIT_RESULT_COMPILE_ERROR
: return "compile error";
44 case JIT_RESULT_OUT_OF_MEMORY
: return "out of memory";
45 case JIT_RESULT_NULL_REFERENCE
: return "null reference";
46 case JIT_RESULT_NULL_FUNCTION
: return "null function";
47 case JIT_RESULT_CALLED_NESTED
: return "called nested";
48 case JIT_RESULT_OUT_OF_BOUNDS
: return "out of bounds";
49 case JIT_RESULT_UNDEFINED_LABEL
: return "undefined label";
50 case JIT_RESULT_MEMORY_FULL
: return "memory full";
53 return "unknown error #"~to
!string(res
);
56 override string
toString () {
57 import std
.string
: format
;
58 return "*** libjit error %s\n%s".format(result2str(result
), super.toString());
63 // ////////////////////////////////////////////////////////////////////////// //
69 this (jit_value_t value
) pure nothrow @safe @nogc { this.value
= value
; }
70 this (JitValue value
) pure nothrow @safe @nogc { this.value
= value
.value
; }
73 ref JitValue
opAssign() (in auto ref JitValue value
) pure nothrow @safe @nogc { pragma(inline
, true); this.value
= value
.value
; return this; }
75 @property inout(jit_value_t
) raw () inout pure nothrow @safe @nogc { pragma(inline
, true); return value
; }
76 @property bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (value
!is null); }
78 @property bool is_temporary () nothrow @nogc { pragma(inline
, true); return (jit_value_is_temporary(value
) != 0); }
79 @property bool is_local () nothrow @nogc { pragma(inline
, true); return (jit_value_is_local(value
) != 0); }
80 @property bool is_constant () nothrow @nogc { pragma(inline
, true); return (jit_value_is_constant(value
) != 0); }
81 @property bool is_parameter () nothrow @nogc { pragma(inline
, true); return (jit_value_is_parameter(value
) != 0); }
83 @property bool volatileValue () nothrow @nogc { pragma(inline
, true); return (jit_value_is_volatile(value
) != 0); }
84 void setVolatileValue () nothrow @nogc { pragma(inline
, true); jit_value_set_volatile(value
); }
85 @property void volatileValue (bool v
) {
86 if (!v
) { if (jit_value_is_volatile(value
)) throw new JitException(JIT_RESULT_COMPILE_ERROR
); }
87 jit_value_set_volatile(value
);
90 @property bool addressable () nothrow @nogc { pragma(inline
, true); return (jit_value_is_addressable(value
) != 0); }
91 void setAddressable () nothrow @nogc { pragma(inline
, true); jit_value_set_addressable(value
); }
92 @property void addressable (bool v
) {
93 if (!v
) { if (jit_value_is_addressable(value
)) throw new JitException(JIT_RESULT_COMPILE_ERROR
); }
94 jit_value_set_addressable(value
);
97 @property jit_type_t
type () nothrow @nogc { pragma(inline
, true); return jit_value_get_type(value
); }
98 @property jit_function_t
func () nothrow @nogc { pragma(inline
, true); return jit_value_get_function(value
); }
99 @property jit_block_t
block () nothrow @nogc { pragma(inline
, true); return jit_value_get_block(value
); }
100 @property jit_context_t
context () nothrow @nogc { pragma(inline
, true); return jit_value_get_context(value
); }
102 @property jit_constant_t
constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_constant(value
); }
103 @property jit_nint
nint_constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_nint_constant(value
); }
104 @property jit_long
long_constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_long_constant(value
); }
105 @property jit_float32
float32_constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_float32_constant(value
); }
106 @property jit_float64
float64_constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_float64_constant(value
); }
107 @property jit_nfloat
nfloat_constant () nothrow @nogc { pragma(inline
, true); return jit_value_get_nfloat_constant(value
); }
109 private enum UnOpMixin(string op
, string insn
) =
110 "JitValue opUnary(string op : "~op
.stringof
~") () {\n"~
111 " pragma(inline, true);\n"~
112 " return JitValue(jit_insn_"~insn
~"(jit_value_get_function(this), this.raw));\n"~
115 mixin(UnOpMixin
!("-", "neg"));
116 mixin(UnOpMixin
!("~", "not"));
119 private enum BinOpMixin(string op
, string insn
, string opname
="opBinary") =
120 "JitValue "~opname
~"(string op : "~op
.stringof
~") (JitValue rhs) {\n"~
121 " pragma(inline, true);\n"~
122 " return JitValue(jit_insn_"~insn
~"(value_owner(this, rhs), this.raw, rhs.raw));\n"~
125 mixin(BinOpMixin
!("+", "add"));
126 mixin(BinOpMixin
!("-", "sub"));
127 mixin(BinOpMixin
!("*", "mul"));
128 mixin(BinOpMixin
!("/", "div"));
129 mixin(BinOpMixin
!("%", "rem"));
130 mixin(BinOpMixin
!("&", "and"));
131 mixin(BinOpMixin
!("|", "or"));
132 mixin(BinOpMixin
!("^", "xor"));
133 mixin(BinOpMixin
!("<<", "shl"));
134 mixin(BinOpMixin
!(">>", "shr"));
136 // the following should be explicitly instantiated, like `l.opBinary!"<"(r)`
137 mixin(BinOpMixin
!("<", "lt"));
138 mixin(BinOpMixin
!(">", "gt"));
139 mixin(BinOpMixin
!("==", "eq"));
140 mixin(BinOpMixin
!("!=", "ne"));
141 mixin(BinOpMixin
!("<=", "le"));
142 mixin(BinOpMixin
!(">=", "ge"));
145 mixin(BinOpMixin
!("<", "lt", "opBinaryCmp"));
146 mixin(BinOpMixin
!(">", "gt", "opBinaryCmp"));
147 mixin(BinOpMixin
!("==", "eq", "opBinaryCmp"));
148 mixin(BinOpMixin
!("!=", "ne", "opBinaryCmp"));
149 mixin(BinOpMixin
!("<=", "le", "opBinaryCmp"));
150 mixin(BinOpMixin
!(">=", "ge", "opBinaryCmp"));
153 // Get the function that owns a pair of values. It will choose
154 // the function for the first value, unless it is NULL (e.g. for
155 // global values). In that case, it will choose the function
156 // for the second value.
157 static jit_function_t
value_owner (JitValue value1
, JitValue value2
) nothrow @nogc {
158 pragma(inline
, true);
159 jit_function_t func
= jit_value_get_function(value1
.raw
);
160 return (func
!is null ? func
: jit_value_get_function(value2
.raw
));
165 // ////////////////////////////////////////////////////////////////////////// //
168 jit_label_t label
= jit_label_undefined
;
171 this (jit_label_t label
) pure nothrow @safe @nogc { this.label
= label
; }
172 this (JitLabel label
) pure nothrow @safe @nogc { this.label
= label
.label
; }
175 @property inout(jit_label_t
) raw () inout const pure nothrow @safe @nogc { pragma(inline
, true); return label
; }
176 @property jit_label_t
* rawp () pure nothrow @nogc { pragma(inline
, true); return &label
; }
177 bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (label
!= jit_label_undefined
); }
179 ref JitLabel
opAssign (JitLabel value
) pure nothrow @safe @nogc { this.label
= value
.label
; return this; }
183 // ////////////////////////////////////////////////////////////////////////// //
184 struct JitJumpTable
{
186 jit_label_t
[] labels
;
189 this (int size
) nothrow @safe {
191 labels
= new jit_label_t
[](size
);
192 labels
[] = jit_label_undefined
;
195 @property bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (labels
.length
> 0); }
197 @property int size () const pure nothrow @safe @nogc { pragma(inline
, true); return cast(int)labels
.length
; }
198 jit_label_t
* raw () pure nothrow @nogc { pragma(inline
, true); return labels
.ptr
; }
200 JitLabel
get (usize index
) {
201 if (index
>= labels
.length
) throw new JitException(JIT_RESULT_COMPILE_ERROR
);
202 return JitLabel(labels
.ptr
[index
]);
205 void set (usize index
, JitLabel label
) {
206 if (index
>= labels
.length
) throw new JitException(JIT_RESULT_COMPILE_ERROR
);
207 labels
.ptr
[index
] = label
.raw
;
210 JitLabel
opIndex (usize index
) { pragma(inline
, true); return get(index
); }
211 void opIndexAssign (JitLabel value
, usize index
) { pragma(inline
, true); set(index
, value
); }
215 // ////////////////////////////////////////////////////////////////////////// //
218 jit_context_t context
;
222 this () nothrow @nogc {
224 context
= jit_context_create();
228 this (jit_context_t context
) nothrow @nogc {
229 assert(context
!is null);
230 this.context
= context
;
234 ~this () nothrow @nogc { release(); }
236 @property bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (context
!is null); }
238 @property jit_context_t
raw () pure nothrow @safe @nogc { /*pragma(inline, true);bug*/ return context
; }
240 void release () nothrow @nogc {
241 if (context
!is null) {
242 if (!copied
) jit_context_destroy(context
);
247 void buildStart () nothrow @nogc { pragma(inline
, true); assert(context
!is null); jit_context_build_start(context
); }
248 void buildEnd () nothrow @nogc { pragma(inline
, true); assert(context
!is null); jit_context_build_end(context
); }
252 // ////////////////////////////////////////////////////////////////////////// //
255 private import std
.traits
;
257 enum JITD_MAPPING
= 20001; // it's in reserved tange, but meh...
258 alias jit_byte
= jit_sbyte
; // for mixin trick
262 jit_context_t context
;
265 static JitValue
wrapValue() (jit_value_t x
) {
266 auto val
= JitValue(x
);
267 if (val
.raw
is null) out_of_memory();
272 // normally overridden by subclasses
273 if (builder
!is null) {
280 jit_type_t
createSignature () {
281 // normally overridden by subclasses
282 return signatureHelper(jit_type_void
);
286 static jit_type_t
signatureHelper (jit_type_t return_type
, jit_type_t
[] args
...) {
287 return jit_type_create_signature(jit_abi_cdecl
, return_type
, args
.ptr
, cast(uint)args
.length
, 1);
290 static void fail (string file
=__FILE__
, usize line
=__LINE__
) { throw new JitException(JIT_RESULT_COMPILE_ERROR
, file
, line
); }
291 static void out_of_memory (string file
=__FILE__
, usize line
=__LINE__
) { throw new JitException(JIT_RESULT_OUT_OF_MEMORY
, file
, line
); }
294 // you can set this delegate if you don't want to override `build()` method
295 void delegate (JitFunction me
) builder
;
298 this (JitContext context
, jit_type_t signature
) {
299 // save the context for the "create" method
300 this.context
= context
.raw
;
302 // create the function
306 this (JitContext context
) nothrow @nogc {
307 // save the context, but don't create the function yet.
308 this.context
= context
.raw
;
312 this (jit_function_t func
) {
313 this.context
= jit_function_get_context(func
);
316 jit_context_build_start(context
);
317 jit_function_set_meta(func
, JITD_MAPPING
, cast(void*)this, &freeMapping
, 0);
319 jit_context_build_end(context
);
323 ~this () nothrow @nogc { release(); }
326 void release () nothrow @nogc {
328 jit_context_build_start(context
);
329 jit_function_free_meta(func
, JITD_MAPPING
);
330 jit_context_build_end(context
);
335 @property jit_function_t
raw () pure nothrow @safe @nogc { pragma(inline
, true); return func
; }
336 @property bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (func
!is null); }
338 static JitFunction
getFuncObjFromRaw (jit_function_t func
) nothrow @nogc {
339 assert(func
!is null);
340 return cast(JitFunction
)jit_function_get_meta(func
, JITD_MAPPING
);
343 jit_type_t
signature () nothrow @nogc { assert(this.valid
); return jit_function_get_signature(func
); }
345 void create (jit_type_t signature
) {
346 // bail out if the function is already created
347 if (this.valid
) return;
348 // lock down the context
349 jit_context_build_start(context
);
350 // create the new function
351 func
= jit_function_create(context
, signature
);
352 if (func
is null) { jit_context_build_end(context
); return; }
353 // store this object's pointer on the raw function so that we can
354 // map the raw function back to this object later
355 jit_function_set_meta(func
, JITD_MAPPING
, cast(void*)this, &freeMapping
, 0);
356 // register us as the on-demand compiler
358 // unlock the context
359 jit_context_build_end(context
);
364 jit_type_t signature
= createSignature();
366 jit_type_free(signature
);
370 int compile () nothrow @nogc { return (func
is null ?
0 : jit_function_compile(func
)); }
372 @property bool compiled () nothrow @nogc { assert(this.valid
); return (jit_function_is_compiled(func
) != 0); }
374 @property bool recompilable () nothrow @nogc { assert(this.valid
); return (jit_function_is_recompilable(func
) != 0); }
375 @property void recompilable (bool flag
) nothrow @nogc { assert(this.valid
); if (flag
) jit_function_set_recompilable(func
); else jit_function_clear_recompilable(func
); }
377 @property uint optimizationLevel () nothrow @nogc { assert(this.valid
); return jit_function_get_optimization_level(func
); }
378 @property void optimizationLevel (uint level
) nothrow @nogc { assert(this.valid
); jit_function_set_optimization_level(func
, level
); }
380 static @property uint maxOptimizationLevel () nothrow @nogc { return jit_function_get_max_optimization_level(); }
382 @property void* closure () nothrow @nogc { assert(this.valid
); return jit_function_to_closure(func
); }
383 @property void* vtablePointer () nothrow @nogc { assert(this.valid
); return jit_function_to_vtable_pointer(func
); }
385 int apply (void*[] args
, void* result
) nothrow { assert(this.valid
); return jit_function_apply(func
, args
.ptr
, result
); }
386 int apply (jit_type_t signature
, void*[] args
, void* return_area
) nothrow { assert(this.valid
); return jit_function_apply_vararg(func
, signature
, args
.ptr
, return_area
); }
388 void buildStart () { assert(this.valid
); jit_context_build_start(jit_function_get_context(func
)); }
389 void buildEnd () { assert(this.valid
); jit_context_build_end(jit_function_get_context(func
)); }
391 JitValue
newValue (jit_type_t type
) { assert(this.valid
); return wrapValue(jit_value_create(func
, type
)); }
393 JitValue
newConstant(T
) (T value
, jit_type_t type
=null) if (isIntegral
!T ||
is(T
== float) ||
is(T
== double) ||
is(T
== real)) {
395 static if (isIntegral
!T
) {
396 if (type
is null) type
= mixin("jit_type_"~T
.stringof
);
397 static if (T
.sizeof
<= jit_nint
.sizeof
) {
398 return wrapValue(jit_value_create_nint_constant(func
, type
, cast(jit_nint
)value
));
400 return wrapValue(jit_value_create_long_constant(func
, type
, value
));
402 } else static if (is(T
== float)) {
403 if (type
is null) type
= jit_type_float32
;
404 return wrapValue(jit_value_create_float32_constant(func
, type
, value
));
405 } else static if (is(T
== double)) {
406 if (type
is null) type
= jit_type_float64
;
407 return wrapValue(jit_value_create_float64_constant(func
, type
, value
));
408 } else static if (is(T
== real)) {
409 if (type
is null) type
= jit_type_nfloat
;
410 return wrapValue(jit_value_create_nfloat_constant(func
, type
, value
));
412 static assert(0, "wtf?!");
416 JitValue
newConstant (void* value
, jit_type_t type
=null) {
418 if (type
is null) type
= jit_type_void_ptr
;
419 return wrapValue(jit_value_create_nint_constant(func
, type
, cast(jit_nint
)value
));
422 JitValue
newConstant (jit_constant_t
* value
) {
424 assert(value
!is null);
425 return wrapValue(jit_value_create_constant(func
, value
));
428 JitValue
getParam (uint param
) {
430 return wrapValue(jit_value_get_param(func
, param
));
433 JitValue
getStructPointer () {
435 return wrapValue(jit_value_get_struct_pointer(func
));
438 JitLabel
newLabel () {
440 return JitLabel(jit_function_reserve_label(func
));
443 void insn_label (JitLabel label
) {
446 if (!jit_insn_label(func
, label
.rawp
)) out_of_memory();
449 void insn_label_tight (JitLabel label
) {
452 if (!jit_insn_label_tight(func
, label
.rawp
)) out_of_memory();
455 void insn_new_block () {
457 if (!jit_insn_new_block(func
)) out_of_memory();
460 void store (JitValue dest
, JitValue value
) {
462 assert(dest
.valid
&& value
.valid
);
463 if (!jit_insn_store(func
, dest
.raw
, value
.raw
)) out_of_memory();
466 JitValue
insn_load_relative (JitValue value
, jit_nint offset
, jit_type_t type
) {
469 assert(type
!is null);
470 return wrapValue(jit_insn_load_relative(func
, value
.raw
, offset
, type
));
473 void insn_store_relative (JitValue dest
, jit_nint offset
, JitValue value
) {
475 assert(dest
.valid
&& value
.valid
);
476 if (!jit_insn_store_relative(func
, dest
.raw
, offset
, value
.raw
)) out_of_memory();
479 JitValue
insn_add_relative (JitValue value
, jit_nint offset
) {
482 return wrapValue(jit_insn_add_relative(func
, value
.raw
, offset
));
485 JitValue
insn_load_elem (JitValue base_addr
, JitValue index
, jit_type_t elem_type
) {
487 assert(base_addr
.valid
&& index
.valid
&& elem_type
!is null);
488 return wrapValue(jit_insn_load_elem(func
, base_addr
.raw
, index
.raw
, elem_type
));
491 JitValue
insn_load_elem_address (JitValue base_addr
, JitValue index
, jit_type_t elem_type
) {
493 assert(base_addr
.valid
&& index
.valid
&& elem_type
!is null);
494 return wrapValue(jit_insn_load_elem_address(func
, base_addr
.raw
, index
.raw
, elem_type
));
497 void insn_store_elem (JitValue base_addr
, JitValue index
, JitValue value
) {
499 assert(base_addr
.valid
&& index
.valid
&& value
.valid
);
500 if (!jit_insn_store_elem(func
, base_addr
.raw
, index
.raw
, value
.raw
)) out_of_memory();
503 void insn_check_null (JitValue value
) {
506 if (!jit_insn_check_null(func
, value
.raw
)) out_of_memory();
509 void insn_nop (JitValue value
) {
511 if (!jit_insn_nop(func
)) out_of_memory();
514 private enum UnInsnMixin(string name
) =
515 "JitValue insn_"~name
~" (JitValue value1) {\n"~
516 " assert(this.valid);\n"~
517 " assert(value1.valid);\n"~
518 " return wrapValue(jit_insn_"~name
~"(func, value1.raw));\n"
521 mixin(UnInsnMixin
!"load");
522 mixin(UnInsnMixin
!"dup");
524 mixin(UnInsnMixin
!"neg");
525 mixin(UnInsnMixin
!"not");
526 mixin(UnInsnMixin
!"to_bool");
527 mixin(UnInsnMixin
!"to_not_bool");
528 mixin(UnInsnMixin
!"acos");
529 mixin(UnInsnMixin
!"asin");
530 mixin(UnInsnMixin
!"atan");
531 mixin(UnInsnMixin
!"ceil");
532 mixin(UnInsnMixin
!"cos");
533 mixin(UnInsnMixin
!"cosh");
534 mixin(UnInsnMixin
!"exp");
535 mixin(UnInsnMixin
!"floor");
536 mixin(UnInsnMixin
!"log");
537 mixin(UnInsnMixin
!"log10");
538 mixin(UnInsnMixin
!"rint");
539 mixin(UnInsnMixin
!"round");
540 mixin(UnInsnMixin
!"sin");
541 mixin(UnInsnMixin
!"sinh");
542 mixin(UnInsnMixin
!"sqrt");
543 mixin(UnInsnMixin
!"tan");
544 mixin(UnInsnMixin
!"tanh");
545 mixin(UnInsnMixin
!"trunc");
546 mixin(UnInsnMixin
!"is_nan");
547 mixin(UnInsnMixin
!"is_finite");
548 mixin(UnInsnMixin
!"is_inf");
549 mixin(UnInsnMixin
!"abs");
550 mixin(UnInsnMixin
!"sign");
551 mixin(UnInsnMixin
!"address_of");
553 private enum BinInsnMixin(string name
) =
554 "JitValue insn_"~name
~" (JitValue value1, JitValue value2) {\n"~
555 " assert(this.valid);\n"~
556 " assert(value1.valid && value2.valid);\n"~
557 " return wrapValue(jit_insn_"~name
~"(func, value1.raw, value2.raw));\n"
560 mixin(BinInsnMixin
!"add");
561 mixin(BinInsnMixin
!"add_ovf");
562 mixin(BinInsnMixin
!"sub");
563 mixin(BinInsnMixin
!"sub_ovf");
564 mixin(BinInsnMixin
!"mul");
565 mixin(BinInsnMixin
!"mul_ovf");
566 mixin(BinInsnMixin
!"div");
567 mixin(BinInsnMixin
!"rem");
568 mixin(BinInsnMixin
!"rem_ieee");
569 mixin(BinInsnMixin
!"and");
570 mixin(BinInsnMixin
!"or");
571 mixin(BinInsnMixin
!"xor");
572 mixin(BinInsnMixin
!"shl");
573 mixin(BinInsnMixin
!"shr");
574 mixin(BinInsnMixin
!"ushr");
575 mixin(BinInsnMixin
!"sshr");
576 mixin(BinInsnMixin
!"eq");
577 mixin(BinInsnMixin
!"ne");
578 mixin(BinInsnMixin
!"lt");
579 mixin(BinInsnMixin
!"le");
580 mixin(BinInsnMixin
!"gt");
581 mixin(BinInsnMixin
!"ge");
582 mixin(BinInsnMixin
!"cmpl");
583 mixin(BinInsnMixin
!"cmpg");
584 mixin(BinInsnMixin
!"atan2");
585 mixin(BinInsnMixin
!"pow");
586 mixin(BinInsnMixin
!"min");
587 mixin(BinInsnMixin
!"max");
589 void insn_branch (JitLabel label
) {
592 if (!jit_insn_branch(func
, label
.rawp
)) out_of_memory();
595 void insn_branch_if (JitValue value
, JitLabel label
) {
598 if (!jit_insn_branch_if(func
, value
.raw
, label
.rawp
)) out_of_memory();
601 void insn_branch_if_not (JitValue value
, JitLabel label
) {
603 assert(value
.valid
&& label
.valid
);
604 if (!jit_insn_branch_if_not(func
, value
.raw
, label
.rawp
)) out_of_memory();
607 void insn_jump_table (JitValue value
, JitJumpTable jump_table
) {
609 assert(jump_table
.valid
&& jump_table
.size
> 0);
610 if (!jit_insn_jump_table(func
, value
.raw
, jump_table
.raw
, jump_table
.size
)) out_of_memory();
613 JitValue
insn_address_of_label (JitLabel label
) {
616 return wrapValue(jit_insn_address_of_label(func
, label
.rawp
));
619 JitValue
insn_convert (JitValue value
, jit_type_t type
, bool overflow_check
=false) {
621 assert(value
.valid
&& type
!is null);
622 return wrapValue(jit_insn_convert(func
, value
.raw
, type
, overflow_check
));
625 JitValue
insn_call (string name
, jit_function_t jit_func
, jit_type_t signature
, jit_value_t
[] args
, int flags
=0) {
626 import std
.string
: toStringz
;
628 assert(jit_func
!is null && signature
!is null);
629 assert(args
.length
<= uint.max
);
630 return wrapValue(jit_insn_call(func
, name
.toStringz
, jit_func
, signature
, args
.ptr
, cast(uint)args
.length
, flags
));
633 JitValue
insn_call_indirect (JitValue value
, jit_type_t signature
, jit_value_t
[] args
, int flags
=0) {
635 assert(value
.valid
&& signature
!is null);
636 assert(args
.length
<= uint.max
);
637 return wrapValue(jit_insn_call_indirect(func
, value
.raw
, signature
, args
.ptr
, cast(uint)args
.length
, flags
));
640 JitValue
insn_call_indirect_vtable (JitValue value
, jit_type_t signature
, jit_value_t
[] args
, int flags
=0) {
642 assert(value
.valid
&& signature
!is null);
643 assert(args
.length
<= uint.max
);
644 return wrapValue(jit_insn_call_indirect_vtable(func
, value
.raw
, signature
, args
.ptr
, cast(uint)args
.length
, flags
));
647 JitValue
insn_call_native (string name
, void* native_func
, jit_type_t signature
, jit_value_t
[] args
, int flags
=0) {
648 import std
.string
: toStringz
;
650 assert(native_func
!is null && signature
!is null);
651 assert(args
.length
<= uint.max
);
652 return wrapValue(jit_insn_call_native(func
, name
.toStringz
, native_func
, signature
, args
.ptr
, cast(uint)args
.length
, flags
));
655 JitValue
insn_call_intrinsic (string name
, void* intrinsic_func
, jit_intrinsic_descr_t
* descriptor
, JitValue arg1
) {
656 import std
.string
: toStringz
;
658 assert(intrinsic_func
!is null && descriptor
!is null);
660 return wrapValue(jit_insn_call_intrinsic(func
, name
.toStringz
, intrinsic_func
, descriptor
, arg1
.raw
, null));
663 JitValue
insn_call_intrinsic (string name
, void* intrinsic_func
, jit_intrinsic_descr_t
* descriptor
, JitValue arg1
, JitValue arg2
) {
664 import std
.string
: toStringz
;
666 assert(intrinsic_func
!is null && descriptor
!is null);
669 return wrapValue(jit_insn_call_intrinsic(func
, name
.toStringz
, intrinsic_func
, descriptor
, arg1
.raw
, arg2
.raw
));
672 void insn_incoming_reg (JitValue value
, int reg
) {
675 if (!jit_insn_incoming_reg(func
, value
.raw
, reg
)) out_of_memory();
678 void insn_incoming_frame_posn (JitValue value
, jit_nint posn
) {
681 if (!jit_insn_incoming_frame_posn(func
, value
.raw
, posn
)) out_of_memory();
684 void insn_outgoing_reg (JitValue value
, int reg
) {
687 if (!jit_insn_outgoing_reg(func
, value
.raw
, reg
)) out_of_memory();
690 void insn_outgoing_frame_posn (JitValue value
, jit_nint posn
) {
693 if (!jit_insn_outgoing_frame_posn(func
, value
.raw
, posn
)) out_of_memory();
696 void insn_return_reg (JitValue value
, int reg
) {
699 if (!jit_insn_return_reg(func
, value
.raw
, reg
)) out_of_memory();
702 void insn_setup_for_nested (int nested_level
, int reg
) {
704 if (!jit_insn_setup_for_nested(func
, nested_level
, reg
)) out_of_memory();
707 void insn_flush_struct (JitValue value
) {
710 if (!jit_insn_flush_struct(func
, value
.raw
)) out_of_memory();
713 JitValue
insn_import (JitValue value
) {
716 return wrapValue(jit_insn_import(func
, value
.raw
));
719 void insn_push (JitValue value
) {
722 if (!jit_insn_push(func
, value
.raw
)) out_of_memory();
725 void insn_push_ptr (JitValue value
, jit_type_t type
) {
727 assert(value
.valid
&& type
!is null);
728 if (!jit_insn_push_ptr(func
, value
.raw
, type
)) out_of_memory();
731 void insn_set_param (JitValue value
, jit_nint offset
) {
734 if (!jit_insn_set_param(func
, value
.raw
, offset
)) out_of_memory();
737 void insn_set_param_ptr (JitValue value
, jit_type_t type
, jit_nint offset
) {
739 assert(value
.valid
&& type
!is null);
740 if (!jit_insn_set_param_ptr(func
, value
.raw
, type
, offset
)) out_of_memory();
743 void insn_push_return_area_ptr () {
745 if (!jit_insn_push_return_area_ptr(func
)) out_of_memory();
748 void insn_return (JitValue value
) {
751 if (!jit_insn_return(func
, value
.raw
)) out_of_memory();
754 void insn_return () {
756 if (!jit_insn_return(func
, null)) out_of_memory();
759 void insn_return_ptr (JitValue value
, jit_type_t type
) {
761 assert(value
.valid
&& type
!is null);
762 if (!jit_insn_return_ptr(func
, value
.raw
, type
)) out_of_memory();
765 void insn_default_return () {
767 if (!jit_insn_default_return(func
)) out_of_memory();
770 void insn_throw (JitValue value
) {
773 if (!jit_insn_throw(func
, value
.raw
)) out_of_memory();
776 JitValue
insn_get_call_stack () {
778 return wrapValue(jit_insn_get_call_stack(func
));
781 JitValue
insn_thrown_exception () {
783 return wrapValue(jit_insn_thrown_exception(func
));
786 void insn_uses_catcher () {
788 if (!jit_insn_uses_catcher(func
)) out_of_memory();
791 JitValue
insn_start_catcher () {
793 return wrapValue(jit_insn_start_catcher(func
));
796 void insn_branch_if_pc_not_in_range (JitLabel start_label
, JitLabel end_label
, JitLabel label
) {
798 assert(start_label
.valid
&& end_label
.valid
&& label
.valid
);
799 if (!jit_insn_branch_if_pc_not_in_range(func
, start_label
.raw
, end_label
.raw
, label
.rawp
)) out_of_memory();
802 void insn_rethrow_unhandled () {
804 if (!jit_insn_rethrow_unhandled(func
)) out_of_memory();
807 void insn_start_finally (JitLabel label
) {
810 if (!jit_insn_start_finally(func
, label
.rawp
)) out_of_memory();
813 void insn_return_from_finally () {
815 if (!jit_insn_return_from_finally(func
)) out_of_memory();
818 void insn_call_finally (JitLabel label
) {
821 if (!jit_insn_call_finally(func
, label
.rawp
)) out_of_memory();
824 JitValue
insn_start_filter (JitLabel label
, jit_type_t type
) {
826 assert(label
.valid
&& type
!is null);
827 return wrapValue(jit_insn_start_filter(func
, label
.rawp
, type
));
830 void insn_return_from_filter (JitValue value
) {
833 if (!jit_insn_return_from_filter(func
, value
.raw
)) out_of_memory();
836 JitValue
insn_call_filter (JitLabel label
, JitValue value
, jit_type_t type
) {
838 assert(label
.valid
&& value
.valid
&& type
!is null);
839 return wrapValue(jit_insn_call_filter(func
, label
.rawp
, value
.raw
, type
));
842 void insn_memcpy (JitValue dest
, JitValue src
, JitValue size
) {
844 assert(dest
.valid
&& src
.valid
&& size
.valid
);
845 if (!jit_insn_memcpy(func
, dest
.raw
, src
.raw
, size
.raw
)) out_of_memory();
848 void insn_memmove (JitValue dest
, JitValue src
, JitValue size
) {
850 assert(dest
.valid
&& src
.valid
&& size
.valid
);
851 if (!jit_insn_memmove(func
, dest
.raw
, src
.raw
, size
.raw
)) out_of_memory();
854 void insn_memset (JitValue dest
, JitValue value
, JitValue size
) {
856 assert(dest
.valid
&& value
.valid
&& size
.valid
);
857 if (!jit_insn_memset(func
, dest
.raw
, value
.raw
, size
.raw
)) out_of_memory();
860 JitValue
insn_alloca (JitValue size
) {
863 return wrapValue(jit_insn_alloca(func
, size
.raw
));
866 void insn_move_blocks_to_end (JitLabel from_label
, JitLabel to_label
) {
868 assert(from_label
.valid
&& to_label
.valid
);
869 if (!jit_insn_move_blocks_to_end(func
, from_label
.raw
, to_label
.raw
)) out_of_memory();
872 void insn_move_blocks_to_start (JitLabel from_label
, JitLabel to_label
) {
874 assert(from_label
.valid
&& to_label
.valid
);
875 if (!jit_insn_move_blocks_to_start(func
, from_label
.raw
, to_label
.raw
)) out_of_memory();
878 void insn_mark_offset (jit_int offset
) {
880 if (!jit_insn_mark_offset(func
, offset
)) out_of_memory();
883 void insn_mark_breakpoint (jit_nint data1
, jit_nint data2
) {
885 if (!jit_insn_mark_breakpoint(func
, data1
, data2
)) out_of_memory();
889 void registerOnDemand () {
890 jit_function_set_on_demand_compiler(func
, &onDemandCompiler
);
893 static extern(C
) int onDemandCompiler (jit_function_t func
) nothrow {
894 // get the object that corresponds to the raw function
895 auto func_object
= getFuncObjFromRaw(func
);
896 if (func_object
is null) return JIT_RESULT_COMPILE_ERROR
;
897 // attempt to build the function's contents
900 if (!jit_insn_default_return(func
)) func_object
.out_of_memory();
901 return JIT_RESULT_OK
;
902 } catch (JitException e
) {
904 } catch (Exception e
) {
905 return JIT_RESULT_COMPILE_ERROR
;
909 static extern(C
) void freeMapping (void* data
) nothrow {
910 // If we were called during the context's shutdown,
911 // then the raw function pointer is no longer valid.
912 (cast(JitFunction
)data
).func
= null;