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