1 /******************************** -*- C -*- ****************************
2 *
3 * Translator to native code.
4 *
5 *
6 ***********************************************************************/
7
8 /***********************************************************************
9 *
10 * Copyright 2001, 2002, 2003, 2004, 2006, 2008 Free Software Foundation, Inc.
11 * Written by Paolo Bonzini.
12 *
13 * This file is part of GNU Smalltalk.
14 *
15 * GNU Smalltalk is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the Free
17 * Software Foundation; either version 2, or (at your option) any later
18 * version.
19 *
20 * Linking GNU Smalltalk statically or dynamically with other modules is
21 * making a combined work based on GNU Smalltalk. Thus, the terms and
22 * conditions of the GNU General Public License cover the whole
23 * combination.
24 *
25 * In addition, as a special exception, the Free Software Foundation
26 * give you permission to combine GNU Smalltalk with free software
27 * programs or libraries that are released under the GNU LGPL and with
28 * independent programs running under the GNU Smalltalk virtual machine.
29 *
30 * You may copy and distribute such a system following the terms of the
31 * GNU GPL for GNU Smalltalk and the licenses of the other code
32 * concerned, provided that you include the source code of that other
33 * code when and as the GNU GPL requires distribution of source code.
34 *
35 * Note that people who make modified versions of GNU Smalltalk are not
36 * obligated to grant this special exception for their modified
37 * versions; it is their choice whether to do so. The GNU General
38 * Public License gives permission to release a modified version without
39 * this exception; this exception also makes it possible to release a
40 * modified version which carries forward this exception.
41 *
42 * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
43 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
44 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
45 * more details.
46 *
47 * You should have received a copy of the GNU General Public License along with
48 * GNU Smalltalk; see the file COPYING. If not, write to the Free Software
49 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
50 *
51 ***********************************************************************/
52
53 #include "gstpriv.h"
54 #include "match.h"
55
56 #ifdef ENABLE_JIT_TRANSLATION
57 #include "lightning.h"
58 #include "jitpriv.h"
59
60 #ifdef __GNUC__
61 #warning .---------------------------------------
62 #warning | do not worry if you get lots of
63 #warning | 'value computed is not used' warnings
64 #warning `---------------------------------------
65 #endif
66
67 /* This file implements GNU Smalltalk's just-in-time compiler to native code.
68 It is inspired by techniques shown in Ian Piumarta's PhD thesis "Delayed
69 code generation in a Smalltalk-80 compiler" (available online at
70 http://www-sor.inria.fr/~piumarta), with quite a few modifications:
71 - we target a RISC architecture (GNU lightning) instead of the CISC
72 Motorola 68020 architecture used in the thesis.
73 - we use inline caching (only discussed briefly in the thesis)
74 - block implementation is radically different
75 - we don't work directly on a parse tree. Rather, we recreate a tree
76 structure from bytecodes that constitute a statement.
77 - a few parts that were left back in the thesis (doesNotUnderstand:,
78 non local returns, primitives, etc.) are fully implemented
79
80 The aim of the code in this file is to generate pretty good code,
81 as fast as possible, and without requiring too much memory and
82 information (Self's 64MB requirement comes to mind...). Nothing
83 less, nothing more. All bottlenecks and inefficiencies should be
84 due to the generic nature of GNU lightning's architecture and to
85 interp.c, not to the compiler. */
86
87
88 /* These two small structures are used to store information on labels
89 and forward references. */
90 typedef struct label_use
91 {
92 jit_insn *addr; /* addr of client insn */
93 struct label_use *next; /* next label use or 0 */
94 }
95 label_use;
96
97 typedef struct label
98 {
99 jit_insn *addr; /* defined address of label or 0
100 (forward) */
101 label_use *uses; /* list of uses while forward */
102 }
103 label;
104
105
106 /* This structure represents an n-tree. Children of a node are
107 connected by a linked list. It is probably the most important for
108 the operation of the translator.
109
110 The translator operates on blocks of bytecodes that constitute a
111 statement, and represents what the block does on a stack. The
112 stack, however, does not contain results of the execution, but
113 rather code_trees that store how the value in that stack slot was
114 computed; these code_trees are built by dcd_* functions. When a
115 statement boundary is found (i.e. a result on the stack is
116 discarded, a jump is encountered, or a jump destination is
117 reached), the code_trees that are currently on the stack are walked
118 (calling recursively the gen_* functions depending on the contents
119 of the 'operation' field), resulting in the generation of native
120 code. */
121 typedef struct code_tree
122 {
123 struct code_tree *child, *next;
124 int operation;
125 PTR data;
126 label *jumpDest;
127 gst_uchar *bp;
128 } code_tree, *code_stack_element, **code_stack_pointer;
129
130 /* This structure represents a message send. A sequence of
131 inline_cache objects is allocated on the heap and initialized as
132 the code_tree is constructed. Inline caches have two roles:
133
134 a) avoiding that data is stored in the methodsTableObstack, therefore
135 making it easier to guess the size of the produced native code
136
137 b) improving execution speed by lowering the number of global cache
138 lookups to be done.
139
140 A pointer to an inline_cache is used for the 'data' field in
141 message send code_trees. */
142 typedef struct inline_cache
143 {
144 OOP selector;
145 jit_insn *cachedIP;
146 jit_insn *native_ip;
147 char imm; /* For short sends, the selector number. */
148 char numArgs;
149 char more;
150 char is_super;
151 }
152 inline_cache;
153
154 typedef struct ip_map
155 {
156 jit_insn *native_ip;
157 int virtualIP;
158 }
159 ip_map;
160
161 /* This structure forms a list that remembers which message sends were
162 inlined directly into the instruction flow. The list is walked by
163 emit_deferred_sends after the last bytecode has been compiled, and
164 recovery code that performs real message sends is written. */
165 typedef struct deferred_send
166 {
167 code_tree *tree;
168 label *trueDest;
169 label *falseDest;
170 label *address;
171 int reg0, reg1;
172 OOP oop;
173 struct deferred_send *next;
174 }
175 deferred_send;
176
177
178 /* To reduce multiplies and divides to shifts */
179
180 #define LONG_SHIFT (sizeof (long) == 4 ? 2 : 3)
181
182 /* An arbitrary value */
183
184 #define MAX_BYTES_PER_BYTECODE (100 * sizeof(jit_insn))
185
186 /* These are for the hash table of translations */
187
188 #define HASH_TABLE_SIZE (8192)
189 #define METHOD_HEADER_SIZE (sizeof(method_entry) - sizeof(jit_insn))
190
191 /* Here is where the dynamically compiled stuff goes */
192 static method_entry *methods_table[HASH_TABLE_SIZE+1], *released;
193
194 #define discarded methods_table[HASH_TABLE_SIZE]
195
196 /* Current status of the translator at the method level */
197 static method_entry *current;
198 static struct obstack aux_data_obstack;
199 static inline_cache *curr_inline_cache;
200 static deferred_send *deferred_head;
201 static label **labels, **this_label;
202 static gst_uchar *bc;
203 static OOP *literals;
204 static OOP method_class;
205 static code_stack_element t_stack[MAX_DEPTH];
206 static code_stack_pointer t_sp;
207
208 /* Current status of the code generator */
209 static mst_Boolean self_cached, rec_var_cached;
210 static int sp_delta, self_class_check, stack_cached;
211
212 /* These are pieces of native code that are used by the run-time. */
213 static jit_insn *do_send_code, *do_super_code, *non_boolean_code,
214 *bad_return_code, *does_not_understand_code;
215
216 PTR (*_gst_run_native_code) ();
217 PTR (*_gst_return_from_native_code) ();
218
219
220
221 /* Kinds of functions used in function tables */
222 typedef void (*emit_func) (code_tree *);
223 typedef mst_Boolean (*decode_func) (gst_uchar b, gst_uchar *bp);
224
225 /* Constants used in the reconstruction of the parse tree (operation field)
226
227 .---------------. .--------------.-----------.--------------.
228 | bits 12-13 |.| bits 6-8 | bits 3-5 | bits 0-2 |
229 |---------------|.|--------------|-----------|--------------|
230 | class check |.| jump, pop & | operation | suboperation |
231 | SmallInteger |.| return flags | | |
232 '---------------' '--------------'-----------'--------------'
233 \
234 \__ 3 unused bits */
235
236 /* operations ** value of tree->data */
237 #define TREE_OP 00070
238 #define TREE_SEND 00000 /* points to an inline_cache */
239 #define TREE_STORE 00010 /* see below */
240 #define TREE_PUSH 00020 /* see below */
241 #define TREE_ALT_PUSH 00030 /* see below */
242 #define TREE_SET_TOP 00040 /* see below */
243 #define TREE_NOP 00050 /* unused */
244
245 /* suboperations for TREE_SEND */
246 #define TREE_SUBOP 00007
247 #define TREE_NORMAL 00000
248 #define TREE_BINARY_INT 00001
249 #define TREE_BINARY_BOOL 00003 /* 2 skipped - reserved to LIT_CONST */
250 #define TREE_UNARY_SPECIAL 00004
251 #define TREE_UNARY_BOOL 00005
252 #define TREE_STORE_LIT_VAR 00006 /* receiver in V1 */
253 #define TREE_DIRTY_BLOCK 00007 /* doesn't use tree->data! */
254
255 /* stack suboperations value of tree->data */
256 #define TREE_REC_VAR 00000 /* variable number */
257 #define TREE_TEMP 00001 /* variable number */
258 #define TREE_LIT_CONST 00002 /* literal to be pushed */
259 #define TREE_LIT_VAR 00003 /* An gst_association object */
260 #define TREE_DUP 00004 /* unused */
261 #define TREE_SELF 00005 /* unused */
262 #define TREE_OUTER_TEMP 00006 /* unused */
263 #define TREE_POP_INTO_ARRAY 00007 /* index */
264
265 /* suboperations for TREE_NOP */
266 #define TREE_ALREADY_EMITTED 00000
267 #define TREE_TWO_EXTRAS 00001
268
269 /* extra operations */
270 #define TREE_EXTRA 00700
271 #define TREE_EXTRA_NONE 00000
272 #define TREE_EXTRA_JMP_TRUE 00100
273 #define TREE_EXTRA_JMP_FALSE 00200
274 #define TREE_EXTRA_JMP_ALWAYS 00300
275 #define TREE_EXTRA_RETURN 00400
276 #define TREE_EXTRA_METHOD_RET 00500
277 #define TREE_EXTRA_POP 00600
278
279 /* class check flags */
280 #define TREE_CLASS_CHECKS 0x03000L
281 #define TREE_IS_INTEGER 0x01000L
282 #define TREE_IS_NOT_INTEGER 0x02000L
283
284 /* testing macros */
285 #define NOT_INTEGER(tree) ( (tree)->operation & TREE_IS_NOT_INTEGER)
286 #define IS_INTEGER(tree) ( (tree)->operation & TREE_IS_INTEGER)
287 #define IS_PUSH(tree) ( ((tree)->operation & TREE_OP) == TREE_PUSH)
288 #define IS_SEND(tree) ( ((tree)->operation & TREE_OP) == TREE_SEND)
289 #define IS_STORE(tree) ( ((tree)->operation & TREE_OP) == TREE_STORE)
290 #define IS_SET_TOP(tree) ( ((tree)->operation & TREE_OP) == TREE_SET_TOP)
291 #define IS_LITERAL(tree) ( ((tree)->operation & TREE_SUBOP) == TREE_LIT_CONST)
292
293
294
295 /* Strength reduction */
296 static inline int analyze_factor (int x);
297 static inline void analyze_dividend (int imm, int *shift, mst_Boolean *adjust, uintptr_t *factor);
298
299 /* label handling */
300 static inline label *lbl_new (void);
301 static inline jit_insn *lbl_get (label *lbl);
302 static inline void lbl_use (label *lbl, jit_insn *result);
303 static inline mst_Boolean lbl_define (label *lbl);
304 static inline void define_ip_map_entry (int virtualIP);
305
306 /* Inlining (deferred sends) */
307 static void defer_send (code_tree *tree, mst_Boolean isBool, jit_insn *address, int reg0, int reg1, OOP oop);
308 static inline label *last_deferred_send (void);
309 static inline void emit_deferred_sends (deferred_send *ds);
310 static inline void finish_deferred_send (void);
311
312 /* CompiledMethod hash table handling */
313 static method_entry *find_method_entry (OOP methodOOP, OOP receiverClass);
314 static inline void new_method_entry (OOP methodOOP, OOP receiverClass, int size);
315 static inline method_entry *finish_method_entry (void);
316
317 /* code_tree handling */
318 static inline code_tree *push_tree_node (gst_uchar *bp, code_tree *firstChild, int operation, PTR data);
319 static inline code_tree *push_tree_node_oop (gst_uchar *bp, code_tree *firstChild, int operation, OOP literal);
320 static inline code_tree *pop_tree_node (code_tree *linkedChild);
321 static inline code_tree *push_send_node (gst_uchar *bp, OOP selector, int numArgs, mst_Boolean super, int operation, int imm);
322 static inline void set_top_node_extra (int extra, int jumpOffset);
323 static inline gst_uchar *decode_bytecode (gst_uchar *bp);
324
325 static inline void emit_code (void);
326 static void emit_code_tree (code_tree *tree);
327
328 /* Non-bytecode specific code generation functions */
329 static inline void emit_user_defined_method_call (OOP methodOOP, int numArgs, gst_compiled_method method);
330 static inline mst_Boolean emit_method_prolog (OOP methodOOP, gst_compiled_method method);
331 static inline mst_Boolean emit_block_prolog (OOP blockOOP, gst_compiled_block block);
332 static inline mst_Boolean emit_inlined_primitive (int primitive, int numArgs, int attr);
333 static inline mst_Boolean emit_primitive (int primitive, int numArgs);
334
335 static inline void emit_interrupt_check (int restartReg);
336 static inline void generate_run_time_code (void);
337 static inline void translate_method (OOP methodOOP, OOP receiverClass, int size);
338 static void emit_basic_size_in_r0 (OOP classOOP, mst_Boolean tagged, int objectReg);
339
340 /* Code generation functions for bytecodes */
341 static void gen_send (code_tree *tree);
342 static void gen_binary_int (code_tree *tree);
343 static void gen_pop_into_array (code_tree *tree);
344 static void gen_binary_bool (code_tree *tree);
345 static void gen_send_store_lit_var (code_tree *tree);
346 static void gen_dirty_block (code_tree *tree);
347 static void gen_unary_special (code_tree *tree);
348 static void gen_unary_bool (code_tree *tree);
349 static void gen_store_rec_var (code_tree *tree);
350 static void gen_store_temp (code_tree *tree);
351 static void gen_store_lit_var (code_tree *tree);
352 static void gen_store_outer (code_tree *tree);
353 static void gen_push_rec_var (code_tree *tree);
354 static void gen_push_temp (code_tree *tree);
355 static void gen_push_lit_const (code_tree *tree);
356 static void gen_push_lit_var (code_tree *tree);
357 static void gen_dup_top (code_tree *tree);
358 static void gen_push_self (code_tree *tree);
359 static void gen_push_outer (code_tree *tree);
360 static void gen_top_rec_var (code_tree *tree);
361 static void gen_top_temp (code_tree *tree);
362 static void gen_top_self (code_tree *tree);
363 static void gen_top_outer (code_tree *tree);
364 static void gen_alt_rec_var (code_tree *tree);
365 static void gen_alt_temp (code_tree *tree);
366 static void gen_alt_lit_const (code_tree *tree);
367 static void gen_alt_lit_var (code_tree *tree);
368 static void gen_get_top (code_tree *tree);
369 static void gen_alt_self (code_tree *tree);
370 static void gen_alt_outer (code_tree *tree);
371 static void gen_top_lit_const (code_tree *tree);
372 static void gen_top_lit_var (code_tree *tree);
373 static void gen_nothing (code_tree *tree);
374 static void gen_two_extras (code_tree *tree);
375 static void gen_invalid (code_tree *tree);
376
377 /* Function table for the code generator */
378 static const emit_func emit_operation_funcs[96] = {
379 gen_send, gen_binary_int, gen_invalid, gen_binary_bool,
380 gen_unary_special, gen_unary_bool, gen_send_store_lit_var, gen_dirty_block,
381
382 gen_store_rec_var, gen_store_temp, gen_invalid, gen_store_lit_var,
383 gen_invalid, gen_invalid, gen_store_outer, gen_pop_into_array,
384
385 gen_push_rec_var, gen_push_temp, gen_push_lit_const, gen_push_lit_var,
386 gen_dup_top, gen_push_self, gen_push_outer, gen_invalid,
387
388 gen_alt_rec_var, gen_alt_temp, gen_alt_lit_const, gen_alt_lit_var,
389 gen_get_top, gen_alt_self, gen_alt_outer, gen_invalid,
390
391 gen_top_rec_var, gen_top_temp, gen_top_lit_const, gen_top_lit_var,
392 gen_invalid, gen_top_self, gen_top_outer, gen_invalid,
393
394 gen_nothing, gen_two_extras, gen_invalid, gen_invalid,
395 gen_invalid, gen_invalid, gen_invalid, gen_invalid
396 };
397
398 static const int special_send_bytecodes[32] = {
399 TREE_SEND | TREE_BINARY_INT, /* PLUS_SPECIAL */
400 TREE_SEND | TREE_BINARY_INT, /* MINUS_SPECIAL */
401 TREE_SEND | TREE_BINARY_BOOL, /* LESS_THAN_SPECIAL */
402 TREE_SEND | TREE_BINARY_BOOL, /* GREATER_THAN_SPECIAL */
403 TREE_SEND | TREE_BINARY_BOOL, /* LESS_EQUAL_SPECIAL */
404 TREE_SEND | TREE_BINARY_BOOL, /* GREATER_EQUAL_SPECIAL */
405 TREE_SEND | TREE_BINARY_BOOL, /* EQUAL_SPECIAL */
406 TREE_SEND | TREE_BINARY_BOOL, /* NOT_EQUAL_SPECIAL */
407 TREE_SEND | TREE_BINARY_INT, /* TIMES_SPECIAL */
408 TREE_SEND | TREE_NORMAL, /* DIVIDE_SPECIAL */
409 TREE_SEND | TREE_NORMAL, /* REMAINDER_SPECIAL */
410 TREE_SEND | TREE_BINARY_INT, /* BIT_XOR_SPECIAL */
411 TREE_SEND | TREE_NORMAL, /* BIT_SHIFT_SPECIAL */
412 TREE_SEND | TREE_BINARY_INT, /* INTEGER_DIVIDE_SPECIAL */
413 TREE_SEND | TREE_BINARY_INT, /* BIT_AND_SPECIAL */
414 TREE_SEND | TREE_BINARY_INT, /* BIT_OR_SPECIAL */
415 TREE_SEND | TREE_NORMAL, /* AT_SPECIAL */
416 TREE_SEND | TREE_NORMAL, /* AT_PUT_SPECIAL */
417 TREE_SEND | TREE_NORMAL, /* SIZE_SPECIAL */
418 TREE_SEND | TREE_NORMAL, /* CLASS_SPECIAL */
419 TREE_SEND | TREE_UNARY_BOOL, /* IS_NIL_SPECIAL */
420 TREE_SEND | TREE_UNARY_BOOL, /* NOT_NIL_SPECIAL */
421 TREE_SEND | TREE_NORMAL, /* VALUE_SPECIAL */
422 TREE_SEND | TREE_NORMAL, /* VALUE_COLON_SPECIAL */
423 TREE_SEND | TREE_BINARY_BOOL, /* SAME_OBJECT_SPECIAL */
424 TREE_SEND | TREE_UNARY_SPECIAL, /* JAVA_AS_INT_SPECIAL */
425 TREE_SEND | TREE_UNARY_SPECIAL, /* JAVA_AS_LONG_SPECIAL */
426 };
427
428
429
430 /* Runtime support code */
431
432 static void
generate_run_native_code(void)433 generate_run_native_code (void)
434 {
435 static inline_cache ic;
436 static int arg;
437
438 jit_prolog (1);
439 arg = jit_arg_p ();
440 jit_getarg_p (JIT_R0, arg);
441 jit_movi_p (JIT_V1, &ic);
442 jit_ldi_p (JIT_V2, &sp);
443 jit_jmpr (JIT_R0);
444 jit_align (2);
445
446 ic.native_ip = jit_get_label ();
447 jit_ret ();
448 }
449
450 static void
generate_dnu_code(void)451 generate_dnu_code (void)
452 {
453 /* send #doesNotUnderstand: If the method is not understood, the
454 stack is changed to the format needed by #doesNotUnderstand: in
455 lookup_native_ip; no inline caching must take place because we
456 have modify the stack each time they try to send the message. */
457
458 jit_ldi_p (JIT_V2, &sp); /* changed by lookup_method!! */
459 jit_movi_l (JIT_R2, 1);
460 jit_ldi_p (JIT_R0, &_gst_does_not_understand_symbol);
461 jit_ldxi_p (JIT_R1, JIT_V2, -sizeof (PTR));
462 jit_prepare (4);
463 jit_pusharg_p (JIT_V0); /* method_class */
464 jit_pusharg_p (JIT_R1); /* receiver */
465 jit_pusharg_i (JIT_R2); /* numArgs */
466 jit_pusharg_p (JIT_R0); /* selector */
467 jit_finish (PTR_LOOKUP_NATIVE_IP);
468 jit_retval (JIT_R0);
469
470 /* Could crash if again #doesNotUnderstand: -- probably better than
471 an infinite loop. */
472 jit_jmpr (JIT_R0);
473 }
474
475 static void
generate_bad_return_code(void)476 generate_bad_return_code (void)
477 {
478 jit_insn *jmp;
479
480 jit_ldi_p (JIT_V2, &sp);
481 jit_movi_l (JIT_R2, 0);
482 jit_ldi_p (JIT_R0, &_gst_bad_return_error_symbol);
483 jit_ldr_p (JIT_R1, JIT_V2);
484
485 /* load the class of the receiver (which is in R1) */
486 jit_movi_p (JIT_V0, _gst_small_integer_class);
487 jmp = jit_bmsi_l (jit_forward (), JIT_R1, 1);
488 jit_ldxi_p (JIT_V0, JIT_R1, jit_ptr_field (OOP, object));
489 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (gst_object, objClass));
490 jit_patch (jmp);
491
492 jit_prepare (4);
493 jit_pusharg_p (JIT_V0); /* method_class */
494 jit_pusharg_p (JIT_R1); /* receiver */
495 jit_pusharg_i (JIT_R2); /* numArgs */
496 jit_pusharg_p (JIT_R0); /* selector */
497 jit_finish (PTR_LOOKUP_NATIVE_IP);
498 jit_retval (JIT_R0);
499
500 /* Might not be understood... how broken they are :-) */
501 jit_beqi_l (does_not_understand_code, JIT_R0, 0);
502 jit_jmpr (JIT_R0);
503 }
504
505 static void
generate_non_boolean_code(void)506 generate_non_boolean_code (void)
507 {
508 static char methodName[] = "mustBeBoolean";
509
510 jit_ldi_p (JIT_V2, &sp); /* push R0 on the */
511 jit_stxi_p (sizeof (PTR), JIT_V2, JIT_R0); /* Smalltalk stack */
512 jit_addi_p (JIT_V2, JIT_V2, sizeof (PTR));
513 jit_movi_p (JIT_R1, methodName);
514 jit_sti_p (&sp, JIT_V2); /* update SP */
515 jit_sti_p (&_gst_abort_execution, JIT_R1);
516 jit_ret ();
517 }
518
519 static void
generate_do_super_code(void)520 generate_do_super_code (void)
521 {
522 /* load other args into R1/R2 */
523 jit_ldi_l (JIT_R1, &_gst_self);
524 jit_ldxi_uc (JIT_R2, JIT_V1, jit_field (inline_cache, numArgs));
525 jit_ldxi_p (JIT_R0, JIT_V1, jit_field (inline_cache, selector));
526
527 jit_prepare (4);
528 jit_pusharg_p (JIT_V0); /* method_class */
529 jit_pusharg_p (JIT_R1); /* receiver */
530 jit_pusharg_i (JIT_R2); /* numArgs */
531 jit_pusharg_p (JIT_R0); /* selector */
532 jit_finish (PTR_LOOKUP_NATIVE_IP);
533 jit_retval (JIT_R0);
534
535 /* store the address in the inline cache if not #doesNotUnderstand: */
536 jit_beqi_l (does_not_understand_code, JIT_R0, 0);
537 jit_stxi_p (jit_field (inline_cache, cachedIP), JIT_V1, JIT_R0);
538 jit_jmpr (JIT_R0);
539 }
540
541 static void
generate_do_send_code(void)542 generate_do_send_code (void)
543 {
544 jit_insn *jmp;
545
546 /* load other parameters into R0/R2 */
547 jit_ldxi_uc (JIT_R2, JIT_V1, jit_field (inline_cache, numArgs));
548 jit_ldxi_p (JIT_R0, JIT_V1, jit_field (inline_cache, selector));
549
550 /* load _gst_self into R1 */
551 jit_lshi_l (JIT_R1, JIT_R2, LONG_SHIFT);
552 jit_negr_l (JIT_R1, JIT_R1);
553 jit_ldxr_l (JIT_R1, JIT_V2, JIT_R1);
554
555 /* method class */
556 jit_movi_p (JIT_V0, _gst_small_integer_class);
557 jmp = jit_bmsi_l (jit_forward (), JIT_R1, 1);
558 jit_ldxi_p (JIT_V0, JIT_R1, jit_ptr_field (OOP, object));
559 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (gst_object, objClass));
560 jit_patch (jmp);
561
562 jit_prepare (4);
563 jit_pusharg_p (JIT_V0); /* method_class */
564 jit_pusharg_p (JIT_R1); /* receiver */
565 jit_pusharg_i (JIT_R2); /* numArgs */
566 jit_pusharg_p (JIT_R0); /* selector */
567 jit_finish (PTR_LOOKUP_NATIVE_IP);
568 jit_retval (JIT_R0);
569
570 /* store the address in the inline cache if not #doesNotUnderstand: */
571 jit_beqi_l (does_not_understand_code, JIT_R0, 0);
572 jit_stxi_p (jit_field (inline_cache, cachedIP), JIT_V1, JIT_R0);
573 jit_jmpr (JIT_R0);
574 }
575
576 void
generate_run_time_code(void)577 generate_run_time_code (void)
578 {
579 PTR area = xmalloc (10000);
580
581 _gst_run_native_code = jit_set_ip (area).pptr;
582 generate_run_native_code ();
583
584 jit_align (2);
585 does_not_understand_code = jit_get_label ();
586 jit_prolog (1);
587 jit_set_ip (does_not_understand_code);
588 generate_dnu_code ();
589
590 /* send #badReturnError. No inline caching must take place because
591 this is called upon a return, not upon a send. */
592 jit_align (2);
593 bad_return_code = jit_get_label ();
594 jit_prolog (1);
595 jit_set_ip (bad_return_code);
596 generate_bad_return_code ();
597
598 jit_align (2);
599 non_boolean_code = jit_get_label ();
600 jit_prolog (1);
601 jit_set_ip (non_boolean_code);
602 generate_non_boolean_code ();
603
604 jit_align (2);
605 do_super_code = jit_get_label ();
606 jit_prolog (1);
607 jit_set_ip (do_super_code);
608 generate_do_super_code ();
609
610 jit_align (2);
611 do_send_code = jit_get_label ();
612 jit_prolog (1);
613 jit_set_ip (do_send_code);
614 generate_do_send_code ();
615
616 jit_align (2);
617 _gst_return_from_native_code = jit_get_ip ().pptr;
618 jit_prolog (1);
619 jit_set_ip ((void *) _gst_return_from_native_code);
620
621 jit_movi_i (JIT_RET, 0);
622 jit_ret ();
623 }
624
625
626 /* Functions for managing the translated methods' hash table */
627
628 void
new_method_entry(OOP methodOOP,OOP receiverClass,int size)629 new_method_entry (OOP methodOOP, OOP receiverClass, int size)
630 {
631 if (!size)
632 size = GET_METHOD_NUM_ARGS (methodOOP) * 2 + 10;
633
634 current =
635 (method_entry *) xmalloc (MAX_BYTES_PER_BYTECODE * (size + 2));
636 current->methodOOP = methodOOP;
637 current->receiverClass = receiverClass;
638 current->inlineCaches = NULL;
639 methodOOP->flags |= F_XLAT;
640
641 /* The buffer functions in str.c are used to deal with the ip_map. */
642 _gst_reset_buffer ();
643
644 obstack_init (&aux_data_obstack);
645 jit_set_ip (current->nativeCode);
646
647 /* We need to compile a dummy prolog, which we'll overwrite, to make
648 GNU lightning's status consistent with that when the
649 trampolineCode was written. */
650 jit_prolog (1);
651 jit_set_ip (current->nativeCode);
652 }
653
654 method_entry *
finish_method_entry(void)655 finish_method_entry (void)
656 {
657 unsigned int hashEntry;
658 char *codePtr;
659 method_entry *result;
660 int size;
661
662 /* Shrink the method, and store it into the hash table */
663 codePtr = (char *) jit_get_label ();
664 jit_flush_code (current->nativeCode, codePtr);
665
666 result =
667 (method_entry *) xrealloc (current, codePtr - (char *) current);
668 current = NULL;
669
670 /* Copy the IP map, adding a final dummy entry */
671 define_ip_map_entry (-1);
672 size = _gst_buffer_size ();
673 result->ipMap = (ip_map *) xmalloc (size);
674 _gst_copy_buffer (result->ipMap);
675
676 hashEntry = OOP_INDEX (result->methodOOP) % HASH_TABLE_SIZE;
677 result->next = methods_table[hashEntry];
678 methods_table[hashEntry] = result;
679
680 obstack_free (&aux_data_obstack, NULL);
681 return result;
682 }
683
684
685 /* Functions for managing the code_tree */
686
687 code_tree *
push_tree_node(gst_uchar * bp,code_tree * firstChild,int operation,PTR data)688 push_tree_node (gst_uchar *bp, code_tree *firstChild, int operation, PTR data)
689 {
690 code_tree *node =
691 obstack_alloc (&aux_data_obstack, sizeof (code_tree));
692
693 node->child = firstChild;
694 node->next = NULL;
695 node->operation = operation;
696 node->data = data;
697 node->bp = bp;
698 *t_sp++ = node;
699 return (node);
700 }
701
702 code_tree *
push_tree_node_oop(gst_uchar * bp,code_tree * firstChild,int operation,OOP literal)703 push_tree_node_oop (gst_uchar *bp, code_tree *firstChild, int operation, OOP literal)
704 {
705 int classCheck;
706 if (IS_INT (literal))
707 classCheck = TREE_IS_INTEGER;
708 else
709 classCheck = TREE_IS_NOT_INTEGER;
710
711 return push_tree_node (bp, firstChild, operation | classCheck,
712 literal);
713 }
714
715 code_tree *
pop_tree_node(code_tree * linkedChild)716 pop_tree_node (code_tree *linkedChild)
717 {
718 if (t_sp <= t_stack)
719 {
720 /* Stack underflow (note that it can be legal in a few cases,
721 such as for return stack top bytecodes) */
722 return (NULL);
723 }
724 else
725 {
726 code_tree *node = *--t_sp;
727 node->next = linkedChild;
728 return (node);
729 }
730 }
731
732 void
set_top_node_extra(int extra,int jumpOffset)733 set_top_node_extra (int extra, int jumpOffset)
734 {
735 code_tree *node;
736
737 #ifndef OPTIMIZE
738 if (extra == TREE_EXTRA_JMP_ALWAYS
739 || extra == TREE_EXTRA_JMP_TRUE
740 || extra == TREE_EXTRA_JMP_FALSE)
741 assert (this_label[jumpOffset] != NULL);
742 #endif
743
744 if (t_sp <= t_stack)
745 {
746 /* Stack is currently empty -- generate the code directly */
747 if (extra != TREE_EXTRA_JMP_ALWAYS)
748 {
749 OOP selector = GET_METHOD_SELECTOR (current->methodOOP);
750 if (method_class == current->receiverClass)
751 _gst_errorf ("Stack underflow in JIT compilation %O>>%O",
752 current->receiverClass, selector);
753 else
754 _gst_errorf ("Stack underflow in JIT compilation %O(%O)>>%O",
755 current->receiverClass, method_class, selector);
756
757 abort ();
758 }
759 node = alloca (sizeof (code_tree));
760
761 node->child = node->next = NULL;
762 node->operation = TREE_NOP | TREE_ALREADY_EMITTED | extra;
763 node->jumpDest = this_label[jumpOffset];
764 emit_code_tree (node);
765 return;
766 }
767
768 node = t_sp[-1];
769 if (node->operation & TREE_EXTRA)
770 {
771 /* More than one extra operation -- add a fake node */
772 node = obstack_alloc (&aux_data_obstack, sizeof (code_tree));
773 node->child = NULL;
774 node->next = t_sp[-1];
775 node->operation = TREE_NOP | TREE_TWO_EXTRAS;
776 t_sp[-1] = node;
777 }
778
779 node->operation |= extra;
780 node->jumpDest = this_label[jumpOffset];
781 }
782
783 static inline inline_cache *
set_inline_cache(OOP selector,int numArgs,mst_Boolean super,int operation,int imm)784 set_inline_cache (OOP selector, int numArgs, mst_Boolean super, int operation, int imm)
785 {
786 curr_inline_cache->numArgs = numArgs;
787 curr_inline_cache->selector = selector;
788 curr_inline_cache->cachedIP = super ? do_super_code : do_send_code;
789 curr_inline_cache->is_super = super;
790 curr_inline_cache->more = true;
791 curr_inline_cache->imm = imm;
792 return curr_inline_cache++;
793 }
794
795 code_tree *
push_send_node(gst_uchar * bp,OOP selector,int numArgs,mst_Boolean super,int operation,int imm)796 push_send_node (gst_uchar *bp, OOP selector, int numArgs, mst_Boolean super, int operation, int imm)
797 {
798 code_tree *args, *node;
799 int tot_args;
800 inline_cache *ic = set_inline_cache (selector, numArgs, super, operation, imm);
801
802 /* Remember that we must pop an extra node for the receiver! */
803 tot_args = numArgs + (super ? 2 : 1);
804 for (args = NULL; tot_args--;)
805 args = pop_tree_node (args);
806
807 node = push_tree_node (bp, args, operation, (PTR) ic);
808 return (node);
809 }
810
811 void
emit_code(void)812 emit_code (void)
813 {
814 code_tree **pTree, *tree;
815
816 for (pTree = t_stack; pTree < t_sp; pTree++)
817 {
818 tree = *pTree;
819 emit_code_tree (tree);
820 }
821
822 rec_var_cached = false;
823 stack_cached = -1;
824 self_cached = false;
825 }
826
827
828 /* A couple of commodities for strength reduction */
829
830 int
analyze_factor(int x)831 analyze_factor (int x)
832 {
833 int a;
834 int b, c;
835
836 a = x & (x - 1); /* clear lowest bit */
837 a &= a - 1; /* again */
838
839 if (a) /* more than two bits are set to 1 */
840 return 0; /* don't attempt strength reduction */
841
842 for (b = 0; (x & 1) == 0; b++, x >>= 1);
843 if (x == 1)
844 return b; /* a single bit was set */
845
846 for (c = b + 1; (x & 2) == 0; c++, x >>= 1);
847 return b | (c << 8);
848 }
849
850 void
analyze_dividend(int imm,int * shift,mst_Boolean * adjust,uintptr_t * factor)851 analyze_dividend (int imm, int *shift, mst_Boolean *adjust, uintptr_t *factor)
852 {
853 int x, b, r;
854 double f;
855
856 *adjust = 0;
857
858 /* compute floor(log2 imm) */
859 for (r = 0, x = imm >> 1; x; r++, x >>= 1);
860
861 if (!(imm & (imm - 1)))
862 {
863 /* x is a power of two */
864 *shift = r;
865 *factor = 0;
866 return;
867 }
868
869 r += 31;
870 f = ldexp (((double) 1.0) / imm, r);
871 b = (int) floor (f);
872
873 if ((f - (double) b) < 0.5)
874 /* round f down to nearest integer, compute ((x + 1) * f) >> r */
875 ++*adjust;
876 else
877 /* round f up to nearest integer, compute (x * f) >> r */
878 ++b;
879
880 /* Try to shift less bits */
881 while ((r >= 32) && ((b & 1) == 0))
882 {
883 r--;
884 b >>= 1;
885 }
886
887 *factor = b;
888 *shift = r - 32;
889 }
890
891
892 /* Functions for managing labels and forward references */
893
894 label *
lbl_new(void)895 lbl_new (void)
896 {
897 label *lbl = obstack_alloc (&aux_data_obstack, sizeof (label));
898 lbl->addr = NULL;
899 lbl->uses = NULL;
900 #ifdef DEBUG_LABELS
901 printf ("Defined reference at %p\n", lbl);
902 #endif
903 return lbl;
904 }
905
906 jit_insn *
lbl_get(label * lbl)907 lbl_get (label *lbl)
908 {
909 return lbl->addr ? lbl->addr : jit_forward ();
910 }
911
912 void
lbl_use(label * lbl,jit_insn * result)913 lbl_use (label *lbl, jit_insn *result)
914 {
915 if (!lbl->addr)
916 {
917 /* forward reference */
918 label_use *use =
919 obstack_alloc (&aux_data_obstack, sizeof (label_use));
920 #ifdef DEBUG_LABELS
921 printf ("Forward reference at %p to %p (next = %p)\n",
922 result, lbl, lbl->uses);
923 #endif
924 use->addr = result;
925 use->next = lbl->uses;
926 lbl->uses = use;
927 }
928 #ifdef DEBUG_LABELS
929 else
930 printf ("Backward reference at %p to %p (%p)\n", result,
931 lbl->addr, lbl);
932 #endif
933 }
934
935 mst_Boolean
lbl_define(label * lbl)936 lbl_define (label *lbl)
937 {
938 label_use *use = lbl->uses;
939 mst_Boolean used;
940
941 jit_align (2);
942 lbl->addr = jit_get_label ();
943 used = (use != NULL);
944
945 #ifdef DEBUG_LABELS
946 printf ("Defined label at %p (%p)\n", lbl->addr, lbl);
947 #endif
948 while (use)
949 {
950 label_use *next = use->next;
951 #ifdef DEBUG_LABELS
952 printf ("Resolving forward reference at %p\n", use->addr);
953 #endif
954 jit_patch (use->addr);
955 use = next;
956 }
957
958 return (used);
959 }
960
961 void
define_ip_map_entry(int virtualIP)962 define_ip_map_entry (int virtualIP)
963 {
964 ip_map mapEntry;
965 mapEntry.virtualIP = virtualIP;
966 mapEntry.native_ip = jit_get_label ();
967
968 _gst_add_buf_data (&mapEntry, sizeof (mapEntry));
969 }
970
971 void
finish_deferred_send(void)972 finish_deferred_send (void)
973 {
974 if (!deferred_head->trueDest)
975 {
976 deferred_head->trueDest = lbl_new ();
977 lbl_define (deferred_head->trueDest);
978 if (!deferred_head->falseDest)
979 deferred_head->falseDest = deferred_head->trueDest;
980 }
981
982 else if (!deferred_head->falseDest)
983 {
984 deferred_head->falseDest = lbl_new ();
985 lbl_define (deferred_head->falseDest);
986 }
987 }
988
989 label *
last_deferred_send(void)990 last_deferred_send (void)
991 {
992 return deferred_head->address;
993 }
994
995 void
defer_send(code_tree * tree,mst_Boolean isBool,jit_insn * address,int reg0,int reg1,OOP oop)996 defer_send (code_tree *tree, mst_Boolean isBool, jit_insn *address, int reg0, int reg1, OOP oop)
997 {
998 deferred_send *ds =
999 obstack_alloc (&aux_data_obstack, sizeof (deferred_send));
1000
1001 if (isBool)
1002 {
1003 switch (tree->operation & TREE_EXTRA)
1004 {
1005 case TREE_EXTRA_NONE:
1006 case TREE_EXTRA_POP:
1007 case TREE_EXTRA_RETURN:
1008 case TREE_EXTRA_METHOD_RET:
1009 case TREE_EXTRA_JMP_ALWAYS:
1010 isBool = false;
1011 }
1012 }
1013
1014 ds->next = deferred_head;
1015 ds->tree = tree;
1016 ds->reg0 = reg0;
1017 ds->reg1 = reg1;
1018 ds->oop = oop;
1019 ds->address = lbl_new ();
1020
1021 if (address)
1022 lbl_use (ds->address, address);
1023
1024 if (isBool)
1025 {
1026 if ((tree->operation & TREE_EXTRA) == TREE_EXTRA_JMP_TRUE)
1027 {
1028 ds->trueDest = tree->jumpDest;
1029 ds->falseDest = NULL;
1030 }
1031 else
1032 {
1033 ds->falseDest = tree->jumpDest;
1034 ds->trueDest = NULL;
1035 }
1036 }
1037 else
1038 ds->trueDest = ds->falseDest = NULL;
1039
1040 deferred_head = ds;
1041 }
1042
1043 /* Register usage:
1044 * R0 scratch
1045 * R1 cached address of 1st instance variable
1046 * R2 scratch
1047 * V0 stack top
1048 * V1 cache address of 1st temporary or an outer context
1049 * (also) pointer to the inline_cache upon a send
1050 * V2 stack pointer
1051 */
1052
1053
1054 /* Common pieces of code for generating stack operations */
1055
1056 /* Save the old stack top if it was cached in V0 */
1057 #define BEFORE_PUSH(reg) do { \
1058 sp_delta += sizeof (PTR); \
1059 if (sp_delta > 0) { \
1060 jit_stxi_p(sp_delta, JIT_V2, (reg)); \
1061 } \
1062 } while(0)
1063
1064 /* Generate code to evaluate the value to be replaced. Generate
1065 * a `pop' by decrementing V2 unless the stack top is cached in V0 -- in
1066 * this case we can simply overwrite it.
1067 */
1068 #define BEFORE_SET_TOP do { \
1069 if (tree->child) { \
1070 emit_code_tree(tree->child); \
1071 } \
1072 if (sp_delta < 0) { \
1073 jit_subi_p(JIT_V2, JIT_V2, sizeof (PTR)); /* pop stack top */ \
1074 sp_delta += sizeof (PTR); \
1075 } \
1076 } while(0)
1077
1078 /* Generate code to evaluate the value to be stored, and have it loaded
1079 * in V0. */
1080 #define BEFORE_STORE do { \
1081 emit_code_tree(tree->child); \
1082 if (sp_delta < 0) { \
1083 jit_ldr_p(JIT_V0, JIT_V2); \
1084 jit_subi_p(JIT_V2, JIT_V2, sizeof (PTR)); /* pop stack top */ \
1085 sp_delta += sizeof (PTR); \
1086 } \
1087 } while(0)
1088
1089
1090 /* Common pieces of code for generating & caching addresses */
1091
1092 #define TEMP_OFS(tree) (sizeof (PTR) * (((intptr_t) ((tree)->data)) & 255))
1093 #define REC_VAR_OFS(tree) jit_ptr_field(gst_object, data[(intptr_t) ((tree)->data)])
1094 #define STACK_OFS(tree) (jit_ptr_field(gst_block_context, contextStack) + \
1095 TEMP_OFS (tree))
1096
1097
1098 /* Cache the address of the first instance variable in R1 */
1099 #define CACHE_REC_VAR do { \
1100 if (!rec_var_cached) { /* in R1 */ \
1101 if (!self_cached) { /* in V0 */ \
1102 jit_ldi_p(JIT_R1, &_gst_self); \
1103 jit_ldxi_p(JIT_R1, JIT_R1, jit_ptr_field(OOP, object)); \
1104 } else { \
1105 jit_ldxi_p(JIT_R1, JIT_V0, jit_ptr_field(OOP, object)); \
1106 } \
1107 rec_var_cached = true; \
1108 } \
1109 } while(0)
1110
1111 /* Cache the address of the first temporary variable in V1 */
1112 #define CACHE_TEMP do { \
1113 if (stack_cached != 0) { /* in V1 */ \
1114 jit_ldi_p(JIT_V1, &_gst_temporaries); \
1115 stack_cached = 0; \
1116 } \
1117 } while(0)
1118
1119 #define CACHE_NOTHING do { \
1120 rec_var_cached = false; \
1121 stack_cached = -1; \
1122 self_cached = false; \
1123 } while(0)
1124
1125 /* Cache into V1 the address of the outer context specified by the
1126 code_tree. If the address of another outer context (whose depth is
1127 lower) is currently cached, avoid walking the list of outer
1128 contexts from the start. This optimizes bytecode sequences such as
1129
1130 push outer variable, n = 1, index = 2
1131 store outer variable, n = 2, index = 0
1132
1133 Remember that stack_cached = 0 means `cache the address of the
1134 first temporary' (the address of the Context's first *indexed*
1135 instance variable), while stack_cached > 0 means `cache the address
1136 of the n-th outer context' (i.e. the address of the Context's first
1137 *fixed* instance variable). Although confusing, this was done
1138 because the VM provides the address of the first indexed instance
1139 variable for thisContext into the `_gst_temporaries' variable. */
1140 #define CACHE_OUTER_CONTEXT do { \
1141 int scopes; \
1142 scopes = ((int) tree->data) >> 8; \
1143 if (stack_cached <= 0 || stack_cached > scopes) { \
1144 jit_ldi_p(JIT_V1, &_gst_this_context_oop); \
1145 jit_ldxi_p(JIT_V1, JIT_V1, jit_ptr_field(OOP, object)); \
1146 stack_cached = scopes; \
1147 } else { \
1148 scopes -= stack_cached; \
1149 stack_cached += scopes; \
1150 } \
1151 while (scopes--) { \
1152 jit_ldxi_p(JIT_V1, JIT_V1, jit_ptr_field(gst_block_context, outerContext)); \
1153 jit_ldxi_p(JIT_V1, JIT_V1, jit_ptr_field(OOP, object)); \
1154 } \
1155 } while(0)
1156
1157
1158 /* Miscellaneous pieces of code */
1159
1160 /* Push the children on the stack -- needed for sends */
1161 #define PUSH_CHILDREN do { \
1162 code_tree *child; \
1163 \
1164 /* Emit code to generate the receiver and the arguments */ \
1165 for(child = tree->child; child; child = child->next) { \
1166 emit_code_tree(child); \
1167 } \
1168 } while(0)
1169
1170 /* Remember that the stack top is cached in V0, and import V2 (the
1171 * stack pointer) from the sp variable. */
1172 #define KEEP_V0_IMPORT_SP do { \
1173 jit_ldi_p(JIT_V2, &sp); \
1174 sp_delta = 0; \
1175 } while(0)
1176
1177 /* Remember that the stack top is *not* cached in V0, and import V2 (the
1178 * stack pointer) from the sp variable. */
1179 #define IMPORT_SP do { \
1180 jit_ldi_p(JIT_V2, &sp); \
1181 sp_delta = -sizeof (PTR); \
1182 } while(0)
1183
1184 /* Export V2 (the stack pointer) into the sp variable; the top of the
1185 * stack is assured to be in *sp, not in V0. */
1186 #define EXPORT_SP(reg) do { \
1187 if (sp_delta >= 0) { \
1188 sp_delta += sizeof (PTR); \
1189 jit_stxi_p(sp_delta, JIT_V2, (reg)); \
1190 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1191 jit_sti_p(&sp, JIT_V2); \
1192 sp_delta = -sizeof (PTR); \
1193 } \
1194 } while(0)
1195
1196 /* Export V2 (the stack pointer) into the sp variable; the top of the
1197 * stack is assured to be in *sp AND in V0. */
1198 #define CACHE_STACK_TOP do { \
1199 if (sp_delta < 0) { \
1200 jit_ldr_p(JIT_V0, JIT_V2); \
1201 } else { \
1202 EXPORT_SP (JIT_V0); \
1203 } \
1204 } while(0)
1205
1206 /* Export V2 (the stack pointer) into the sp variable, without pushing
1207 * the value cached in V0. */
1208 #define KEEP_V0_EXPORT_SP do { \
1209 if (sp_delta < 0) { \
1210 jit_ldr_p(JIT_V0, JIT_V2); \
1211 } \
1212 if (sp_delta != 0) { \
1213 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1214 } \
1215 jit_sti_p(&sp, JIT_V2); \
1216 sp_delta = -sizeof (PTR); \
1217 } while(0)
1218
1219 /* Export V2 (the stack pointer) into the sp variable, without
1220 * saving the old stack top if it was cached in V0. */
1221 #define POP_EXPORT_SP do { \
1222 if (sp_delta) { \
1223 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1224 } \
1225 jit_sti_p(&sp, JIT_V2); \
1226 jit_ldr_p(JIT_V0, JIT_V2); \
1227 sp_delta = -sizeof (PTR); \
1228 } while(0)
1229
1230 /* Do a conditional jump to tree->jumpDest if the top of the stack
1231 * is successOOP, or to non_boolean_code if it is anything but failOOP. */
1232 #define CONDITIONAL_JUMP(successOOP, failOOP) do { \
1233 jit_insn *addr; \
1234 \
1235 /* Save the value of the top of the stack */ \
1236 if (sp_delta < 0) { \
1237 jit_ldr_p(JIT_R0, JIT_V2); \
1238 } else { \
1239 jit_movr_p(JIT_R0, JIT_V0); \
1240 } \
1241 POP_EXPORT_SP; \
1242 \
1243 addr = lbl_get(tree->jumpDest); \
1244 addr = jit_beqi_p(addr, JIT_R0, successOOP); \
1245 lbl_use(tree->jumpDest, addr); \
1246 jit_bnei_p(non_boolean_code, JIT_R0, failOOP); \
1247 \
1248 CACHE_NOTHING; \
1249 } while(0)
1250
1251
1252
1253 /* Pieces of code for inlining */
1254
1255 /* Don't inline if doing a send to super */
1256 #define DONT_INLINE_SUPER do { \
1257 if(ic->is_super) { \
1258 gen_send(tree); \
1259 return; \
1260 } \
1261 } while(0)
1262
1263 /* Don't attempt to inline an arithmetic operation if one of its
1264 * argument is known not to be a SmallInteger.
1265 */
1266 #define DONT_INLINE_NONINTEGER do { \
1267 if (NOT_INTEGER(tree->child) || NOT_INTEGER(tree->child->next)) { \
1268 gen_send(tree); \
1269 return; \
1270 } \
1271 } while(0)
1272
1273 /* Create a `true' or `false' oop if the value is required `as is'; else
1274 * compile a `jump if true' or `jump if false' native opcode. This is
1275 * the equivalent of the `jump lookahead' option in the bytecode interpreter.
1276 */
1277 #define INLINED_CONDITIONAL do { \
1278 jit_insn *addr; \
1279 \
1280 switch (tree->operation & TREE_EXTRA) { \
1281 case TREE_EXTRA_NONE: \
1282 case TREE_EXTRA_POP: \
1283 case TREE_EXTRA_RETURN: \
1284 case TREE_EXTRA_METHOD_RET: \
1285 case TREE_EXTRA_JMP_ALWAYS: \
1286 FALSE_SET(JIT_R0); \
1287 jit_lshi_i(JIT_R0, JIT_R0, LONG_SHIFT+1); \
1288 jit_addi_p(JIT_V0, JIT_R0, _gst_true_oop); \
1289 break; \
1290 \
1291 case TREE_EXTRA_JMP_TRUE: \
1292 case TREE_EXTRA_JMP_FALSE: \
1293 if (sp_delta) { \
1294 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1295 } \
1296 sp_delta = -sizeof (PTR); \
1297 addr = lbl_get(tree->jumpDest); \
1298 if ((tree->operation & TREE_EXTRA) == TREE_EXTRA_JMP_TRUE) { \
1299 TRUE_BRANCH(addr); \
1300 } else { \
1301 FALSE_BRANCH(addr); \
1302 } \
1303 lbl_use(tree->jumpDest, addr); \
1304 \
1305 /* Change the code_tree's operation to TREE_ALREADY_EMITTED */ \
1306 tree->operation &= TREE_CLASS_CHECKS; \
1307 tree->operation |= TREE_NOP | TREE_ALREADY_EMITTED; \
1308 break; \
1309 } \
1310 } while(0)
1311
1312
1313 /* Generate code for the only argument, and get the argument in V0.
1314 * Think twice about it, it is the same as the code needed to compile
1315 * a store!
1316 */
1317 #define GET_UNARY_ARG BEFORE_STORE
1318
1319 /* Load the two arguments of an inlined binary message, optimizing the
1320 * common case when the second one is a literal (a == 5, a + 2).
1321 * reg0 and reg1 will contain the registers in which the arguments have
1322 * been loaded.
1323 */
1324 #define GET_BINARY_ARGS do { \
1325 code_tree *second = tree->child->next; \
1326 \
1327 emit_code_tree(tree->child); \
1328 oop = NULL; \
1329 reg0 = JIT_V0; \
1330 reg1 = JIT_V1; \
1331 if (IS_LITERAL(second)) { \
1332 if (sp_delta < 0) { \
1333 jit_ldr_p(JIT_V0, JIT_V2); \
1334 } \
1335 reg1 = JIT_NOREG; \
1336 oop = (OOP) second->data; \
1337 } else if (IS_PUSH(second)) { \
1338 if (sp_delta < 0) { \
1339 jit_ldr_p(JIT_V0, JIT_V2); \
1340 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1341 sp_delta = 0; \
1342 } \
1343 /* Load the second operand into V1 */ \
1344 second->operation ^= TREE_PUSH ^ TREE_ALT_PUSH; \
1345 emit_code_tree(second); \
1346 } else { \
1347 emit_code_tree(second); \
1348 if (sp_delta < 0) { \
1349 /* We load the 2nd argument and then the 1st */ \
1350 jit_ldr_p(JIT_V1, JIT_V2); \
1351 jit_ldxi_p(JIT_V0, JIT_V2, -sizeof (PTR)); \
1352 } else { \
1353 /* We load the 1st argument; the 2nd is already in V0 */ \
1354 jit_ldxi_p(JIT_V1, JIT_V2, sp_delta); \
1355 reg0 = JIT_V1; \
1356 reg1 = JIT_V0; \
1357 } \
1358 /* "Pop" the 2nd argument */ \
1359 sp_delta -= sizeof (PTR); \
1360 } \
1361 \
1362 if (sp_delta) { \
1363 jit_addi_p(JIT_V2, JIT_V2, sp_delta); \
1364 sp_delta = 0; \
1365 } \
1366 CACHE_NOTHING; \
1367 } while(0)
1368
1369 /* jump out of the instruction flow (to a send whose compilation is
1370 * deferred to after we compiled the method bytecodes) if one or both
1371 * arguments are not SmallIntegers.
1372 */
1373 #define ENSURE_INT_ARGS(isBool, overflow) do { \
1374 jit_insn *classCheck; \
1375 \
1376 if (IS_INTEGER(tree->child) && IS_INTEGER(tree->child->next)) { \
1377 if (isBool || IS_INTEGER(tree)) { \
1378 /* No need to do class checks & deferred sends */ \
1379 overflow = NULL; \
1380 break; \
1381 } \
1382 classCheck = NULL; \
1383 } else if (IS_INTEGER(tree->child)) { \
1384 classCheck = jit_bmci_ul(jit_forward(), reg1, 1); \
1385 } else if (IS_INTEGER(tree->child->next)) { \
1386 classCheck = jit_bmci_ul(jit_forward(), reg0, 1); \
1387 } else { \
1388 jit_andr_ul(JIT_R2, JIT_V0, JIT_V1); \
1389 classCheck = jit_bmci_ul(jit_forward(), JIT_R2, 1); \
1390 } \
1391 \
1392 defer_send(tree, isBool, classCheck, reg0, reg1, oop); \
1393 overflow = last_deferred_send(); \
1394 } while(0)
1395
1396 /* These are used to simplify the inlining code, as they group the
1397 * `second operand is a literal' and `second operand is a register'
1398 * cases in a single statement. */
1399 #define EXPAND_(what) what
1400 #define IMM_OR_REG(opcode, a) \
1401 ((reg1 != JIT_NOREG) \
1402 ? EXPAND_(jit_##opcode##r_l(a, reg0, reg1)) \
1403 : EXPAND_(jit_##opcode##i_l(a, reg0, (intptr_t) oop)))
1404
1405
1406
1407 /* gst_message sends */
1408 void
gen_send(code_tree * tree)1409 gen_send (code_tree *tree)
1410 {
1411 inline_cache *ic = (inline_cache *) tree->data;
1412
1413 PUSH_CHILDREN;
1414 jit_movi_p (JIT_V1, ic);
1415 if (ic->is_super)
1416 KEEP_V0_EXPORT_SP;
1417 else
1418 EXPORT_SP (JIT_V0);
1419
1420 jit_movi_ul (JIT_R0, tree->bp - bc + BYTECODE_SIZE);
1421 jit_ldxi_p (JIT_R1, JIT_V1, jit_field (inline_cache, cachedIP));
1422 jit_sti_ul (&ip, JIT_R0);
1423
1424 jit_jmpr (JIT_R1);
1425 jit_align (2);
1426
1427 ic->native_ip = jit_get_label ();
1428 define_ip_map_entry (tree->bp - bc + BYTECODE_SIZE);
1429
1430 IMPORT_SP;
1431 CACHE_NOTHING;
1432 }
1433
1434 void
gen_binary_int(code_tree * tree)1435 gen_binary_int (code_tree *tree)
1436 {
1437 inline_cache *ic = (inline_cache *) tree->data;
1438 label *overflow;
1439 int reg0, reg1;
1440 OOP oop;
1441 intptr_t imm;
1442 jit_insn *addr;
1443
1444 DONT_INLINE_SUPER;
1445 DONT_INLINE_NONINTEGER;
1446 GET_BINARY_ARGS;
1447 ENSURE_INT_ARGS (false, overflow);
1448
1449 imm = (intptr_t) oop;
1450
1451 /* Now generate the code for the inlined operation. Don't touch
1452 reg0/reg1 until we are sure that no overflow happens! */
1453 switch (ic->imm)
1454 {
1455 case PLUS_SPECIAL:
1456 if (reg1 == JIT_NOREG)
1457 {
1458 imm--; /* strip tag bit */
1459 if (imm == 0)
1460 {
1461 if (reg0 != JIT_V0)
1462 {
1463 jit_movr_l (JIT_V0, reg0);
1464 }
1465 break;
1466 }
1467
1468 if (overflow)
1469 {
1470 jit_movr_l (JIT_R0, reg0);
1471 addr = lbl_get (overflow);
1472 addr = jit_boaddi_l (addr, JIT_R0, imm);
1473 lbl_use (overflow, addr);
1474 jit_movr_l (JIT_V0, JIT_R0);
1475 }
1476 else
1477 jit_addi_l (JIT_V0, reg0, imm);
1478
1479 }
1480 else
1481 {
1482 jit_subi_l (JIT_R0, reg0, 1); /* remove the tag bit */
1483 if (overflow)
1484 {
1485 addr = lbl_get (overflow);
1486 addr = jit_boaddr_l (addr, JIT_R0, reg1);
1487 lbl_use (overflow, addr);
1488 jit_movr_l (JIT_V0, JIT_R0);
1489 }
1490 else
1491 jit_addr_l (JIT_V0, reg0, reg1);
1492 }
1493 break;
1494
1495
1496
1497 case MINUS_SPECIAL:
1498 if (reg1 == JIT_NOREG)
1499 {
1500 imm--; /* strip tag bit */
1501 if (imm == 0)
1502 {
1503 if (reg0 != JIT_V0)
1504 {
1505 jit_movr_l (JIT_V0, reg0);
1506 }
1507 break;
1508 }
1509
1510 if (overflow)
1511 {
1512 jit_movr_l (JIT_R0, reg0);
1513 addr = lbl_get (overflow);
1514 addr = jit_bosubi_l (addr, JIT_R0, imm);
1515 lbl_use (overflow, addr);
1516 jit_movr_l (JIT_V0, JIT_R0);
1517 }
1518 else
1519 jit_subi_l (JIT_V0, reg0, imm);
1520
1521 }
1522 else
1523 {
1524 if (overflow)
1525 {
1526 jit_movr_l (JIT_R0, reg0);
1527 addr = lbl_get (overflow);
1528 addr = jit_bosubr_l (addr, JIT_R0, reg1);
1529 lbl_use (overflow, addr);
1530 jit_addi_l (JIT_V0, JIT_R0, 1); /* add back the tag bit
1531 */
1532 }
1533 else
1534 {
1535 jit_subr_l (JIT_V0, reg0, reg1);
1536 jit_addi_l (JIT_V0, JIT_V0, 1); /* add back the tag bit
1537 */
1538 }
1539 }
1540 break;
1541
1542
1543
1544 case TIMES_SPECIAL:
1545 if (reg1 == JIT_NOREG)
1546 {
1547 jit_insn *addr1, *addr2;
1548 int reduce;
1549
1550 imm >>= 1;
1551 if (imm == 0)
1552 {
1553 jit_movi_p (JIT_V0, FROM_INT (0));
1554 break;
1555 }
1556 else if (imm == 1)
1557 {
1558 if (reg0 != JIT_V0)
1559 jit_movr_p (JIT_V0, reg0);
1560 break;
1561 }
1562 else if (imm == -1)
1563 {
1564 if (overflow)
1565 {
1566 addr = lbl_get (overflow);
1567 addr = jit_beqi_p (addr, reg0, FROM_INT (MIN_ST_INT));
1568 lbl_use (overflow, addr);
1569 }
1570 jit_rsbi_l (JIT_V0, reg0, 2);
1571 break;
1572 }
1573
1574 if (overflow)
1575 {
1576 addr = lbl_get (overflow);
1577 if (imm < 0)
1578 {
1579 addr1 =
1580 jit_blti_p (addr, reg0,
1581 FROM_INT (MIN_ST_INT / -imm));
1582 addr2 =
1583 jit_bgti_p (addr, reg0,
1584 FROM_INT (MAX_ST_INT / -imm));
1585 }
1586 else
1587 {
1588 addr1 =
1589 jit_blti_p (addr, reg0,
1590 FROM_INT (MIN_ST_INT / imm));
1591 addr2 =
1592 jit_bgti_p (addr, reg0,
1593 FROM_INT (MAX_ST_INT / imm));
1594 }
1595 lbl_use (overflow, addr1);
1596 lbl_use (overflow, addr2);
1597 }
1598
1599 /* Do some strength reduction... */
1600 reduce = analyze_factor (imm);
1601 if (reduce == 0)
1602 jit_muli_l (JIT_V0, reg0, imm);
1603
1604 else if ((reduce & 0x00FF00) == 0)
1605 jit_lshi_l (JIT_V0, reg0, reduce);
1606
1607 else if (reduce & 255)
1608 {
1609 jit_lshi_l (JIT_R0, reg0, reduce & 255);
1610 jit_lshi_l (JIT_V0, reg0, reduce >> 8);
1611 jit_addr_l (JIT_V0, JIT_V0, JIT_R0);
1612 }
1613 else
1614 {
1615 jit_lshi_l (JIT_R0, reg0, reduce >> 8);
1616 jit_addr_l (JIT_V0, reg0, JIT_R0);
1617 }
1618
1619 /* remove the excess due to the tag bit: ((x-1) / 2 * imm) *
1620 2 + 1 = x * imm - imm + 1 = (x*imm) - (imm-1) */
1621 jit_subi_l (JIT_V0, reg0, imm - 1);
1622
1623 }
1624 else
1625 {
1626 jit_rshi_l (JIT_R1, reg0, 1);
1627 jit_rshi_l (JIT_R0, reg1, 1);
1628 jit_mulr_l (JIT_R2, JIT_R0, JIT_R1);
1629 if (overflow)
1630 {
1631 jit_hmulr_l (JIT_R0, JIT_R0, JIT_R1); /* compute high
1632 bits */
1633
1634 /* check for sensible bits of the result in R0, and in
1635 bits 30-31 of R2 */
1636 jit_rshi_i (JIT_R1, JIT_R0, sizeof (PTR) * 8 - 1);
1637 addr = lbl_get (overflow);
1638 addr = jit_bner_l (addr, JIT_R0, JIT_R1);
1639 lbl_use (overflow, addr);
1640
1641 jit_xorr_i (JIT_R1, JIT_R0, JIT_R2);
1642 addr = lbl_get (overflow);
1643 addr =
1644 jit_bmsi_l (addr, JIT_R1, 3 << (sizeof (PTR) * 8 - 2));
1645 lbl_use (overflow, addr);
1646 }
1647
1648 jit_addr_l (JIT_V0, JIT_R2, JIT_R2);
1649 jit_ori_l (JIT_V0, JIT_V0, 1);
1650 }
1651 break;
1652
1653
1654
1655 case INTEGER_DIVIDE_SPECIAL:
1656 if (reg1 == JIT_NOREG)
1657 {
1658 int shift;
1659 mst_Boolean adjust;
1660 uintptr_t factor;
1661
1662 imm >>= 1;
1663 if (imm == 0)
1664 {
1665 addr = lbl_get (overflow);
1666 addr = jit_jmpi (addr);
1667 lbl_use (overflow, addr);
1668 break;
1669 }
1670 else if (imm == 1)
1671 {
1672 if (reg0 != JIT_V0)
1673 jit_movr_p (JIT_V0, reg0);
1674 break;
1675 }
1676 else if (imm == -1)
1677 {
1678 if (overflow)
1679 {
1680 addr = lbl_get (overflow);
1681 addr = jit_beqi_p (addr, reg0, FROM_INT (MIN_ST_INT));
1682 lbl_use (overflow, addr);
1683 }
1684 jit_rsbi_l (JIT_V0, reg0, 2);
1685 break;
1686 }
1687
1688 jit_rshi_l (reg0, reg0, 1);
1689
1690 if (imm < 0)
1691 {
1692 jit_negr_l (reg0, reg0);
1693 imm = -imm;
1694 }
1695
1696 /* Fix the sign of the result: reg0 = imm - _gst_self - 1 if
1697 reg0 < 0 All these instructions are no-ops if reg0 > 0,
1698 because R0=R1=0 */
1699 jit_rshi_l (JIT_R0, reg0, 8 * sizeof (PTR) - 1);
1700 jit_andi_l (JIT_R1, JIT_R0, imm - 1); /* if reg0 < 0, reg0
1701 is... */
1702 jit_subr_l (reg0, reg0, JIT_R1); /* _gst_self - imm + 1 */
1703 jit_xorr_l (reg0, reg0, JIT_R0); /* imm - _gst_self - 2 */
1704 jit_subr_l (reg0, reg0, JIT_R0); /* imm - _gst_self - 1 */
1705
1706 /* Do some strength reduction... */
1707 analyze_dividend (imm, &shift, &adjust, &factor);
1708
1709 if (adjust)
1710 {
1711 /* If adjust is true, we have to sum 1 here, and the
1712 carry after the multiplication. */
1713 jit_movi_l (JIT_R1, 0);
1714 jit_addci_l (reg0, reg0, 1);
1715 jit_addxi_l (JIT_R1, JIT_R1, 0);
1716 }
1717
1718 shift--; /* for the tag bit */
1719 if (factor)
1720 jit_hmuli_l (reg0, reg0, factor);
1721
1722 if (shift < 0)
1723 jit_lshi_l (reg0, reg0, -shift);
1724 else if (shift > 0)
1725 jit_rshi_l (reg0, reg0, shift);
1726
1727 if (adjust)
1728 jit_subr_l (reg0, reg0, JIT_R1);
1729
1730 /* negate the result if the signs were different */
1731 jit_xorr_l (reg0, reg0, JIT_R0);
1732 jit_subr_l (reg0, reg0, JIT_R0);
1733
1734 /* now add the tag bit */
1735 jit_ori_l (JIT_V0, reg0, 1);
1736
1737 }
1738 else
1739 {
1740 if (overflow)
1741 {
1742 addr = lbl_get (overflow);
1743 addr = jit_beqi_p (addr, reg1, FROM_INT (0));
1744 lbl_use (overflow, addr);
1745 }
1746
1747 jit_rshi_l (reg1, reg1, 1);
1748 jit_rshi_l (reg0, reg0, 1);
1749
1750 /* Make the divisor positive */
1751 jit_rshi_l (JIT_R0, reg1, 8 * sizeof (PTR) - 1);
1752 jit_xorr_l (reg0, reg0, JIT_R0);
1753 jit_xorr_l (reg1, reg1, JIT_R0);
1754 jit_subr_l (reg0, reg0, JIT_R0);
1755 jit_subr_l (reg1, reg1, JIT_R0);
1756
1757 /* Fix the result if signs differ: reg0 -= reg1-1 */
1758 jit_rshi_l (JIT_R1, reg0, 8 * sizeof (PTR) - 1);
1759 jit_subi_l (JIT_R0, reg1, 1);
1760 jit_andr_l (JIT_R0, JIT_R0, JIT_R1); /* if reg0 < 0, reg0
1761 is... */
1762 jit_subr_l (reg0, reg0, JIT_R0); /* _gst_self - imm + 1 */
1763 jit_xorr_l (reg0, reg0, JIT_R1); /* imm - _gst_self - 2 */
1764 jit_subr_l (reg0, reg0, JIT_R1); /* imm - _gst_self - 1 */
1765
1766 /* divide, then negate the result if the signs were different
1767 */
1768 jit_divr_l (JIT_R0, reg0, reg1);
1769 jit_xorr_l (JIT_R0, JIT_R0, JIT_R1);
1770 jit_subr_l (JIT_R0, JIT_R0, JIT_R1);
1771
1772 /* add the tag bit */
1773 jit_addr_l (JIT_V0, JIT_R0, JIT_R0);
1774 jit_ori_l (JIT_V0, JIT_V0, 1);
1775 }
1776 break;
1777
1778
1779
1780 case REMAINDER_SPECIAL:
1781 case BIT_SHIFT_SPECIAL:
1782 /* not yet */
1783 addr = lbl_get (overflow);
1784 addr = jit_jmpi (addr);
1785 lbl_use (overflow, addr);
1786 break;
1787
1788 case BIT_AND_SPECIAL:
1789 IMM_OR_REG (and, JIT_V0);
1790 break;
1791 case BIT_OR_SPECIAL:
1792 IMM_OR_REG (or, JIT_V0);
1793 break;
1794
1795 case BIT_XOR_SPECIAL:
1796 /* For XOR, the tag bits of the two operands cancel (unlike
1797 AND and OR), so we cannot simply use the IMM_OR_REG macro. */
1798 if (reg1 != JIT_NOREG)
1799 {
1800 jit_xorr_l(JIT_V0, reg0, reg1);
1801 jit_addi_l(JIT_V0, JIT_V0, 1); /* Put back the tag bit. */
1802 }
1803 else
1804 {
1805 imm--; /* Strip the tag bit. */
1806 jit_xori_l(JIT_V0, reg0, imm);
1807 }
1808
1809 break;
1810 }
1811
1812 EXPORT_SP (JIT_V0);
1813 if (overflow)
1814 finish_deferred_send ();
1815 }
1816
1817 void
gen_binary_bool(code_tree * tree)1818 gen_binary_bool (code_tree *tree)
1819 {
1820 inline_cache *ic = (inline_cache *) tree->data;
1821 label *deferredSend;
1822 int reg0, reg1;
1823 OOP oop;
1824
1825 DONT_INLINE_SUPER;
1826 if (ic->imm != SAME_OBJECT_SPECIAL)
1827 DONT_INLINE_NONINTEGER;
1828
1829 GET_BINARY_ARGS;
1830 if (ic->imm != SAME_OBJECT_SPECIAL)
1831 ENSURE_INT_ARGS (true, deferredSend);
1832
1833 else
1834 deferredSend = NULL;
1835
1836 #define TRUE_BRANCH(addr) \
1837 switch(ic->imm) { \
1838 case LESS_THAN_SPECIAL: addr = IMM_OR_REG(blt, addr); break; \
1839 case GREATER_THAN_SPECIAL: addr = IMM_OR_REG(bgt, addr); break; \
1840 case LESS_EQUAL_SPECIAL: addr = IMM_OR_REG(ble, addr); break; \
1841 case GREATER_EQUAL_SPECIAL: addr = IMM_OR_REG(bge, addr); break; \
1842 case SAME_OBJECT_SPECIAL: \
1843 case EQUAL_SPECIAL: addr = IMM_OR_REG(beq, addr); break; \
1844 case NOT_EQUAL_SPECIAL: addr = IMM_OR_REG(bne, addr); break; \
1845 }
1846
1847 #define FALSE_BRANCH(addr) \
1848 switch(ic->imm) { \
1849 case LESS_THAN_SPECIAL: addr = IMM_OR_REG(bge, addr); break; \
1850 case GREATER_THAN_SPECIAL: addr = IMM_OR_REG(ble, addr); break; \
1851 case LESS_EQUAL_SPECIAL: addr = IMM_OR_REG(bgt, addr); break; \
1852 case GREATER_EQUAL_SPECIAL: addr = IMM_OR_REG(blt, addr); break; \
1853 case SAME_OBJECT_SPECIAL: \
1854 case EQUAL_SPECIAL: addr = IMM_OR_REG(bne, addr); break; \
1855 case NOT_EQUAL_SPECIAL: addr = IMM_OR_REG(beq, addr); break; \
1856 }
1857
1858 #define FALSE_SET(reg) \
1859 switch(ic->imm) { \
1860 case LESS_THAN_SPECIAL: IMM_OR_REG(ge, reg); break; \
1861 case GREATER_THAN_SPECIAL: IMM_OR_REG(le, reg); break; \
1862 case LESS_EQUAL_SPECIAL: IMM_OR_REG(gt, reg); break; \
1863 case GREATER_EQUAL_SPECIAL: IMM_OR_REG(lt, reg); break; \
1864 case SAME_OBJECT_SPECIAL: \
1865 case EQUAL_SPECIAL: IMM_OR_REG(ne, reg); break; \
1866 case NOT_EQUAL_SPECIAL: IMM_OR_REG(eq, reg); break; \
1867 }
1868
1869 INLINED_CONDITIONAL;
1870 #undef TRUE_BRANCH
1871 #undef FALSE_BRANCH
1872 #undef FALSE_SET
1873
1874 EXPORT_SP (JIT_V0);
1875 if (deferredSend)
1876 finish_deferred_send ();
1877 }
1878
1879 void
gen_send_store_lit_var(code_tree * tree)1880 gen_send_store_lit_var (code_tree *tree)
1881 {
1882 inline_cache *ic = (inline_cache *) tree->data;
1883 label *overflow;
1884 int reg0, reg1;
1885 OOP oop;
1886 intptr_t imm;
1887 jit_insn *addr;
1888
1889 /* tree->child = value
1890 tree->child->next = var. */
1891 BEFORE_STORE;
1892 emit_code_tree(tree->child->next);
1893 BEFORE_PUSH (JIT_V1);
1894 EXPORT_SP (JIT_V0);
1895 gen_send (tree);
1896 }
1897
1898 void
gen_dirty_block(code_tree * tree)1899 gen_dirty_block (code_tree *tree)
1900 {
1901 GET_UNARY_ARG;
1902
1903 KEEP_V0_EXPORT_SP;
1904 jit_prepare (1);
1905 jit_pusharg_p (JIT_V0);
1906 jit_finish (_gst_make_block_closure);
1907 jit_retval (JIT_V0);
1908
1909 KEEP_V0_IMPORT_SP;
1910 CACHE_NOTHING;
1911 }
1912
1913 #if 0
1914 void
1915 gen_fetch_class (code_tree *tree)
1916 {
1917 inline_cache *ic = (inline_cache *) tree->data;
1918
1919 DONT_INLINE_SUPER;
1920 GET_UNARY_ARG;
1921
1922 if (IS_INTEGER (tree->child))
1923 jit_movi_p (JIT_V0, _gst_small_integer_class);
1924
1925 else if (NOT_INTEGER (tree->child))
1926 {
1927 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (OOP, object));
1928 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (gst_object, objClass));
1929 }
1930 else
1931 {
1932 jit_insn *jmp;
1933 jit_movi_p (JIT_R0, _gst_small_integer_class);
1934 jmp = jit_bmsi_ul (jit_forward (), JIT_V0, 1);
1935 jit_ldxi_p (JIT_R0, JIT_V0, jit_ptr_field (OOP, object));
1936 jit_ldxi_p (JIT_R0, JIT_R0, jit_ptr_field (gst_object, objClass));
1937 jit_patch (jmp);
1938 jit_movr_p (JIT_V0, JIT_R0);
1939 }
1940
1941 self_cached = false;
1942 }
1943 #endif
1944
1945 void
gen_unary_special(code_tree * tree)1946 gen_unary_special (code_tree *tree)
1947 {
1948 inline_cache *ic = (inline_cache *) tree->data;
1949 jit_insn *ok1 = NULL, *bad1, *ok2, *ok3;
1950 int sz;
1951
1952 DONT_INLINE_SUPER;
1953
1954 switch (ic->imm)
1955 {
1956 case JAVA_AS_INT_SPECIAL:
1957 case JAVA_AS_LONG_SPECIAL:
1958 emit_code_tree(tree->child);
1959 if (IS_INTEGER (tree->child))
1960 break;
1961
1962 /* In order to prepare for emitting the send,
1963 we have to export the top of the stack here.
1964 We won't emit anything in gen_send, though. */
1965 CACHE_STACK_TOP;
1966
1967 if (!NOT_INTEGER (tree->child))
1968 ok1 = jit_bmsi_ul (jit_forward (), JIT_V0, 1);
1969
1970 sz = (ic->imm == JAVA_AS_LONG_SPECIAL) ? 8 : 4;
1971
1972 jit_ldr_p (JIT_R2, JIT_V0);
1973
1974 /* Check if it belongs to the wrong class... */
1975 jit_ldxi_p (JIT_R0, JIT_R2, jit_ptr_field (gst_object, objClass));
1976 jit_subi_p (JIT_R0, JIT_R0, _gst_large_positive_integer_class);
1977 ok2 = jit_beqi_p (jit_forward (), JIT_R0, NULL);
1978 bad1 = jit_bnei_p (jit_forward (), JIT_R0,
1979 ((char *) _gst_large_negative_integer_class) -
1980 ((char *) _gst_large_positive_integer_class));
1981
1982 /* Look for too big an integer... */
1983 jit_patch (ok2);
1984 if (SIZEOF_OOP > 4)
1985 {
1986 emit_basic_size_in_r0 (_gst_large_positive_integer_class, false, JIT_R2);
1987 ok3 = jit_blei_ui (jit_forward (), JIT_R0, sz);
1988 }
1989 else
1990 {
1991 /* We can check the size field directly. */
1992 jit_ldxi_p (JIT_R0, JIT_R2, jit_ptr_field (gst_object, objSize));
1993 ok3 = jit_blei_p (jit_forward (), JIT_R0,
1994 FROM_INT (OBJ_HEADER_SIZE_WORDS + sz / SIZEOF_OOP));
1995 }
1996
1997 jit_patch (bad1);
1998 gen_send (tree);
1999 jit_patch (ok3);
2000 if (ok1)
2001 jit_patch (ok1);
2002 self_cached = false;
2003 return;
2004
2005 default:
2006 GET_UNARY_ARG;
2007 abort ();
2008 }
2009 }
2010
2011 void
gen_unary_bool(code_tree * tree)2012 gen_unary_bool (code_tree *tree)
2013 {
2014 inline_cache *ic = (inline_cache *) tree->data;
2015 mst_Boolean compileIsNil = ic->imm == IS_NIL_SPECIAL;
2016
2017 DONT_INLINE_SUPER;
2018 GET_UNARY_ARG;
2019
2020 #define TRUE_BRANCH(addr) addr = compileIsNil ? jit_beqi_p((addr), JIT_V0, _gst_nil_oop) \
2021 : jit_bnei_p((addr), JIT_V0, _gst_nil_oop)
2022 #define FALSE_BRANCH(addr) addr = compileIsNil ? jit_bnei_p((addr), JIT_V0, _gst_nil_oop) \
2023 : jit_beqi_p((addr), JIT_V0, _gst_nil_oop)
2024 #define FALSE_SET(reg) compileIsNil ? jit_nei_p ((reg), JIT_V0, _gst_nil_oop) \
2025 : jit_eqi_p ((reg), JIT_V0, _gst_nil_oop)
2026 INLINED_CONDITIONAL;
2027 #undef TRUE_BRANCH
2028 #undef FALSE_BRANCH
2029 #undef FALSE_SET
2030 }
2031
2032 void
gen_pop_into_array(code_tree * tree)2033 gen_pop_into_array (code_tree *tree)
2034 {
2035 mst_Boolean useCachedR0;
2036 code_tree *array, *value;
2037 int index;
2038
2039 array = tree->child;
2040 value = array->next;
2041 index = (int) tree->data;
2042 useCachedR0 = (array->operation & (TREE_OP | TREE_SUBOP))
2043 == (TREE_STORE | TREE_POP_INTO_ARRAY);
2044
2045 /* This code is the same as GET_BINARY_ARGS, but it forces the first
2046 parameter in V0 and the second in V1. This is because the bytecode
2047 leaves the first parameter in the stack top */
2048
2049 emit_code_tree (array);
2050 if (IS_PUSH (value))
2051 {
2052 if (sp_delta < 0)
2053 {
2054 jit_ldr_p (JIT_V0, JIT_V2);
2055 jit_addi_p (JIT_V2, JIT_V2, sp_delta);
2056 sp_delta = 0;
2057 }
2058 /* Load the value operand into V1 */
2059 value->operation ^= TREE_PUSH ^ TREE_ALT_PUSH;
2060 emit_code_tree (value);
2061 }
2062 else
2063 {
2064 emit_code_tree (value);
2065 if (sp_delta < 0)
2066 {
2067 /* We load the 2nd argument and then the 1st */
2068 jit_ldr_p (JIT_V1, JIT_V2);
2069 jit_ldxi_p (JIT_V0, JIT_V2, -sizeof (PTR));
2070 }
2071 else
2072 {
2073 /* The 2nd argument is already in V0, move it in V1 */
2074 jit_movr_p (JIT_V1, JIT_V0);
2075 jit_ldxi_p (JIT_V0, JIT_V2, sp_delta);
2076 }
2077
2078 /* "Pop" the 2nd argument */
2079 sp_delta -= sizeof (PTR);
2080 useCachedR0 = false;
2081 }
2082
2083 if (sp_delta)
2084 {
2085 jit_addi_p (JIT_V2, JIT_V2, sp_delta);
2086 sp_delta = 0;
2087 }
2088
2089 if (!useCachedR0)
2090 {
2091 /* Dereference the OOP into R0 */
2092 jit_ldxi_p (JIT_R0, JIT_V0, jit_ptr_field (OOP, object));
2093 }
2094
2095 jit_stxi_p (jit_ptr_field (gst_object, data[index]), JIT_R0, JIT_V1);
2096 }
2097
2098
2099 /* Stores */
2100 void
gen_store_rec_var(code_tree * tree)2101 gen_store_rec_var (code_tree *tree)
2102 {
2103 BEFORE_STORE;
2104 CACHE_REC_VAR;
2105
2106 jit_stxi_p (REC_VAR_OFS (tree), JIT_R1, JIT_V0);
2107 }
2108
2109 void
gen_store_temp(code_tree * tree)2110 gen_store_temp (code_tree *tree)
2111 {
2112 BEFORE_STORE;
2113 CACHE_TEMP;
2114
2115 jit_stxi_p (TEMP_OFS (tree), JIT_V1, JIT_V0);
2116 }
2117
2118 void
gen_store_lit_var(code_tree * tree)2119 gen_store_lit_var (code_tree *tree)
2120 {
2121 char *assocOOP = ((char *) tree->data) + jit_ptr_field (OOP, object);
2122 BEFORE_STORE;
2123
2124 jit_ldi_p (JIT_R0, assocOOP);
2125 jit_stxi_p (jit_ptr_field (gst_association, value), JIT_R0, JIT_V0);
2126 }
2127
2128 void
gen_store_outer(code_tree * tree)2129 gen_store_outer (code_tree *tree)
2130 {
2131 BEFORE_STORE;
2132 CACHE_OUTER_CONTEXT;
2133
2134 jit_stxi_p (STACK_OFS (tree), JIT_V1, JIT_V0);
2135 }
2136
2137 /* Pushes */
2138 void
gen_push_rec_var(code_tree * tree)2139 gen_push_rec_var (code_tree *tree)
2140 {
2141 BEFORE_PUSH (JIT_V0);
2142 CACHE_REC_VAR;
2143
2144 jit_ldxi_p (JIT_V0, JIT_R1, REC_VAR_OFS (tree));
2145 self_cached = false;
2146 }
2147
2148 void
gen_push_temp(code_tree * tree)2149 gen_push_temp (code_tree *tree)
2150 {
2151 BEFORE_PUSH (JIT_V0);
2152 CACHE_TEMP;
2153
2154 jit_ldxi_p (JIT_V0, JIT_V1, TEMP_OFS (tree));
2155 self_cached = false;
2156 }
2157
2158 void
gen_push_lit_const(code_tree * tree)2159 gen_push_lit_const (code_tree *tree)
2160 {
2161 BEFORE_PUSH (JIT_V0);
2162
2163 jit_movi_p (JIT_V0, tree->data);
2164 self_cached = false;
2165 }
2166
2167 void
gen_push_lit_var(code_tree * tree)2168 gen_push_lit_var (code_tree *tree)
2169 {
2170 char *assocOOP = ((char *) tree->data) + jit_ptr_field (OOP, object);
2171 BEFORE_PUSH (JIT_V0);
2172
2173 jit_ldi_p (JIT_V0, assocOOP);
2174 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (gst_association, value));
2175 self_cached = false;
2176 }
2177
2178 void
gen_dup_top(code_tree * tree)2179 gen_dup_top (code_tree *tree)
2180 {
2181 if (sp_delta < 0)
2182 jit_ldr_p (JIT_V0, JIT_V2);
2183
2184 BEFORE_PUSH (JIT_V0);
2185 }
2186
2187 void
gen_push_self(code_tree * tree)2188 gen_push_self (code_tree *tree)
2189 {
2190 BEFORE_PUSH (JIT_V0);
2191
2192 if (!self_cached)
2193 jit_ldi_p (JIT_V0, &_gst_self);
2194
2195 self_cached = true;
2196 }
2197
2198 void
gen_push_outer(code_tree * tree)2199 gen_push_outer (code_tree *tree)
2200 {
2201 BEFORE_PUSH (JIT_V0);
2202 CACHE_OUTER_CONTEXT;
2203
2204 jit_ldxi_p (JIT_V0, JIT_V1, STACK_OFS (tree));
2205 self_cached = false;
2206 }
2207
2208 /* Moves to V1 (alternative push) */
2209 void
gen_alt_rec_var(code_tree * tree)2210 gen_alt_rec_var (code_tree *tree)
2211 {
2212 CACHE_REC_VAR;
2213
2214 jit_ldxi_p (JIT_V1, JIT_R1, REC_VAR_OFS (tree));
2215 stack_cached = -1;
2216 }
2217
2218 void
gen_alt_temp(code_tree * tree)2219 gen_alt_temp (code_tree *tree)
2220 {
2221 CACHE_TEMP;
2222
2223 jit_ldxi_p (JIT_V1, JIT_V1, TEMP_OFS (tree));
2224 stack_cached = -1;
2225 }
2226
2227 void
gen_alt_lit_const(code_tree * tree)2228 gen_alt_lit_const (code_tree *tree)
2229 {
2230 jit_movi_p (JIT_V1, tree->data);
2231 stack_cached = -1;
2232 }
2233
2234 void
gen_alt_lit_var(code_tree * tree)2235 gen_alt_lit_var (code_tree *tree)
2236 {
2237 char *assocOOP = ((char *) tree->data) + jit_ptr_field (OOP, object);
2238
2239 jit_ldi_p (JIT_V1, assocOOP);
2240 jit_ldxi_p (JIT_V1, JIT_V1, jit_ptr_field (gst_association, value));
2241 stack_cached = -1;
2242 }
2243
2244 void
gen_get_top(code_tree * tree)2245 gen_get_top (code_tree *tree)
2246 {
2247 if (sp_delta < 0)
2248 jit_ldr_p (JIT_V1, JIT_V2);
2249
2250 else
2251 jit_movr_p (JIT_V1, JIT_V0);
2252
2253 stack_cached = -1;
2254 }
2255
2256 void
gen_alt_self(code_tree * tree)2257 gen_alt_self (code_tree *tree)
2258 {
2259 if (!self_cached)
2260 jit_ldi_p (JIT_V1, &_gst_self);
2261
2262 else
2263 jit_movr_p (JIT_V1, JIT_V0);
2264
2265 stack_cached = -1;
2266 }
2267
2268 void
gen_alt_outer(code_tree * tree)2269 gen_alt_outer (code_tree *tree)
2270 {
2271 CACHE_OUTER_CONTEXT;
2272
2273 jit_ldxi_p (JIT_V1, JIT_V1, STACK_OFS (tree));
2274 stack_cached = -1;
2275 }
2276
2277 /* Set top */
2278 void
gen_top_rec_var(code_tree * tree)2279 gen_top_rec_var (code_tree *tree)
2280 {
2281 BEFORE_SET_TOP;
2282 CACHE_REC_VAR;
2283
2284 jit_ldxi_p (JIT_V0, JIT_R1, REC_VAR_OFS (tree));
2285 self_cached = false;
2286 }
2287
2288 void
gen_top_temp(code_tree * tree)2289 gen_top_temp (code_tree *tree)
2290 {
2291 BEFORE_SET_TOP;
2292 CACHE_TEMP;
2293
2294 jit_ldxi_p (JIT_V0, JIT_V1, TEMP_OFS (tree));
2295 self_cached = false;
2296 }
2297
2298 void
gen_top_self(code_tree * tree)2299 gen_top_self (code_tree *tree)
2300 {
2301 BEFORE_SET_TOP;
2302
2303 if (!self_cached)
2304 jit_ldi_p (JIT_V0, &_gst_self);
2305
2306 self_cached = true;
2307 }
2308
2309 void
gen_top_outer(code_tree * tree)2310 gen_top_outer (code_tree *tree)
2311 {
2312 int index;
2313 BEFORE_SET_TOP;
2314 CACHE_OUTER_CONTEXT;
2315 index = ((gst_uchar *) tree->data)[0];
2316
2317 jit_ldxi_p (JIT_V0, JIT_V1, STACK_OFS (tree));
2318 self_cached = false;
2319 }
2320
2321 void
gen_top_lit_const(code_tree * tree)2322 gen_top_lit_const (code_tree *tree)
2323 {
2324 BEFORE_SET_TOP;
2325
2326 jit_movi_p (JIT_V0, tree->data);
2327 self_cached = false;
2328 }
2329
2330 void
gen_top_lit_var(code_tree * tree)2331 gen_top_lit_var (code_tree *tree)
2332 {
2333 char *assocOOP = ((char *) tree->data) + jit_ptr_field (OOP, object);
2334
2335 BEFORE_SET_TOP;
2336
2337 jit_ldi_p (JIT_V0, assocOOP);
2338 jit_ldxi_p (JIT_V0, JIT_V0, jit_ptr_field (gst_association, value));
2339 self_cached = false;
2340 }
2341
2342 void
gen_invalid(code_tree * tree)2343 gen_invalid (code_tree *tree)
2344 {
2345 printf ("Invalid operation %o in the code tree", tree->operation);
2346 abort ();
2347 }
2348
2349 void
gen_nothing(code_tree * tree)2350 gen_nothing (code_tree *tree)
2351 {
2352 }
2353
2354 void
gen_two_extras(code_tree * tree)2355 gen_two_extras (code_tree *tree)
2356 {
2357 /* Emit code for the real node and the first extra;
2358 emit_code_tree will take care of the second extra
2359 held by TREE. */
2360 emit_code_tree (tree->next); /* emit the code for the real node */
2361 }
2362
2363 void
emit_code_tree(code_tree * tree)2364 emit_code_tree (code_tree *tree)
2365 {
2366 int operation;
2367
2368 operation = tree->operation & (TREE_OP | TREE_SUBOP);
2369 emit_operation_funcs[operation] (tree);
2370
2371 /* Now emit the extras. */
2372 switch (tree->operation & TREE_EXTRA)
2373 {
2374 case TREE_EXTRA_NONE:
2375 break;
2376
2377 case TREE_EXTRA_POP:
2378 POP_EXPORT_SP;
2379 break;
2380
2381 case TREE_EXTRA_RETURN:
2382 CACHE_STACK_TOP;
2383 jit_calli (PTR_UNWIND_CONTEXT);
2384 IMPORT_SP;
2385 jit_ldi_p (JIT_R0, &native_ip);
2386 jit_str_p (JIT_V2, JIT_V0);
2387 jit_jmpr (JIT_R0);
2388 break;
2389
2390 case TREE_EXTRA_METHOD_RET:
2391 CACHE_STACK_TOP;
2392 jit_calli (PTR_UNWIND_METHOD);
2393 jit_retval (JIT_R0);
2394 jit_beqi_i (bad_return_code, JIT_R0, false);
2395 IMPORT_SP;
2396 jit_ldi_p (JIT_R0, &native_ip);
2397 jit_str_p (JIT_V2, JIT_V0);
2398 jit_jmpr (JIT_R0);
2399 break;
2400
2401 case TREE_EXTRA_JMP_ALWAYS:
2402 {
2403 jit_insn *addr;
2404
2405 CACHE_STACK_TOP;
2406 addr = lbl_get (tree->jumpDest);
2407 addr = jit_jmpi (addr);
2408 lbl_use (tree->jumpDest, addr);
2409 break;
2410 }
2411
2412 case TREE_EXTRA_JMP_TRUE:
2413 CONDITIONAL_JUMP (_gst_true_oop, _gst_false_oop);
2414 break;
2415
2416 case TREE_EXTRA_JMP_FALSE:
2417 CONDITIONAL_JUMP (_gst_false_oop, _gst_true_oop);
2418 break;
2419 }
2420
2421 /* Change the code_tree's operation field to TREE_ALREADY_EMITTED,
2422 and null the extra op. field */
2423 tree->operation &= TREE_CLASS_CHECKS;
2424 tree->operation |= TREE_NOP | TREE_ALREADY_EMITTED;
2425 }
2426
2427
2428
2429 /* Initialization and other code generation (prologs, interrupt checks) */
2430
2431 void
emit_deferred_sends(deferred_send * ds)2432 emit_deferred_sends (deferred_send *ds)
2433 {
2434 jit_insn *addr;
2435 code_tree *tree;
2436 inline_cache *ic;
2437
2438 if (!ds)
2439 return;
2440
2441 emit_deferred_sends (ds->next);
2442
2443 tree = ds->tree;
2444 ic = (inline_cache *) tree->data;
2445 assert (!ic->is_super);
2446
2447 lbl_define (ds->address);
2448 if (ds->reg1 == JIT_NOREG)
2449 {
2450 jit_movi_p (JIT_R0, ds->oop);
2451 ds->reg1 = JIT_R0;
2452 }
2453
2454 jit_stxi_p (sizeof (PTR) * 1, JIT_V2, ds->reg0);
2455 jit_stxi_p (sizeof (PTR) * 2, JIT_V2, ds->reg1);
2456 jit_addi_p (JIT_V2, JIT_V2, sizeof (PTR) * 2);
2457
2458 jit_movi_p (JIT_V1, ic);
2459 jit_sti_p (&sp, JIT_V2);
2460 jit_movi_ul (JIT_V0, tree->bp - bc);
2461 jit_ldxi_p (JIT_R1, JIT_V1, jit_field (inline_cache, cachedIP));
2462 jit_sti_ul (&ip, JIT_V0);
2463
2464 jit_jmpr (JIT_R1);
2465 jit_align (2);
2466
2467 ic->native_ip = jit_get_label ();
2468 define_ip_map_entry (tree->bp - bc);
2469
2470 IMPORT_SP;
2471 if (ds->trueDest == ds->falseDest)
2472 {
2473 /* This was an arithmetic deferred send. */
2474 jit_ldr_p (JIT_V0, JIT_V2);
2475 addr = lbl_get (ds->trueDest);
2476 addr = jit_jmpi (addr);
2477 lbl_use (ds->trueDest, addr);
2478
2479 }
2480 else
2481 {
2482 /* This was a boolean deferred send. */
2483 jit_ldr_p (JIT_R0, JIT_V2);
2484 jit_subi_p (JIT_V2, JIT_V2, sizeof (PTR));
2485 jit_ldr_p (JIT_V0, JIT_V2);
2486
2487 addr = lbl_get (ds->trueDest);
2488 addr = jit_beqi_p (addr, JIT_R0, _gst_true_oop);
2489 lbl_use (ds->trueDest, addr);
2490
2491 addr = lbl_get (ds->falseDest);
2492 addr = jit_beqi_p (addr, JIT_R0, _gst_false_oop);
2493 lbl_use (ds->falseDest, addr);
2494 jit_jmpi (non_boolean_code);
2495 }
2496 }
2497
2498 void
emit_interrupt_check(int restartReg)2499 emit_interrupt_check (int restartReg)
2500 {
2501 jit_insn *jmp, *begin;
2502
2503 jit_align (2);
2504 begin = jit_get_label ();
2505
2506 jit_ldi_i (JIT_R2, &_gst_except_flag);
2507 jmp = jit_beqi_i (jit_forward (), JIT_R2, 0);
2508 if (restartReg == JIT_NOREG)
2509 jit_movi_p (JIT_RET, begin);
2510
2511 else
2512 jit_movr_p (JIT_RET, restartReg);
2513
2514 jit_ret ();
2515 jit_patch (jmp);
2516 }
2517
2518 /* Auxiliary function for inlined primitives. Retrieves the receiver's
2519 * basicSize in R0, expects the pointer to the object data in objectReg.
2520 * Destroys V1. */
2521 void
emit_basic_size_in_r0(OOP classOOP,mst_Boolean tagged,int objectReg)2522 emit_basic_size_in_r0 (OOP classOOP, mst_Boolean tagged, int objectReg)
2523 {
2524 int adjust;
2525
2526 int shape = CLASS_INSTANCE_SPEC (classOOP) & ISP_INDEXEDVARS;
2527
2528 if (!CLASS_IS_INDEXABLE (classOOP))
2529 {
2530 jit_movi_p (JIT_R0, FROM_INT (0));
2531 return;
2532 }
2533
2534 /* Not yet implemented. */
2535 if (shape != GST_ISP_POINTER
2536 && shape != GST_ISP_SCHAR
2537 && shape != GST_ISP_CHARACTER
2538 && shape != GST_ISP_UCHAR)
2539 abort ();
2540
2541 adjust = CLASS_FIXED_FIELDS (classOOP) +
2542 sizeof (gst_object_header) / sizeof (PTR);
2543
2544 if (objectReg == JIT_NOREG)
2545 {
2546 jit_ldxi_p (JIT_R2, JIT_V0, jit_ptr_field (OOP, object));
2547 objectReg = JIT_R2;
2548 }
2549
2550 jit_ldxi_l (JIT_R0, objectReg, jit_ptr_field (gst_object, objSize));
2551
2552 if (shape != GST_ISP_POINTER)
2553 jit_ldxi_p (JIT_V1, JIT_V0, jit_ptr_field (OOP, flags));
2554
2555 if (!tagged)
2556 /* Remove the tag bit */
2557 jit_rshi_l (JIT_R0, JIT_R0, 1);
2558 else
2559 adjust = adjust * 2;
2560
2561 if (shape != GST_ISP_POINTER)
2562 {
2563 jit_andi_l (JIT_V1, JIT_V1, EMPTY_BYTES);
2564 jit_lshi_l (JIT_R0, JIT_R0, LONG_SHIFT);
2565 jit_subr_l (JIT_R0, JIT_R0, JIT_V1);
2566
2567 adjust *= sizeof (PTR);
2568 if (tagged)
2569 {
2570 jit_subr_l (JIT_R0, JIT_R0, JIT_V1);
2571
2572 /* Move the tag bit back to bit 0 after the long shift above */
2573 adjust += sizeof (PTR) - 1;
2574 }
2575 }
2576
2577 if (adjust)
2578 jit_subi_l (JIT_R0, JIT_R0, adjust);
2579 }
2580
2581 /* This takes care of emitting the code for inlined primitives.
2582 Returns a new set of attributes which applies to the inlined code. */
2583 mst_Boolean
emit_inlined_primitive(int primitive,int numArgs,int attr)2584 emit_inlined_primitive (int primitive, int numArgs, int attr)
2585 {
2586 switch (primitive)
2587 {
2588 case 60:
2589 {
2590 jit_insn *fail1, *fail2;
2591 OOP charBase = CHAR_OOP_AT (0);
2592 int numFixed = CLASS_FIXED_FIELDS (current->receiverClass) +
2593 sizeof (gst_object_header) / sizeof (PTR);
2594
2595 int shape = CLASS_INSTANCE_SPEC (current->receiverClass) & ISP_INDEXEDVARS;
2596
2597 if (numArgs != 1)
2598 break;
2599
2600 if (!shape)
2601 {
2602 /* return failure */
2603 jit_movi_p (JIT_R0, -1);
2604 return PRIM_FAIL | PRIM_INLINED;
2605 }
2606
2607 else if (shape != GST_ISP_POINTER && shape != GST_ISP_UCHAR
2608 && shape != GST_ISP_SCHAR && shape != GST_ISP_CHARACTER)
2609 /* too complicated to return LargeIntegers */
2610 break;
2611
2612 jit_ldi_p (JIT_R1, &sp);
2613 emit_basic_size_in_r0 (current->receiverClass, false, JIT_NOREG);
2614
2615 /* Point R2 to the first indexed slot */
2616 jit_addi_ui (JIT_R2, JIT_R2, numFixed * sizeof (PTR));
2617
2618 /* Load the index and test it: remove tag bit, then check if
2619 (unsigned) (V1 - 1) >= R0 */
2620
2621 jit_ldr_l (JIT_V1, JIT_R1);
2622 fail1 = jit_bmci_l (jit_get_label (), JIT_V1, 1);
2623
2624 jit_rshi_ul (JIT_V1, JIT_V1, 1);
2625 jit_subi_ul (JIT_V1, JIT_V1, 1);
2626 fail2 = jit_bger_ul (jit_get_label (), JIT_V1, JIT_R0);
2627
2628 /* adjust stack top */
2629 jit_subi_l (JIT_R1, JIT_R1, sizeof (PTR));
2630
2631 /* Now R2 + V1 << SOMETHING contains the pointer to the slot
2632 (SOMETHING depends on the shape). */
2633 switch (shape)
2634 {
2635 case GST_ISP_POINTER:
2636 jit_lshi_ul (JIT_V1, JIT_V1, LONG_SHIFT);
2637 jit_ldxr_p (JIT_R0, JIT_R2, JIT_V1);
2638 break;
2639
2640 case GST_ISP_UCHAR:
2641 jit_ldxr_uc (JIT_R0, JIT_R2, JIT_V1);
2642
2643 /* Tag the byte we read */
2644 jit_addr_ul (JIT_R0, JIT_R0, JIT_R0);
2645 jit_addi_ul (JIT_R0, JIT_R0, 1);
2646 break;
2647
2648 case GST_ISP_SCHAR:
2649 jit_ldxr_c (JIT_R0, JIT_R2, JIT_V1);
2650
2651 /* Tag the byte we read */
2652 jit_addr_ul (JIT_R0, JIT_R0, JIT_R0);
2653 jit_addi_ul (JIT_R0, JIT_R0, 1);
2654 break;
2655
2656 case GST_ISP_CHARACTER:
2657 {
2658 jit_ldxr_uc (JIT_R0, JIT_R2, JIT_V1);
2659
2660 /* Convert to a character */
2661 jit_lshi_l (JIT_R0, JIT_R0, LONG_SHIFT + 1);
2662 jit_addi_p (JIT_R0, JIT_R0, charBase);
2663 }
2664 }
2665
2666 /* Store the result and the new stack pointer */
2667 jit_str_p (JIT_R1, JIT_R0);
2668 jit_sti_p (&sp, JIT_R1);
2669
2670 jit_movi_l (JIT_R0, -1);
2671
2672 jit_patch (fail1);
2673 jit_patch (fail2);
2674
2675 /* We get here with the _gst_basic_size in R0 upon failure,
2676 with -1 upon success. We need to get 0 upon success and -1
2677 upon failure. */
2678 jit_rshi_l (JIT_R0, JIT_R0, 31);
2679 jit_notr_l (JIT_R0, JIT_R0);
2680
2681 return PRIM_FAIL | PRIM_SUCCEED | PRIM_INLINED;
2682 }
2683 break;
2684
2685 case 61:
2686 {
2687 jit_insn *fail0, *fail1, *fail2, *fail3, *fail4;
2688 OOP charBase = CHAR_OOP_AT (0);
2689 int numFixed = CLASS_FIXED_FIELDS (current->receiverClass) +
2690 sizeof (gst_object_header) / sizeof (PTR);
2691
2692 int shape = CLASS_INSTANCE_SPEC (current->receiverClass) & ISP_INDEXEDVARS;
2693
2694 if (numArgs != 2)
2695 break;
2696
2697 if (!shape)
2698 {
2699 /* return failure */
2700 jit_movi_p (JIT_R0, -1);
2701 return PRIM_FAIL | PRIM_INLINED;
2702 }
2703
2704 if (shape != GST_ISP_UCHAR && shape != GST_ISP_POINTER)
2705 /* too complicated to convert LargeIntegers */
2706 break;
2707
2708 jit_ldxi_ul (JIT_V1, JIT_V0, jit_ptr_field (OOP, flags));
2709 fail0 = jit_bmsi_ul (jit_get_label (), JIT_V1, F_READONLY);
2710
2711 jit_ldi_p (JIT_R1, &sp);
2712 emit_basic_size_in_r0 (current->receiverClass, false, JIT_NOREG);
2713
2714 /* Point R2 to the first indexed slot */
2715 jit_addi_ui (JIT_R2, JIT_R2, numFixed * sizeof (PTR));
2716
2717 /* Load the index and test it: remove tag bit, then check if
2718 (unsigned) (V1 - 1) >= R0 */
2719
2720 jit_ldxi_l (JIT_V1, JIT_R1, -sizeof (PTR));
2721
2722 fail1 = jit_bmci_l (jit_get_label (), JIT_V1, 1);
2723
2724 jit_rshi_ul (JIT_V1, JIT_V1, 1);
2725 jit_subi_ul (JIT_V1, JIT_V1, 1);
2726 fail2 = jit_bger_ul (jit_get_label (), JIT_V1, JIT_R0);
2727
2728 if (shape == GST_ISP_POINTER)
2729 jit_lshi_ul (JIT_V1, JIT_V1, LONG_SHIFT);
2730
2731 /* Compute the effective address to free V1 for the operand */
2732 jit_addr_l (JIT_R2, JIT_R2, JIT_V1);
2733 jit_ldr_l (JIT_V1, JIT_R1);
2734
2735 switch (shape)
2736 {
2737 case GST_ISP_UCHAR:
2738 /* Check and untag the byte we store */
2739 fail3 = jit_bmci_l (jit_get_label (), JIT_V1, 1);
2740 jit_rshi_ul (JIT_R0, JIT_V1, 1);
2741 fail4 = jit_bmsi_ul (jit_get_label (), JIT_R0, ~255);
2742
2743 jit_str_uc (JIT_R2, JIT_R0);
2744 break;
2745
2746 case GST_ISP_CHARACTER:
2747 /* Check the character we store */
2748 fail3 = jit_bmsi_l (jit_get_label (), JIT_V1, 1);
2749
2750 jit_subi_p (JIT_R0, JIT_V1, charBase);
2751 jit_rshi_ul (JIT_R0, JIT_R0, LONG_SHIFT + 1);
2752 fail4 = jit_bmsi_ul (jit_get_label (), JIT_R0, ~255);
2753
2754 jit_str_uc (JIT_R2, JIT_R0);
2755 break;
2756
2757 case GST_ISP_POINTER:
2758 fail3 = fail4 = NULL;
2759 jit_str_p (JIT_R2, JIT_V1);
2760 }
2761
2762 /* Store the result and the new stack pointer */
2763 jit_subi_l (JIT_R1, JIT_R1, sizeof (PTR) * 2);
2764 jit_str_p (JIT_R1, JIT_V1);
2765 jit_sti_p (&sp, JIT_R1);
2766
2767 jit_movi_l (JIT_R0, -1);
2768
2769 jit_patch (fail0);
2770 jit_patch (fail1);
2771 jit_patch (fail2);
2772 if (fail3)
2773 {
2774 jit_patch (fail3);
2775 jit_patch (fail4);
2776 }
2777
2778 /* We get here with the _gst_basic_size in R0 upon failure,
2779 with -1 upon success. We need to get 0 upon success and -1
2780 upon failure. */
2781 jit_rshi_l (JIT_R0, JIT_R0, 31);
2782 jit_notr_l (JIT_R0, JIT_R0);
2783
2784 return PRIM_FAIL | PRIM_SUCCEED | PRIM_INLINED;
2785 }
2786 break;
2787
2788 case 62:
2789 {
2790 int shape = CLASS_INSTANCE_SPEC (current->receiverClass) & ISP_INDEXEDVARS;
2791
2792 if (numArgs != 0)
2793 break;
2794
2795 if (shape != 0 && shape != GST_ISP_UCHAR && shape != GST_ISP_POINTER)
2796 /* too complicated to convert LargeIntegers */
2797 break;
2798
2799 jit_ldi_p (JIT_R1, &sp);
2800 emit_basic_size_in_r0 (current->receiverClass, true, JIT_NOREG);
2801 jit_str_p (JIT_R1, JIT_R0);
2802 return (PRIM_SUCCEED | PRIM_INLINED);
2803 }
2804
2805 #if 0
2806 case 70:
2807 {
2808 OOP class_oop;
2809 if (numArgs != 0)
2810 break;
2811
2812 if (!is_a_kind_of (current->receiverClass, _gst_class_class))
2813 break;
2814
2815 class_oop = METACLASS_INSTANCE (current->receiverClass);
2816 if (CLASS_IS_INDEXABLE (class_oop))
2817 {
2818 /* return failure */
2819 jit_movi_p (JIT_R0, -1);
2820 return PRIM_FAIL | PRIM_INLINED;
2821 }
2822
2823 /* SET_STACKTOP (alloc_oop (instantiate (_gst_self))) */
2824 jit_prepare (1);
2825 jit_pusharg_p (JIT_V0);
2826 jit_finish (instantiate);
2827 jit_retval (JIT_R0);
2828
2829 jit_prepare (1);
2830 jit_pusharg_p (JIT_R0);
2831 jit_finish (alloc_oop);
2832
2833 jit_ldi_p (JIT_V1, &sp);
2834 jit_retval (JIT_R0);
2835 jit_str_p (JIT_V1, JIT_R0);
2836 return (PRIM_SUCCEED | PRIM_INLINED);
2837 }
2838
2839
2840 case 71:
2841 {
2842 OOP class_oop;
2843 jit_insn *fail1, *fail2;
2844
2845 if (numArgs != 1)
2846 break;
2847
2848 if (!is_a_kind_of (current->receiverClass, _gst_class_class))
2849 break;
2850
2851 class_oop = METACLASS_INSTANCE (current->receiverClass);
2852 if (!CLASS_IS_INDEXABLE (class_oop))
2853 {
2854 /* return failure */
2855 jit_movi_p (JIT_R0, -1);
2856 return PRIM_FAIL | PRIM_INLINED;
2857 }
2858
2859 jit_ldi_p (JIT_V1, &sp);
2860 jit_ldr_p (JIT_R1, JIT_V1); /* load the argument */
2861 jit_movi_i (JIT_R0, -1); /* failure */
2862
2863 fail2 = jit_bmci_l (jit_get_label (), JIT_R1, 1);
2864 fail1 = jit_blti_p (jit_get_label (), JIT_R1, FROM_INT (0));
2865
2866 jit_rshi_l (JIT_R1, JIT_R1, 1); /* clear tag bit */
2867 jit_subi_l (JIT_V1, JIT_V1, sizeof (PTR)); /* set new
2868 stack top */
2869
2870 /* SET_STACKTOP (instantiate_oopwith (_gst_self, POP_OOP())) */
2871 jit_prepare (2);
2872 jit_pusharg_p (JIT_R1);
2873 jit_pusharg_p (JIT_V0);
2874 jit_finish (instantiate_oopwith);
2875 jit_retval (JIT_R0);
2876
2877 /* Store the result and the new stack pointer */
2878 jit_str_p (JIT_V1, JIT_R0);
2879 jit_sti_p (&sp, JIT_V1);
2880
2881 jit_movi_i (JIT_R0, 0); /* success */
2882
2883 jit_patch (fail2);
2884 jit_patch (fail1);
2885
2886 return (PRIM_SUCCEED | PRIM_FAIL | PRIM_INLINED);
2887 }
2888 #endif
2889
2890 case 110:
2891 if (numArgs != 1)
2892 break;
2893
2894 jit_ldi_p (JIT_V1, &sp);
2895 jit_ldr_p (JIT_R1, JIT_V1); /* load the argument */
2896 jit_ner_p (JIT_R0, JIT_R1, JIT_V0);
2897
2898 jit_subi_l (JIT_V1, JIT_V1, sizeof (PTR)); /* set new stack top */
2899 jit_lshi_i (JIT_V0, JIT_R0, LONG_SHIFT + 1);
2900 jit_movi_i (JIT_R0, 0); /* success */
2901 jit_addi_p (JIT_V0, JIT_V0, _gst_true_oop);
2902
2903 /* Store the result and the new stack pointer */
2904 jit_str_p (JIT_V1, JIT_V0);
2905 jit_sti_p (&sp, JIT_V1);
2906
2907 return (PRIM_SUCCEED | PRIM_INLINED);
2908
2909 case 111:
2910 {
2911 jit_insn *jmp;
2912 if (numArgs != 0)
2913 break;
2914
2915 jit_ldi_p (JIT_V1, &sp);
2916 jit_movi_p (JIT_R0, _gst_small_integer_class);
2917 jmp = jit_bmsi_ul (jit_forward (), JIT_V0, 1);
2918 jit_ldxi_p (JIT_R0, JIT_V0, jit_ptr_field (OOP, object));
2919 jit_ldxi_p (JIT_R0, JIT_R0, jit_ptr_field (gst_object, objClass));
2920 jit_patch (jmp);
2921
2922 /* Store the result and the new stack pointer */
2923 jit_movi_i (JIT_R0, 0); /* success */
2924 jit_str_p (JIT_V1, JIT_V0);
2925
2926 return (PRIM_SUCCEED | PRIM_INLINED);
2927 }
2928 }
2929
2930 return (attr & ~PRIM_INLINED);
2931 }
2932
2933 mst_Boolean
emit_primitive(int primitive,int numArgs)2934 emit_primitive (int primitive, int numArgs)
2935 {
2936 /* primitive */
2937 jit_insn *fail, *succeed;
2938 prim_table_entry *pte = _gst_get_primitive_attributes (primitive);
2939 int attr = pte->attributes;
2940
2941 if (attr & PRIM_INLINED)
2942 attr = emit_inlined_primitive (pte->id, numArgs, attr);
2943
2944 if (!(attr & PRIM_INLINED))
2945 {
2946 jit_prepare (2);
2947 jit_movi_p (JIT_R1, numArgs);
2948 jit_movi_p (JIT_R2, pte->id);
2949 jit_pusharg_i (JIT_R1);
2950 jit_pusharg_i (JIT_R2);
2951 jit_finish (pte->func);
2952 jit_retval (JIT_R0);
2953 }
2954
2955 fail = ((attr & PRIM_FAIL)
2956 && (attr & (PRIM_SUCCEED | PRIM_RELOAD_IP))) ?
2957 jit_beqi_i (jit_forward (), JIT_R0, -1) : NULL;
2958
2959 if (attr & PRIM_RELOAD_IP)
2960 {
2961 succeed = (attr & PRIM_SUCCEED)
2962 ? jit_beqi_i (jit_forward (), JIT_R0, 0) : NULL;
2963
2964 /* BlockClosure>>#value saves the native code's IP in the inline cache */
2965 if (attr & PRIM_CACHE_NEW_IP)
2966 jit_stxi_p (jit_field (inline_cache, cachedIP), JIT_V1, JIT_R0);
2967
2968 jit_movr_p (JIT_V2, JIT_R0);
2969
2970 if (succeed)
2971 jit_patch (succeed);
2972 }
2973 if (attr & (PRIM_SUCCEED | PRIM_RELOAD_IP))
2974 {
2975 if (attr & PRIM_CHECK_INTERRUPT)
2976 emit_interrupt_check (JIT_V2);
2977
2978 jit_jmpr (JIT_V2);
2979 }
2980 if (fail)
2981 jit_patch (fail);
2982
2983 return !(attr & PRIM_FAIL);
2984 }
2985
2986 void
emit_context_setup(int numArgs,int numTemps)2987 emit_context_setup (int numArgs, int numTemps)
2988 {
2989 if (numArgs > 3 || numTemps > 3)
2990 {
2991 /* Call through a loop written in C */
2992 jit_movi_i (JIT_V1, numTemps);
2993 jit_prepare (3);
2994 jit_pusharg_p (JIT_V1); /* numTemps */
2995 jit_pusharg_p (JIT_V2); /* numArgs */
2996 jit_pusharg_p (JIT_R0); /* newContext */
2997 jit_finish (PTR_PREPARE_CONTEXT);
2998 IMPORT_SP;
2999 return;
3000 }
3001
3002 /* Generate unrolled code to set up the frame -- this is done for
3003 about 95% of the methods. */
3004 if (numArgs || numTemps)
3005 {
3006 int ofs;
3007
3008 IMPORT_SP;
3009 switch (numArgs)
3010 {
3011 case 3:
3012 jit_ldxi_p (JIT_V0, JIT_V2, -2 * sizeof (PTR));
3013 case 2:
3014 jit_ldxi_p (JIT_R2, JIT_V2, -1 * sizeof (PTR));
3015 case 1:
3016 jit_ldr_p (JIT_R1, JIT_V2);
3017 case 0:
3018 break;
3019 }
3020 if (numTemps)
3021 jit_movi_p (JIT_V1, _gst_nil_oop);
3022
3023 jit_addi_p (JIT_V2, JIT_R0,
3024 jit_ptr_field (gst_method_context, contextStack));
3025 jit_sti_p (&_gst_temporaries, JIT_V2);
3026 ofs = 0;
3027 switch (numArgs)
3028 {
3029 case 3:
3030 jit_stxi_p (ofs, JIT_V2, JIT_V0);
3031 ofs += sizeof (PTR);
3032 case 2:
3033 jit_stxi_p (ofs, JIT_V2, JIT_R2);
3034 ofs += sizeof (PTR);
3035 case 1:
3036 jit_stxi_p (ofs, JIT_V2, JIT_R1);
3037 ofs += sizeof (PTR);
3038 case 0:
3039 break;
3040 }
3041 switch (numTemps)
3042 {
3043 case 3:
3044 jit_stxi_p (ofs, JIT_V2, JIT_V1);
3045 ofs += sizeof (PTR);
3046 case 2:
3047 jit_stxi_p (ofs, JIT_V2, JIT_V1);
3048 ofs += sizeof (PTR);
3049 case 1:
3050 jit_stxi_p (ofs, JIT_V2, JIT_V1);
3051 ofs += sizeof (PTR);
3052 case 0:
3053 break;
3054 }
3055
3056 jit_addi_p (JIT_V2, JIT_V2, ofs - sizeof (PTR));
3057 }
3058 else
3059 {
3060 jit_addi_p (JIT_V2, JIT_R0,
3061 jit_ptr_field (gst_method_context, contextStack[-1]));
3062 }
3063 jit_sti_p (&sp, JIT_V2);
3064 }
3065
3066 void
emit_user_defined_method_call(OOP methodOOP,int numArgs,gst_compiled_method method)3067 emit_user_defined_method_call (OOP methodOOP, int numArgs,
3068 gst_compiled_method method)
3069 {
3070 int i;
3071 char *bp = method->bytecodes;
3072 static OOP arrayAssociation;
3073
3074 current->inlineCaches = curr_inline_cache =
3075 (inline_cache *) xmalloc (2 * sizeof (inline_cache));
3076
3077 /* Emit code similar to
3078 <method> valueWithReceiver: <self> withArguments: { arg1. arg2. ... } */
3079
3080 if (!arrayAssociation)
3081 {
3082 arrayAssociation =
3083 dictionary_association_at (_gst_smalltalk_dictionary,
3084 _gst_intern_string ("Array"));
3085 }
3086
3087 t_sp = t_stack;
3088 push_tree_node_oop (bp, NULL, TREE_PUSH | TREE_LIT_CONST, methodOOP);
3089 push_tree_node (bp, NULL, TREE_PUSH | TREE_SELF, NULL);
3090
3091 /* TODO: use instantiate_oop_with instead. */
3092 push_tree_node_oop (bp, NULL, TREE_PUSH | TREE_LIT_VAR, arrayAssociation);
3093 push_tree_node_oop (bp, NULL, TREE_PUSH | TREE_LIT_CONST, FROM_INT (numArgs));
3094 push_send_node (bp, _gst_intern_string ("new:"), 1, false,
3095 TREE_SEND | TREE_NORMAL, NEW_COLON_SPECIAL);
3096
3097 for (i = 0; i < numArgs; i++)
3098 {
3099 push_tree_node (bp, NULL, TREE_PUSH | TREE_TEMP, (PTR) (uintptr_t) i);
3100 push_tree_node (bp, pop_tree_node (pop_tree_node (NULL)),
3101 TREE_STORE | TREE_POP_INTO_ARRAY,
3102 (PTR) (uintptr_t) i);
3103 }
3104
3105 push_send_node (bp, _gst_value_with_rec_with_args_symbol, 2,
3106 false, TREE_SEND | TREE_NORMAL, 0);
3107
3108 set_top_node_extra (TREE_EXTRA_RETURN, 0);
3109 emit_code ();
3110 curr_inline_cache[-1].more = false;
3111 }
3112
3113 mst_Boolean
emit_method_prolog(OOP methodOOP,gst_compiled_method method)3114 emit_method_prolog (OOP methodOOP,
3115 gst_compiled_method method)
3116 {
3117 method_header header;
3118 int flag, stack_depth;
3119 OOP receiverClass;
3120
3121 header = method->header;
3122 flag = header.headerFlag;
3123 receiverClass = current->receiverClass;
3124
3125 if (flag == MTH_USER_DEFINED)
3126 /* Include enough stack slots for the arguments, the first
3127 two parameters of #valueWithReceiver:withArguments:,
3128 the Array class, and the parameter to #new:. */
3129 stack_depth = ((header.numArgs + 4) + (1 << DEPTH_SCALE) - 1)
3130 >> DEPTH_SCALE;
3131 else
3132 stack_depth = header.stack_depth;
3133
3134
3135 jit_ldxi_p (JIT_V0, JIT_V2, sizeof (PTR) * -header.numArgs);
3136 if (receiverClass == _gst_small_integer_class)
3137 jit_bmci_ul (do_send_code, JIT_V0, 1);
3138
3139 else
3140 {
3141 jit_bmsi_ul (do_send_code, JIT_V0, 1);
3142 jit_ldxi_p (JIT_R2, JIT_V0, jit_ptr_field (OOP, object));
3143 jit_ldxi_p (JIT_R1, JIT_R2, jit_ptr_field (gst_object, objClass));
3144 jit_bnei_p (do_send_code, JIT_R1, receiverClass);
3145 }
3146
3147 /* Mark the translation as used *before* a GC can be triggered. */
3148 jit_ldi_ul (JIT_R0, &(methodOOP->flags));
3149 jit_ori_ul (JIT_R0, JIT_R0, F_XLAT_REACHABLE);
3150 jit_sti_ul (&(methodOOP->flags), JIT_R0);
3151
3152 switch (flag)
3153 {
3154 case MTH_RETURN_SELF:
3155 jit_ldxi_p (JIT_V1, JIT_V1, jit_field (inline_cache, native_ip));
3156 jit_jmpr (JIT_V1);
3157 return (true);
3158
3159 case MTH_RETURN_INSTVAR:
3160 {
3161 int ofs = jit_ptr_field (gst_object, data[header.primitiveIndex]);
3162 jit_ldxi_p (JIT_V1, JIT_V1, jit_field (inline_cache, native_ip));
3163 jit_ldxi_p (JIT_R2, JIT_R2, ofs); /* Remember? R2 is _gst_self->object */
3164 jit_str_p (JIT_V2, JIT_R2); /* Make it the stack top */
3165 jit_jmpr (JIT_V1);
3166 return (true);
3167 }
3168
3169 case MTH_RETURN_LITERAL:
3170 {
3171 OOP literal = OOP_TO_OBJ (method->literals)->data[header.primitiveIndex];
3172 jit_ldxi_p (JIT_V1, JIT_V1, jit_field (inline_cache, native_ip));
3173 jit_movi_p (JIT_R2, literal);
3174 jit_str_p (JIT_V2, JIT_R2); /* Make it the stack top */
3175 jit_jmpr (JIT_V1);
3176 return (true);
3177 }
3178
3179 default:
3180 break;
3181 }
3182
3183 jit_ldxi_p (JIT_V2, JIT_V1, jit_field (inline_cache, native_ip));
3184
3185 if (flag == MTH_PRIMITIVE)
3186 if (emit_primitive (header.primitiveIndex, header.numArgs))
3187 return (true);
3188
3189 /* Save the return IP */
3190 jit_ldi_p (JIT_R0, &_gst_this_context_oop);
3191 jit_ldxi_p (JIT_R0, JIT_R0, jit_ptr_field (OOP, object));
3192 jit_addi_p (JIT_V2, JIT_V2, 1);
3193 jit_stxi_p (jit_ptr_field (gst_method_context, native_ip), JIT_R0,
3194 JIT_V2);
3195
3196 /* Prepare new state */
3197 jit_movi_i (JIT_R0, stack_depth);
3198 jit_movi_i (JIT_V2, header.numArgs);
3199 jit_prepare (2);
3200 jit_pusharg_p (JIT_V2);
3201 jit_pusharg_p (JIT_R0);
3202 jit_finish (PTR_ACTIVATE_NEW_CONTEXT);
3203 jit_retval (JIT_R0);
3204
3205 /* Remember? V0 was loaded with _gst_self for the inline cache test */
3206 jit_sti_p (&_gst_self, JIT_V0);
3207
3208 /* Set the new context's flags, and _gst_this_method */
3209 jit_movi_p (JIT_V0, current->methodOOP);
3210 jit_movi_l (JIT_V1, MCF_IS_METHOD_CONTEXT);
3211 jit_sti_p (&_gst_this_method, JIT_V0);
3212 jit_stxi_p (jit_ptr_field (gst_method_context, flags), JIT_R0,
3213 JIT_V1);
3214
3215 /* Move the arguments and nil the temporaries */
3216 emit_context_setup (header.numArgs, header.numTemps);
3217
3218 define_ip_map_entry (0);
3219 emit_interrupt_check (JIT_NOREG);
3220
3221 /* For simplicity, we emit user-defined methods by creating a code_tree
3222 for the acrual send of #valueWithReceiver:withArguments: that they do.
3223 This requires creating the context, so we translate it now; otherwise
3224 it is very similar to a non-failing primitive. */
3225 if (flag == MTH_USER_DEFINED)
3226 {
3227 emit_user_defined_method_call (methodOOP, header.numArgs, method);
3228 return (true);
3229 }
3230
3231 return (false);
3232 }
3233
3234 mst_Boolean
emit_block_prolog(OOP blockOOP,gst_compiled_block block)3235 emit_block_prolog (OOP blockOOP,
3236 gst_compiled_block block)
3237 {
3238 block_header header;
3239 OOP receiverClass;
3240 jit_insn *x;
3241
3242 header = block->header;
3243 receiverClass = current->receiverClass;
3244
3245 /* Check if the number of arguments matches ours */
3246 jit_ldxi_uc (JIT_R2, JIT_V1, jit_field (inline_cache, numArgs));
3247 x = jit_beqi_ui (jit_forward (), JIT_R2, header.numArgs);
3248
3249 /* If they don't, check if we came here because somebody called
3250 send_block_value. In this case, the number of arguments is surely
3251 valid and the inline cache's numArgs is bogus. This handles
3252 #valueWithArguments:, #primCompile:ifError: and other primitives
3253 in which send_block_value is used. */
3254 jit_ldi_p (JIT_R2, &native_ip);
3255 jit_bnei_p (do_send_code, JIT_R2, current->nativeCode);
3256 jit_patch (x);
3257
3258 /* Check if a block evaluation was indeed requested, and if the
3259 BlockClosure really points to this CompiledBlock */
3260 jit_ldxi_p (JIT_R1, JIT_V2, sizeof (PTR) * -header.numArgs);
3261 jit_bmsi_ul (do_send_code, JIT_R1, 1);
3262 jit_ldxi_p (JIT_R1, JIT_R1, jit_ptr_field (OOP, object));
3263 jit_ldxi_p (JIT_R0, JIT_R1, jit_ptr_field (gst_object, objClass));
3264 jit_ldxi_p (JIT_R2, JIT_R1, jit_ptr_field (gst_block_closure, block));
3265 jit_bnei_p (do_send_code, JIT_R0, _gst_block_closure_class);
3266 jit_bnei_p (do_send_code, JIT_R2, current->methodOOP);
3267
3268 /* Now, the standard class check. Always load _gst_self, but don't
3269 check the receiver's class for clean blocks. */
3270 jit_ldxi_p (JIT_V0, JIT_R1,
3271 jit_ptr_field (gst_block_closure, receiver));
3272 if (block->header.clean != 0)
3273 {
3274 if (receiverClass == _gst_small_integer_class)
3275 {
3276 jit_bmci_ul (do_send_code, JIT_V0, 1);
3277 }
3278 else
3279 {
3280 jit_bmsi_ul (do_send_code, JIT_V0, 1);
3281 jit_ldxi_p (JIT_R0, JIT_V0, jit_ptr_field (OOP, object));
3282 jit_ldxi_p (JIT_R0, JIT_R0,
3283 jit_ptr_field (gst_object, objClass));
3284 jit_bnei_p (do_send_code, JIT_R0, receiverClass);
3285 }
3286 }
3287
3288 /* Mark the translation as used *before* a GC can be triggered. */
3289 jit_ldi_ul (JIT_R0, &(blockOOP->flags));
3290 jit_ori_ul (JIT_R0, JIT_R0, F_XLAT_REACHABLE);
3291 jit_sti_ul (&(blockOOP->flags), JIT_R0);
3292
3293 /* All tests passed. Now save the return IP */
3294 jit_ldxi_p (JIT_V2, JIT_V1, jit_field (inline_cache, native_ip));
3295 jit_ldi_p (JIT_R0, &_gst_this_context_oop);
3296 jit_ldxi_p (JIT_R0, JIT_R0, jit_ptr_field (OOP, object));
3297 jit_addi_p (JIT_V2, JIT_V2, 1);
3298 jit_stxi_p (jit_ptr_field (gst_method_context, native_ip), JIT_R0,
3299 JIT_V2);
3300
3301 /* Get the outer context in a callee-preserved register... */
3302 jit_ldxi_p (JIT_V1, JIT_R1,
3303 jit_ptr_field (gst_block_closure, outerContext));
3304
3305 /* prepare new state */
3306 jit_movi_i (JIT_R0, header.depth);
3307 jit_movi_i (JIT_V2, header.numArgs);
3308 jit_prepare (2);
3309 jit_pusharg_p (JIT_V2);
3310 jit_pusharg_p (JIT_R0);
3311 jit_finish (PTR_ACTIVATE_NEW_CONTEXT);
3312 jit_retval (JIT_R0);
3313
3314 /* Remember? V0 was loaded with _gst_self for the inline cache test.
3315 Also initialize _gst_this_method and the pointer to the
3316 outerContext. */
3317 jit_movi_p (JIT_R1, current->methodOOP);
3318 jit_sti_p (&_gst_self, JIT_V0);
3319 jit_sti_p (&_gst_this_method, JIT_R1);
3320 jit_stxi_p (jit_ptr_field (gst_block_context, outerContext), JIT_R0,
3321 JIT_V1);
3322
3323 /* Move the arguments and nil the temporaries */
3324 emit_context_setup (header.numArgs, header.numTemps);
3325
3326 define_ip_map_entry (0);
3327 emit_interrupt_check (JIT_NOREG);
3328
3329 return (false);
3330 }
3331
3332
3333 /* Code tree creation */
3334
3335 gst_uchar *
decode_bytecode(gst_uchar * bp)3336 decode_bytecode (gst_uchar *bp)
3337 {
3338 static OOP *specialOOPs[] = {
3339 &_gst_nil_oop, &_gst_true_oop, &_gst_false_oop
3340 };
3341
3342 MATCH_BYTECODES (XLAT_BUILD_CODE_TREE, bp, (
3343 PUSH_RECEIVER_VARIABLE {
3344 push_tree_node (IP0, NULL, TREE_PUSH | TREE_REC_VAR,
3345 (PTR) (uintptr_t) n);
3346 }
3347
3348 PUSH_TEMPORARY_VARIABLE {
3349 push_tree_node (IP0, NULL, TREE_PUSH | TREE_TEMP,
3350 (PTR) (uintptr_t) n);
3351 }
3352
3353 PUSH_LIT_CONSTANT {
3354 push_tree_node_oop (IP0, NULL, TREE_PUSH | TREE_LIT_CONST,
3355 literals[n]);
3356 }
3357
3358 PUSH_LIT_VARIABLE {
3359 if (is_a_kind_of (OOP_INT_CLASS (literals[n]), _gst_association_class))
3360 push_tree_node_oop (IP0, NULL, TREE_PUSH | TREE_LIT_VAR,
3361 literals[n]);
3362 else
3363 {
3364 push_tree_node_oop (IP0, NULL, TREE_PUSH | TREE_LIT_CONST,
3365 literals[n]);
3366 push_send_node (IP0, _gst_builtin_selectors[VALUE_SPECIAL].symbol,
3367 0, false, TREE_SEND, 0);
3368 }
3369 }
3370
3371 PUSH_SELF {
3372 push_tree_node (IP0, NULL,
3373 TREE_PUSH | TREE_SELF | self_class_check, NULL);
3374 }
3375 PUSH_SPECIAL {
3376 push_tree_node_oop (IP0, NULL, TREE_PUSH | TREE_LIT_CONST,
3377 *specialOOPs[n]);
3378 }
3379 PUSH_INTEGER {
3380 push_tree_node_oop (IP0, NULL, TREE_PUSH | TREE_LIT_CONST,
3381 FROM_INT (n));
3382 }
3383
3384 RETURN_METHOD_STACK_TOP {
3385 set_top_node_extra (TREE_EXTRA_METHOD_RET, 0);
3386 emit_code ();
3387 }
3388 RETURN_CONTEXT_STACK_TOP {
3389 set_top_node_extra (TREE_EXTRA_RETURN, 0);
3390 emit_code ();
3391 }
3392
3393 LINE_NUMBER_BYTECODE {
3394 }
3395
3396 STORE_RECEIVER_VARIABLE {
3397 push_tree_node (IP0, pop_tree_node (NULL),
3398 TREE_STORE | TREE_REC_VAR,
3399 (PTR) (uintptr_t) n);
3400 }
3401 STORE_TEMPORARY_VARIABLE {
3402 push_tree_node (IP0, pop_tree_node (NULL),
3403 TREE_STORE | TREE_TEMP,
3404 (PTR) (uintptr_t) n);
3405 }
3406 STORE_LIT_VARIABLE {
3407 if (is_a_kind_of (OOP_INT_CLASS (literals[n]), _gst_association_class))
3408 push_tree_node_oop (IP0, pop_tree_node (NULL),
3409 TREE_STORE | TREE_LIT_VAR, literals[n]);
3410 else
3411 {
3412 code_tree *value, *var;
3413 inline_cache *ic;
3414
3415 push_tree_node_oop (IP0, NULL,
3416 TREE_ALT_PUSH | TREE_LIT_CONST, literals[n]);
3417 ic = set_inline_cache (_gst_builtin_selectors[VALUE_COLON_SPECIAL].symbol,
3418 1, false, TREE_SEND, 0);
3419
3420 var = pop_tree_node (NULL);
3421 value = pop_tree_node (var);
3422 push_tree_node (IP0, value, TREE_SEND | TREE_STORE_LIT_VAR, (PTR) ic);
3423 }
3424 }
3425
3426 SEND {
3427 push_send_node (IP0, literals[n], num_args, super, TREE_SEND, 0);
3428 }
3429
3430 POP_INTO_NEW_STACKTOP {
3431 push_tree_node (IP0,
3432 pop_tree_node (pop_tree_node (NULL)),
3433 TREE_STORE | TREE_POP_INTO_ARRAY,
3434 (PTR) (uintptr_t) n);
3435 }
3436
3437 POP_STACK_TOP {
3438 set_top_node_extra (TREE_EXTRA_POP, 0);
3439 emit_code ();
3440
3441 /* This is very important! If we do not adjust T_SP here, we
3442 miscompile superoperators that include a POP/PUSH sequence. */
3443 t_sp--;
3444 }
3445 DUP_STACK_TOP {
3446 push_tree_node (IP0, NULL, TREE_PUSH | TREE_DUP, NULL);
3447 }
3448
3449 PUSH_OUTER_TEMP {
3450 push_tree_node (IP0, NULL, TREE_PUSH | TREE_OUTER_TEMP,
3451 (PTR) (uintptr_t) ((scopes << 8) | n));
3452 }
3453 STORE_OUTER_TEMP {
3454 push_tree_node (IP0,
3455 pop_tree_node (NULL),
3456 TREE_STORE | TREE_OUTER_TEMP,
3457 (PTR) (uintptr_t) ((scopes << 8) | n));
3458 }
3459
3460 JUMP {
3461 set_top_node_extra (TREE_EXTRA_JMP_ALWAYS, ofs);
3462
3463 emit_code ();
3464 }
3465 POP_JUMP_TRUE {
3466 set_top_node_extra (TREE_EXTRA_JMP_TRUE, ofs);
3467
3468 emit_code ();
3469 }
3470 POP_JUMP_FALSE {
3471 set_top_node_extra (TREE_EXTRA_JMP_FALSE, ofs);
3472
3473 emit_code ();
3474 }
3475
3476 SEND_ARITH {
3477 int op = special_send_bytecodes[n];
3478 const struct builtin_selector *bs = &_gst_builtin_selectors[n];
3479 push_send_node (IP0, bs->symbol, bs->numArgs, false, op, n);
3480 }
3481 SEND_SPECIAL {
3482 int op = special_send_bytecodes[n + 16];
3483 const struct builtin_selector *bs = &_gst_builtin_selectors[n + 16];
3484 push_send_node (IP0, bs->symbol, bs->numArgs, false, op, n + 16);
3485 }
3486 SEND_IMMEDIATE {
3487 const struct builtin_selector *bs = &_gst_builtin_selectors[n];
3488 push_send_node (IP0, bs->symbol, bs->numArgs, super,
3489 TREE_SEND | TREE_NORMAL, n);
3490 }
3491
3492 MAKE_DIRTY_BLOCK {
3493 code_tree *arg;
3494 arg = pop_tree_node (NULL);
3495 push_tree_node (IP0, arg, TREE_SEND | TREE_DIRTY_BLOCK, NULL);
3496 }
3497
3498 EXIT_INTERPRETER, INVALID {
3499 abort ();
3500 }
3501 ));
3502
3503 #if 0
3504 /* These used to be here but we do not produce them anymore. It would
3505 speed up the code a bit, so they are kept here as a remainder. */
3506
3507 REPLACE_SELF {
3508 push_tree_node (IP0,
3509 pop_tree_node (NULL),
3510 TREE_SET_TOP | TREE_SELF | self_class_check, NULL);
3511
3512 emit_code ();
3513 }
3514 REPLACE_ONE {
3515 push_tree_node_oop (IP0,
3516 pop_tree_node (NULL),
3517 TREE_SET_TOP | TREE_LIT_CONST, FROM_INT (1));
3518
3519 emit_code ();
3520 }
3521
3522 REPLACE_RECEIVER_VARIABLE {
3523 push_tree_node (IP0,
3524 pop_tree_node (NULL),
3525 TREE_SET_TOP | TREE_REC_VAR,
3526 (PTR) (uintptr_t) n);
3527
3528 emit_code ();
3529 }
3530 REPLACE_TEMPORARY_VARIABLE {
3531 push_tree_node (IP0,
3532 pop_tree_node (NULL),
3533 TREE_SET_TOP | TREE_TEMP,
3534 (PTR) (uintptr_t) n);
3535
3536 emit_code ();
3537 }
3538 REPLACE_LIT_CONSTANT {
3539 push_tree_node (IP0,
3540 pop_tree_node (NULL),
3541 TREE_SET_TOP | TREE_LIT_CONST,
3542 literals[n]);
3543
3544 emit_code ();
3545 }
3546 REPLACE_LIT_VARIABLE {
3547 push_tree_node (IP0,
3548 pop_tree_node (NULL),
3549 TREE_SET_TOP | TREE_LIT_VAR,
3550 literals[n]);
3551
3552 emit_code ();
3553 }
3554 #endif
3555
3556 return bp;
3557 }
3558
3559
3560
3561
3562 /* Main translator loop */
3563 void
translate_method(OOP methodOOP,OOP receiverClass,int size)3564 translate_method (OOP methodOOP, OOP receiverClass, int size)
3565 {
3566 gst_uchar *end, *bp, *bp_first;
3567 int inlineCacheCount;
3568 char *destinations;
3569 code_stack_pointer *stackPos;
3570 int i;
3571
3572 rec_var_cached = self_cached = false;
3573 stack_cached = -1;
3574 sp_delta = -sizeof (PTR);
3575 deferred_head = NULL;
3576 method_class = GET_METHOD_CLASS (methodOOP);
3577 bc = GET_METHOD_BYTECODES (methodOOP);
3578 literals = GET_METHOD_LITERALS (methodOOP);
3579 end = bc + size;
3580
3581 if (receiverClass == _gst_small_integer_class)
3582 self_class_check = TREE_IS_INTEGER;
3583
3584 else
3585 self_class_check = TREE_IS_NOT_INTEGER;
3586
3587 /* Emit the prolog of the compiled code. */
3588 jit_ldi_p (JIT_V2, &sp);
3589 if (OOP_CLASS (methodOOP) == _gst_compiled_block_class)
3590 {
3591 if (emit_block_prolog
3592 (methodOOP, (gst_compiled_block) OOP_TO_OBJ (methodOOP)))
3593 return;
3594 }
3595 else
3596 {
3597 if (emit_method_prolog
3598 (methodOOP, (gst_compiled_method) OOP_TO_OBJ (methodOOP)))
3599 return;
3600 }
3601
3602
3603 /* Count the space for the inline caches */
3604 for (inlineCacheCount = 0, bp = bc; bp < end; )
3605 MATCH_BYTECODES (XLAT_COUNT_SENDS, bp, (
3606 PUSH_RECEIVER_VARIABLE, PUSH_TEMPORARY_VARIABLE,
3607 PUSH_LIT_CONSTANT, PUSH_SELF,
3608 PUSH_SPECIAL, PUSH_INTEGER, RETURN_METHOD_STACK_TOP,
3609 RETURN_CONTEXT_STACK_TOP, LINE_NUMBER_BYTECODE,
3610 STORE_RECEIVER_VARIABLE, STORE_TEMPORARY_VARIABLE,
3611 POP_INTO_NEW_STACKTOP,
3612 POP_STACK_TOP, DUP_STACK_TOP, PUSH_OUTER_TEMP,
3613 STORE_OUTER_TEMP, JUMP, POP_JUMP_TRUE, POP_JUMP_FALSE,
3614 MAKE_DIRTY_BLOCK, EXIT_INTERPRETER, INVALID { }
3615
3616 PUSH_LIT_VARIABLE, STORE_LIT_VARIABLE {
3617 if (!is_a_kind_of (OOP_INT_CLASS (literals[n]), _gst_association_class))
3618 inlineCacheCount++;
3619 }
3620
3621 SEND_ARITH, SEND_SPECIAL, SEND_IMMEDIATE, SEND {
3622 inlineCacheCount++;
3623 }
3624 ));
3625
3626
3627 if (inlineCacheCount)
3628 {
3629 current->inlineCaches = curr_inline_cache =
3630 (inline_cache *) xmalloc (inlineCacheCount *
3631 sizeof (inline_cache));
3632 }
3633
3634 stackPos = alloca ((1 + size) * sizeof (code_stack_pointer *));
3635 labels = alloca ((1 + size) * sizeof (label *));
3636 destinations = (char *) labels;
3637
3638 _gst_compute_stack_positions (bc, size, (PTR *) t_stack, (PTR **) stackPos);
3639 _gst_analyze_bytecodes (methodOOP, size, destinations);
3640
3641 /* Create labels for bytecodes on which a jump lands */
3642 for (i = size; --i >= 0;)
3643 labels[i] = destinations[i] ? lbl_new () : NULL;
3644
3645 /* Now, go through the main translation loop */
3646 for (bp = bc, this_label = labels; bp < end; )
3647 {
3648 if (!*stackPos)
3649 {
3650 assert (!*this_label);
3651 this_label += 2;
3652 stackPos += 2;
3653 continue;
3654 }
3655
3656 /* Updating the t_sp in push_tree_node/pop_tree_node is not
3657 enough, because if two basic blocks are mutually exclusive the
3658 SP at the second block's entrance must be the same as the SP at
3659 the first block's entrance, even if the blocks have a non-zero
3660 stack balance. */
3661 t_sp = *stackPos;
3662
3663 if (*this_label)
3664 {
3665 /* A basic block ends here. Compile it. */
3666 emit_code ();
3667 CACHE_STACK_TOP;
3668
3669 /* If the label was not used yet, it will be used for a
3670 backward jump. A backward jump could be used to code an
3671 infinite loop such as `[] repeat', so we test
3672 _gst_except_flag here. */
3673 if (!lbl_define (*this_label))
3674 {
3675 define_ip_map_entry (bp - bc);
3676 jit_movi_ul (JIT_V0, bp - bc);
3677 jit_sti_ul (&ip, JIT_V0);
3678 emit_interrupt_check (JIT_NOREG);
3679 }
3680 }
3681
3682 bp_first = bp;
3683 bp = decode_bytecode (bp);
3684 this_label += bp - bp_first;
3685 stackPos += bp - bp_first;
3686 }
3687
3688 emit_code ();
3689 emit_deferred_sends (deferred_head);
3690
3691 if (inlineCacheCount)
3692 curr_inline_cache[-1].more = false;
3693 }
3694
3695
3696 /* External interfacing */
3697
3698 void
_gst_init_translator(void)3699 _gst_init_translator (void)
3700 {
3701 static mst_Boolean initialized = false;
3702
3703 if (!initialized)
3704 {
3705 initialized = true;
3706 generate_run_time_code ();
3707 memset (methods_table, 0, sizeof (methods_table));
3708 }
3709 }
3710
3711 PTR
_gst_map_virtual_ip(OOP methodOOP,OOP receiverClass,int ip)3712 _gst_map_virtual_ip (OOP methodOOP, OOP receiverClass, int ip)
3713 {
3714 ip_map *map;
3715 method_entry *method;
3716
3717 method = find_method_entry (methodOOP, receiverClass);
3718
3719 map = method->ipMap;
3720 if (!map)
3721 return NULL;
3722
3723 do
3724 if (map->virtualIP == ip)
3725 return map->native_ip;
3726 while ((++map)->native_ip);
3727
3728 return NULL;
3729 }
3730
3731 PTR
_gst_get_native_code(OOP methodOOP,OOP receiverClass)3732 _gst_get_native_code (OOP methodOOP, OOP receiverClass)
3733 {
3734 if (!IS_OOP_VERIFIED (methodOOP))
3735 _gst_verify_sent_method (methodOOP);
3736
3737 return find_method_entry (methodOOP, receiverClass)->nativeCode;
3738 }
3739
3740 method_entry *
find_method_entry(OOP methodOOP,OOP receiverClass)3741 find_method_entry (OOP methodOOP, OOP receiverClass)
3742 {
3743 method_entry *method, *prev;
3744 unsigned int hashEntry;
3745 int size;
3746
3747 if (IS_NIL (methodOOP))
3748 return (NULL);
3749
3750 hashEntry = OOP_INDEX (methodOOP) % HASH_TABLE_SIZE;
3751 if ((method = methods_table[hashEntry]))
3752 {
3753 if (method->methodOOP == methodOOP
3754 && method->receiverClass == receiverClass)
3755 return method;
3756
3757 for (prev = method; (method = method->next); prev = method)
3758 {
3759 if (method->methodOOP != methodOOP
3760 || method->receiverClass != receiverClass)
3761 continue;
3762
3763 prev->next = method->next;
3764 method->next = methods_table[hashEntry];
3765 methods_table[hashEntry] = method;
3766 return method;
3767 }
3768 }
3769
3770 size = NUM_INDEXABLE_FIELDS (methodOOP);
3771 new_method_entry (methodOOP, receiverClass, size);
3772 translate_method (methodOOP, receiverClass, size);
3773 return (finish_method_entry ());
3774 }
3775
3776 void
reset_invalidated_inline_caches()3777 reset_invalidated_inline_caches ()
3778 {
3779 method_entry *method, **hashEntry;
3780 inline_cache *ic;
3781 jit_insn *lookupIP;
3782
3783 for (hashEntry = methods_table; hashEntry <= &discarded; hashEntry++)
3784 for (method = *hashEntry; method; method = method->next)
3785 {
3786 ic = method->inlineCaches;
3787 if (!ic)
3788 continue;
3789
3790 do
3791 {
3792 lookupIP = ic->is_super ? do_super_code : do_send_code;
3793 if (ic->cachedIP != lookupIP && !IS_VALID_IP (ic->cachedIP))
3794 ic->cachedIP = lookupIP;
3795 }
3796 while ((ic++)->more);
3797 }
3798 }
3799
3800 void
_gst_reset_inline_caches()3801 _gst_reset_inline_caches ()
3802 {
3803 method_entry *method, **hashEntry;
3804 inline_cache *ic;
3805
3806 for (hashEntry = methods_table; hashEntry <= &discarded; hashEntry++)
3807 for (method = *hashEntry; method; method = method->next)
3808 {
3809 ic = method->inlineCaches;
3810 if (!ic)
3811 continue;
3812
3813 do
3814 ic->cachedIP = ic->is_super ? do_super_code : do_send_code;
3815 while ((ic++)->more);
3816 }
3817 }
3818
3819 void
_gst_free_released_native_code(void)3820 _gst_free_released_native_code (void)
3821 {
3822 method_entry *method;
3823
3824 if (!released)
3825 return;
3826
3827 reset_invalidated_inline_caches ();
3828 _gst_validate_method_cache_entries ();
3829
3830 /* now free the list */
3831 while ((method = released))
3832 {
3833 released = released->next;
3834 xfree (method);
3835 }
3836 }
3837
3838 void
walk_and_remove_method(OOP methodOOP,method_entry ** ptrNext)3839 walk_and_remove_method (OOP methodOOP, method_entry **ptrNext)
3840 {
3841 method_entry *method;
3842
3843 while ((method = *ptrNext))
3844 {
3845 if (method->methodOOP != methodOOP)
3846 {
3847 /* Move ptrNext forward */
3848 ptrNext = &(method->next);
3849 continue;
3850 }
3851
3852 /* Adjust the list */
3853 *ptrNext = method->next;
3854 method->next = released;
3855 released = method;
3856
3857 /* Mark the method as freed */
3858 if (method->inlineCaches)
3859 xfree (method->inlineCaches);
3860
3861 method->receiverClass = NULL;
3862 method->inlineCaches = NULL;
3863 }
3864
3865 /* Terminate the list */
3866 *ptrNext = NULL;
3867 }
3868
3869 void
_gst_release_native_code(OOP methodOOP)3870 _gst_release_native_code (OOP methodOOP)
3871 {
3872 unsigned int hashEntry;
3873
3874 hashEntry = OOP_INDEX (methodOOP) % HASH_TABLE_SIZE;
3875 walk_and_remove_method (methodOOP, &methods_table[hashEntry]);
3876 methodOOP->flags &= ~F_XLAT;
3877
3878 if (methodOOP->flags & F_XLAT_DISCARDED)
3879 {
3880 walk_and_remove_method (methodOOP, &discarded);
3881 methodOOP->flags &= ~F_XLAT_DISCARDED;
3882 }
3883 }
3884
3885 void
_gst_discard_native_code(OOP methodOOP)3886 _gst_discard_native_code (OOP methodOOP)
3887 {
3888 method_entry *method, **ptrNext;
3889 unsigned int hashEntry;
3890
3891 methodOOP->flags |= F_XLAT_DISCARDED;
3892 hashEntry = OOP_INDEX (methodOOP) % HASH_TABLE_SIZE;
3893 ptrNext = &methods_table[hashEntry];
3894
3895 while ((method = *ptrNext))
3896 {
3897 if (method->methodOOP != methodOOP)
3898 {
3899 /* Move ptrNext forward */
3900 ptrNext = &(method->next);
3901 continue;
3902 }
3903
3904 assert (methodOOP->flags & F_XLAT);
3905
3906 /* Move to the `discarded' list */
3907 *ptrNext = method->next;
3908 method->next = discarded;
3909 discarded = method;
3910 }
3911
3912 /* Terminate the list */
3913 *ptrNext = NULL;
3914 }
3915
3916 #endif /* ENABLE_JIT_TRANSLATION */
3917