egra: some cleanups in agg mini rasterizer
[iv.d.git] / libjit / d.d
blobb901817f49ffe6dda137fa0ee04dea40c8412131
1 /*
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*/;
23 import iv.alice;
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); }
34 int result;
36 static string result2str (int res) {
37 import std.conv : to;
38 switch (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";
51 default:
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 // ////////////////////////////////////////////////////////////////////////// //
64 struct JitValue {
65 private:
66 jit_value_t value;
68 public:
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; }
72 final:
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"~
113 "}";
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"~
123 "}";
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"));
144 // Aliced extension
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"));
152 private:
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 // ////////////////////////////////////////////////////////////////////////// //
166 struct JitLabel {
167 private:
168 jit_label_t label = jit_label_undefined;
170 public:
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; }
174 final:
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 {
185 private:
186 jit_label_t[] labels;
188 public:
189 this (int size) nothrow @safe {
190 assert(size > 0);
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 // ////////////////////////////////////////////////////////////////////////// //
216 class JitContext {
217 private:
218 jit_context_t context;
219 bool copied;
221 public:
222 this () nothrow @nogc {
223 jit_init();
224 context = jit_context_create();
225 copied = false;
228 this (jit_context_t context) nothrow @nogc {
229 assert(context !is null);
230 this.context = context;
231 this.copied = true;
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);
243 context = null;
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 // ////////////////////////////////////////////////////////////////////////// //
253 class JitFunction {
254 private:
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
260 private:
261 jit_function_t func;
262 jit_context_t context;
264 protected:
265 static JitValue wrapValue() (jit_value_t x) {
266 auto val = JitValue(x);
267 if (val.raw is null) out_of_memory();
268 return val;
271 void build () {
272 // normally overridden by subclasses
273 if (builder !is null) {
274 builder(this);
275 } else {
276 fail();
280 jit_type_t createSignature () {
281 // normally overridden by subclasses
282 return signatureHelper(jit_type_void);
285 public:
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); }
293 public:
294 // you can set this delegate if you don't want to override `build()` method
295 void delegate (JitFunction me) builder;
297 public:
298 this (JitContext context, jit_type_t signature) {
299 // save the context for the "create" method
300 this.context = context.raw;
301 this.func = null;
302 // create the function
303 create(signature);
306 this (JitContext context) nothrow @nogc {
307 // save the context, but don't create the function yet.
308 this.context = context.raw;
309 this.func = null;
312 this (jit_function_t func) {
313 this.context = jit_function_get_context(func);
314 this.func = func;
315 if (func !is null) {
316 jit_context_build_start(context);
317 jit_function_set_meta(func, JITD_MAPPING, cast(void*)this, &freeMapping, 0);
318 registerOnDemand();
319 jit_context_build_end(context);
323 ~this () nothrow @nogc { release(); }
325 final:
326 void release () nothrow @nogc {
327 if (func !is null) {
328 jit_context_build_start(context);
329 jit_function_free_meta(func, JITD_MAPPING);
330 jit_context_build_end(context);
331 func = null;
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
357 registerOnDemand();
358 // unlock the context
359 jit_context_build_end(context);
362 void create () {
363 if (func is null) {
364 jit_type_t signature = createSignature();
365 create(signature);
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)) {
394 assert(this.valid);
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));
399 } else {
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));
411 } else {
412 static assert(0, "wtf?!");
416 JitValue newConstant (void* value, jit_type_t type=null) {
417 assert(this.valid);
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) {
423 assert(this.valid);
424 assert(value !is null);
425 return wrapValue(jit_value_create_constant(func, value));
428 JitValue getParam (uint param) {
429 assert(this.valid);
430 return wrapValue(jit_value_get_param(func, param));
433 JitValue getStructPointer () {
434 assert(this.valid);
435 return wrapValue(jit_value_get_struct_pointer(func));
438 JitLabel newLabel () {
439 assert(this.valid);
440 return JitLabel(jit_function_reserve_label(func));
443 void insn_label (JitLabel label) {
444 assert(this.valid);
445 assert(label.valid);
446 if (!jit_insn_label(func, label.rawp)) out_of_memory();
449 void insn_label_tight (JitLabel label) {
450 assert(this.valid);
451 assert(label.valid);
452 if (!jit_insn_label_tight(func, label.rawp)) out_of_memory();
455 void insn_new_block () {
456 assert(this.valid);
457 if (!jit_insn_new_block(func)) out_of_memory();
460 void store (JitValue dest, JitValue value) {
461 assert(this.valid);
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) {
467 assert(this.valid);
468 assert(value.valid);
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) {
474 assert(this.valid);
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) {
480 assert(this.valid);
481 assert(value.valid);
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) {
486 assert(this.valid);
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) {
492 assert(this.valid);
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) {
498 assert(this.valid);
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) {
504 assert(this.valid);
505 assert(value.valid);
506 if (!jit_insn_check_null(func, value.raw)) out_of_memory();
509 void insn_nop (JitValue value) {
510 assert(this.valid);
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"
519 "}";
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"
558 "}";
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) {
590 assert(this.valid);
591 assert(label.valid);
592 if (!jit_insn_branch(func, label.rawp)) out_of_memory();
595 void insn_branch_if (JitValue value, JitLabel label) {
596 assert(this.valid);
597 assert(label.valid);
598 if (!jit_insn_branch_if(func, value.raw, label.rawp)) out_of_memory();
601 void insn_branch_if_not (JitValue value, JitLabel label) {
602 assert(this.valid);
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) {
608 assert(this.valid);
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) {
614 assert(this.valid);
615 assert(label.valid);
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) {
620 assert(this.valid);
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;
627 assert(this.valid);
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) {
634 assert(this.valid);
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) {
641 assert(this.valid);
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;
649 assert(this.valid);
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;
657 assert(this.valid);
658 assert(intrinsic_func !is null && descriptor !is null);
659 assert(arg1.valid);
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;
665 assert(this.valid);
666 assert(intrinsic_func !is null && descriptor !is null);
667 assert(arg1.valid);
668 assert(arg2.valid);
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) {
673 assert(this.valid);
674 assert(value.valid);
675 if (!jit_insn_incoming_reg(func, value.raw, reg)) out_of_memory();
678 void insn_incoming_frame_posn (JitValue value, jit_nint posn) {
679 assert(this.valid);
680 assert(value.valid);
681 if (!jit_insn_incoming_frame_posn(func, value.raw, posn)) out_of_memory();
684 void insn_outgoing_reg (JitValue value, int reg) {
685 assert(this.valid);
686 assert(value.valid);
687 if (!jit_insn_outgoing_reg(func, value.raw, reg)) out_of_memory();
690 void insn_outgoing_frame_posn (JitValue value, jit_nint posn) {
691 assert(this.valid);
692 assert(value.valid);
693 if (!jit_insn_outgoing_frame_posn(func, value.raw, posn)) out_of_memory();
696 void insn_return_reg (JitValue value, int reg) {
697 assert(this.valid);
698 assert(value.valid);
699 if (!jit_insn_return_reg(func, value.raw, reg)) out_of_memory();
702 void insn_setup_for_nested (int nested_level, int reg) {
703 assert(this.valid);
704 if (!jit_insn_setup_for_nested(func, nested_level, reg)) out_of_memory();
707 void insn_flush_struct (JitValue value) {
708 assert(this.valid);
709 assert(value.valid);
710 if (!jit_insn_flush_struct(func, value.raw)) out_of_memory();
713 JitValue insn_import (JitValue value) {
714 assert(this.valid);
715 assert(value.valid);
716 return wrapValue(jit_insn_import(func, value.raw));
719 void insn_push (JitValue value) {
720 assert(this.valid);
721 assert(value.valid);
722 if (!jit_insn_push(func, value.raw)) out_of_memory();
725 void insn_push_ptr (JitValue value, jit_type_t type) {
726 assert(this.valid);
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) {
732 assert(this.valid);
733 assert(value.valid);
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) {
738 assert(this.valid);
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 () {
744 assert(this.valid);
745 if (!jit_insn_push_return_area_ptr(func)) out_of_memory();
748 void insn_return (JitValue value) {
749 assert(this.valid);
750 assert(value.valid);
751 if (!jit_insn_return(func, value.raw)) out_of_memory();
754 void insn_return () {
755 assert(this.valid);
756 if (!jit_insn_return(func, null)) out_of_memory();
759 void insn_return_ptr (JitValue value, jit_type_t type) {
760 assert(this.valid);
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 () {
766 assert(this.valid);
767 if (!jit_insn_default_return(func)) out_of_memory();
770 void insn_throw (JitValue value) {
771 assert(this.valid);
772 assert(value.valid);
773 if (!jit_insn_throw(func, value.raw)) out_of_memory();
776 JitValue insn_get_call_stack () {
777 assert(this.valid);
778 return wrapValue(jit_insn_get_call_stack(func));
781 JitValue insn_thrown_exception () {
782 assert(this.valid);
783 return wrapValue(jit_insn_thrown_exception(func));
786 void insn_uses_catcher () {
787 assert(this.valid);
788 if (!jit_insn_uses_catcher(func)) out_of_memory();
791 JitValue insn_start_catcher () {
792 assert(this.valid);
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) {
797 assert(this.valid);
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 () {
803 assert(this.valid);
804 if (!jit_insn_rethrow_unhandled(func)) out_of_memory();
807 void insn_start_finally (JitLabel label) {
808 assert(this.valid);
809 assert(label.valid);
810 if (!jit_insn_start_finally(func, label.rawp)) out_of_memory();
813 void insn_return_from_finally () {
814 assert(this.valid);
815 if (!jit_insn_return_from_finally(func)) out_of_memory();
818 void insn_call_finally (JitLabel label) {
819 assert(this.valid);
820 assert(label.valid);
821 if (!jit_insn_call_finally(func, label.rawp)) out_of_memory();
824 JitValue insn_start_filter (JitLabel label, jit_type_t type) {
825 assert(this.valid);
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) {
831 assert(this.valid);
832 assert(value.valid);
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) {
837 assert(this.valid);
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) {
843 assert(this.valid);
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) {
849 assert(this.valid);
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) {
855 assert(this.valid);
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) {
861 assert(this.valid);
862 assert(size.valid);
863 return wrapValue(jit_insn_alloca(func, size.raw));
866 void insn_move_blocks_to_end (JitLabel from_label, JitLabel to_label) {
867 assert(this.valid);
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) {
873 assert(this.valid);
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) {
879 assert(this.valid);
880 if (!jit_insn_mark_offset(func, offset)) out_of_memory();
883 void insn_mark_breakpoint (jit_nint data1, jit_nint data2) {
884 assert(this.valid);
885 if (!jit_insn_mark_breakpoint(func, data1, data2)) out_of_memory();
888 private:
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
898 try {
899 func_object.build();
900 if (!jit_insn_default_return(func)) func_object.out_of_memory();
901 return JIT_RESULT_OK;
902 } catch (JitException e) {
903 return e.result;
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;