1 /******************************** -*- C -*- ****************************
2  *
3  *	Byte code array utility routines.
4  *
5  *
6  ***********************************************************************/
7 
8 /***********************************************************************
9  *
10  * Copyright 1988,89,90,91,92,94,95,99,2000,2001,2002,2003,2006,2008,2009
11  * Free Software Foundation, Inc.
12  * Written by Steve Byrne.
13  *
14  * This file is part of GNU Smalltalk.
15  *
16  * GNU Smalltalk is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the Free
18  * Software Foundation; either version 2, or (at your option) any later
19  * version.
20  *
21  * Linking GNU Smalltalk statically or dynamically with other modules is
22  * making a combined work based on GNU Smalltalk.  Thus, the terms and
23  * conditions of the GNU General Public License cover the whole
24  * combination.
25  *
26  * In addition, as a special exception, the Free Software Foundation
27  * give you permission to combine GNU Smalltalk with free software
28  * programs or libraries that are released under the GNU LGPL and with
29  * independent programs running under the GNU Smalltalk virtual machine.
30  *
31  * You may copy and distribute such a system following the terms of the
32  * GNU GPL for GNU Smalltalk and the licenses of the other code
33  * concerned, provided that you include the source code of that other
34  * code when and as the GNU GPL requires distribution of source code.
35  *
36  * Note that people who make modified versions of GNU Smalltalk are not
37  * obligated to grant this special exception for their modified
38  * versions; it is their choice whether to do so.  The GNU General
39  * Public License gives permission to release a modified version without
40  * this exception; this exception also makes it possible to release a
41  * modified version which carries forward this exception.
42  *
43  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
44  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
45  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
46  * more details.
47  *
48  * You should have received a copy of the GNU General Public License along with
49  * GNU Smalltalk; see the file COPYING.	 If not, write to the Free Software
50  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
51  *
52  ***********************************************************************/
53 
54 #include "gstpriv.h"
55 #include "match.h"
56 
57 #define BYTECODE_CHUNK_SIZE  64
58 
59 /* Where the compiled bytecodes go.  */
60 bc_vector _gst_cur_bytecodes;
61 
62 /* Reallocate an array of bytecodes, leaving space for DELTA more
63    bytes.  */
64 static void realloc_bytecodes (bc_vector bytecodes,
65 			       int delta);
66 
67 
68 
69 
70 bc_vector
_gst_extract_bytecodes(OOP byteArrayOOP)71 _gst_extract_bytecodes (OOP byteArrayOOP)
72 {
73   bc_vector result;
74   int len;
75   gst_byte_array byteArray;
76 
77   byteArray = (gst_byte_array) OOP_TO_OBJ (byteArrayOOP);
78   len = oop_num_fields (byteArrayOOP);
79   result = (bc_vector) xmalloc (sizeof (struct bytecode_array));
80 
81   result->base = (gst_uchar *) xmalloc (len);
82   result->ptr = result->base + len;
83   result->maxLen = len;
84   memcpy (result->base, byteArray->bytes, len);
85   return (result);
86 }
87 
88 static int next_line_number;
89 
90 static void
compile_byte(gst_uchar byte,int arg)91 compile_byte (gst_uchar byte, int arg)
92 {
93   int num_bytes;
94   long n;
95 
96   for (num_bytes = 2, n = arg; n > 255; n >>= 8)
97     num_bytes += 2;
98 
99   assert (_gst_cur_bytecodes);
100 
101   if ((_gst_cur_bytecodes->ptr - _gst_cur_bytecodes->base) >
102 	   _gst_cur_bytecodes->maxLen - num_bytes)
103 
104     realloc_bytecodes (_gst_cur_bytecodes, BYTECODE_CHUNK_SIZE);
105 
106 
107   while (num_bytes > 2)
108     {
109       num_bytes -= 2;
110       *_gst_cur_bytecodes->ptr++ = EXT_BYTE;
111       *_gst_cur_bytecodes->ptr++ = (arg >> (num_bytes * 4)) & 255;
112     }
113 
114   *_gst_cur_bytecodes->ptr++ = byte;
115   *_gst_cur_bytecodes->ptr++ = arg & 255;
116 }
117 
118 void
_gst_line_number(int n,int flags)119 _gst_line_number (int n, int flags)
120 {
121   static int prev_line;
122   static int line_offset;
123 
124   if (n > 65535)
125     n = 65535;
126 
127   if (flags & LN_RESET)
128     {
129       assert (!(flags & LN_FORCE));
130       assert (n > 0);
131       if (flags & LN_ABSOLUTE)
132 	{
133 	  compile_byte (LINE_NUMBER_BYTECODE, n);
134 	  prev_line = n;
135 	}
136       line_offset = n - 1;
137       next_line_number = -1;
138     }
139   else
140     {
141       assert (!(flags & LN_ABSOLUTE));
142       if (n == -1)
143 	{
144 	  prev_line = -1;
145 	  next_line_number = -1;
146 	}
147       else
148 	{
149 	  assert (n > line_offset);
150 	  if ((flags & LN_FORCE) || n != prev_line)
151 	    {
152 	      prev_line = n;
153 	      next_line_number = n - line_offset;
154 	    }
155 	}
156     }
157 }
158 
159 void
_gst_compile_byte(gst_uchar byte,int arg)160 _gst_compile_byte (gst_uchar byte, int arg)
161 {
162   if (next_line_number != -1)
163     {
164       compile_byte (LINE_NUMBER_BYTECODE, next_line_number);
165       next_line_number = -1;
166     }
167 
168   compile_byte (byte, arg);
169 }
170 
171 void
_gst_free_bytecodes(bc_vector bytecodes)172 _gst_free_bytecodes (bc_vector bytecodes)
173 {
174   if (bytecodes != NULL)
175     {
176       xfree (bytecodes->base);
177       xfree (bytecodes);
178     }
179 }
180 
181 void
_gst_compile_and_free_bytecodes(bc_vector bytecodes)182 _gst_compile_and_free_bytecodes (bc_vector bytecodes)
183 {
184   _gst_compile_bytecodes (bytecodes->base, bytecodes->ptr);
185 
186   /* First add the worst case, then leave the net effect.  */
187   ADD_STACK_DEPTH (bytecodes->max_stack_depth);
188   SUB_STACK_DEPTH (bytecodes->max_stack_depth - bytecodes->stack_depth);
189 
190   _gst_free_bytecodes (bytecodes);
191 }
192 
193 bc_vector
_gst_get_bytecodes(void)194 _gst_get_bytecodes (void)
195 {
196   bc_vector curBytecodes;
197 
198   curBytecodes = _gst_cur_bytecodes;
199   _gst_cur_bytecodes = NULL;
200 
201   return (curBytecodes);
202 }
203 
204 
205 bc_vector
_gst_save_bytecode_array()206 _gst_save_bytecode_array ()
207 {
208   bc_vector curBytecodes;
209 
210   curBytecodes = _gst_cur_bytecodes;
211   _gst_alloc_bytecodes ();
212 
213   return (curBytecodes);
214 }
215 
216 
217 void
_gst_restore_bytecode_array(bc_vector bytecodes)218 _gst_restore_bytecode_array (bc_vector bytecodes)
219 {
220   _gst_cur_bytecodes = bytecodes;
221 }
222 
223 int
_gst_bytecode_length(bc_vector bytecodes)224 _gst_bytecode_length (bc_vector bytecodes)
225 {
226   if (bytecodes == NULL)
227     return (0);
228 
229   return (bytecodes->ptr - bytecodes->base);
230 }
231 
232 
233 int
_gst_current_bytecode_length(void)234 _gst_current_bytecode_length (void)
235 {
236   if (_gst_cur_bytecodes == NULL)
237     return (0);
238 
239   return (_gst_cur_bytecodes->ptr - _gst_cur_bytecodes->base);
240 }
241 
242 void
_gst_copy_bytecodes(gst_uchar * dest,bc_vector bytecodes)243 _gst_copy_bytecodes (gst_uchar * dest,
244 		     bc_vector bytecodes)
245 {
246   memcpy (dest, bytecodes->base, _gst_bytecode_length (bytecodes));
247 }
248 
249 void
_gst_truncate_bytecodes(gst_uchar * here,bc_vector bytecodes)250 _gst_truncate_bytecodes (gst_uchar * here,
251 			 bc_vector bytecodes)
252 {
253   bytecodes->ptr = here;
254 }
255 
256 
257 
258 void
_gst_print_bytecodes(bc_vector bytecodes,OOP * literal_vec)259 _gst_print_bytecodes (bc_vector bytecodes,
260 		      OOP * literal_vec)
261 {
262   gst_uchar *b;
263   int ip;
264 
265   if (bytecodes == NULL)
266     return;
267 
268   for (b = bytecodes->base; b < bytecodes->ptr; )
269     {
270       ip = b - bytecodes->base;
271       printf ("%5d:", ip);
272       b = _gst_print_bytecode_name (b, ip, literal_vec, "");
273     }
274   printf ("\n");
275 }
276 
277 gst_uchar *
_gst_print_bytecode_name(gst_uchar * bp,int ip,OOP * literal_vec,const char * pref)278 _gst_print_bytecode_name (gst_uchar * bp,
279 			  int ip,
280 			  OOP * literal_vec,
281 			  const char *pref)
282 {
283   const char *prefix = "";
284   gst_uchar b = *bp;
285 
286   MATCH_BYTECODES (PRINT_BYTECODE_NAME, bp, (
287     PUSH_RECEIVER_VARIABLE {
288       printf ("%s\tpush Instance Variable[%d]\n", prefix, n);
289       prefix = pref;
290     }
291 
292     PUSH_TEMPORARY_VARIABLE {
293       printf ("%s\tpush Temporary Variable[%d]\n", prefix, n);
294       prefix = pref;
295     }
296 
297     PUSH_LIT_CONSTANT {
298       printf ("%s\tpush Literal[%d]", prefix, n);
299       if (literal_vec)
300 	printf (" = %O", literal_vec[n]);
301       printf ("\n");
302       prefix = pref;
303     }
304 
305     PUSH_LIT_VARIABLE {
306       printf ("%s\tpush Global Variable[%d]", prefix, n);
307       if (literal_vec)
308 	printf (" = %+O", literal_vec[n]);
309       printf ("\n");
310       prefix = pref;
311     }
312 
313     PUSH_SELF {
314       printf ("%s\tpush self\n", prefix);
315       prefix = pref;
316     }
317     PUSH_SPECIAL {
318       switch (n) {
319 	case TRUE_INDEX: printf ("%s\tpush true\n", prefix); break;
320 	case FALSE_INDEX: printf ("%s\tpush false\n", prefix); break;
321 	case NIL_INDEX: printf ("%s\tpush nil\n", prefix); break;
322       }
323       prefix = pref;
324     }
325     PUSH_INTEGER {
326       printf ("%s\tpush %d\n", prefix, n);
327       prefix = pref;
328     }
329 
330     RETURN_METHOD_STACK_TOP {
331       printf ("%s\treturn explicitly from method\n", prefix);
332       prefix = pref;
333     }
334     RETURN_CONTEXT_STACK_TOP {
335       printf ("%s\treturn stack top\n", prefix);
336       prefix = pref;
337     }
338 
339     LINE_NUMBER_BYTECODE {
340       printf ("%s\tsource line %d\n", prefix, n);
341       prefix = pref;
342     }
343 
344     STORE_RECEIVER_VARIABLE {
345       printf ("%s\tstore into Instance Variable[%d]\n", prefix, n);
346       prefix = pref;
347     }
348     STORE_TEMPORARY_VARIABLE {
349       printf ("%s\tstore into Temporary Variable[%d]\n", prefix, n);
350       prefix = pref;
351     }
352     STORE_LIT_VARIABLE {
353       printf ("%s\tstore into Global Variable[%d]", prefix, n);
354       if (literal_vec)
355 	printf (" = %+O", literal_vec[n]);
356       printf ("\n");
357       prefix = pref;
358     }
359 
360     SEND {
361       printf ("%s\tsend selector %d%s, %d args", prefix, n, super ? " to super" : "", num_args);
362       if (literal_vec)
363 	printf (" = %O", literal_vec[n]);
364       printf ("\n");
365       prefix = pref;
366     }
367 
368     POP_INTO_NEW_STACKTOP {
369       printf ("%s\tpop and store into Instance Variable[%d] of new stack top\n", prefix, n);
370       prefix = pref;
371     }
372 
373     POP_STACK_TOP {
374       printf ("%s\tpop stack top\n", prefix);
375       prefix = pref;
376     }
377     DUP_STACK_TOP {
378       printf ("%s\tduplicate stack top\n", prefix);
379       prefix = pref;
380     }
381 
382     PUSH_OUTER_TEMP {
383       printf ("%s\tpush outer var scopes = %d varIndex = %d\n", prefix, scopes, n);
384       prefix = pref;
385     }
386     STORE_OUTER_TEMP {
387       printf ("%s\tstore outer var scopes = %d varIndex = %d\n", prefix, scopes, n);
388       prefix = pref;
389     }
390 
391     EXIT_INTERPRETER {
392       printf ("%s\tterminate interpreter\n", prefix);
393       prefix = pref;
394     }
395 
396     JUMP {
397       printf ("%s\tjump to %d\n", prefix, ip + ofs);
398       prefix = pref;
399     }
400     POP_JUMP_TRUE {
401       printf ("%s\tpop and jump to %d if true\n", prefix, ip + ofs);
402       prefix = pref;
403     }
404     POP_JUMP_FALSE {
405       printf ("%s\tpop and jump to %d if false\n", prefix, ip + ofs);
406       prefix = pref;
407     }
408 
409     SEND_ARITH {
410       printf ("%s\tsend arithmetic message %O\n", prefix,
411 	      _gst_builtin_selectors[n].symbol);
412       prefix = pref;
413     }
414     SEND_SPECIAL {
415       printf ("%s\tsend special message %O\n", prefix,
416 	      _gst_builtin_selectors[n + 16].symbol);
417       prefix = pref;
418     }
419 
420     MAKE_DIRTY_BLOCK {
421       printf ("%s\tmake dirty block\n", prefix);
422       prefix = pref;
423     }
424 
425     SEND_IMMEDIATE {
426       printf ("%s\tsend special message %O%s\n", prefix,
427 	      _gst_builtin_selectors[n].symbol,
428 	      super ? " to super" : "");
429       prefix = pref;
430     }
431 
432     INVALID {
433       printf ("%s\tINVALID BYTECODE %d(%d)\n", prefix, b, arg);
434       prefix = pref;
435     }
436   ));
437   return bp;
438 }
439 
440 void
_gst_compile_bytecodes(gst_uchar * from,gst_uchar * to)441 _gst_compile_bytecodes (gst_uchar * from,
442 			gst_uchar * to)
443 {
444   int free;
445   assert (_gst_cur_bytecodes);
446 
447   free = _gst_cur_bytecodes->maxLen -
448     (_gst_cur_bytecodes->ptr - _gst_cur_bytecodes->base);
449 
450   if (free < (to - from))
451     {
452       memcpy (_gst_cur_bytecodes->ptr, from, free);
453       _gst_cur_bytecodes->ptr += free;
454       from += free;
455       realloc_bytecodes (_gst_cur_bytecodes,
456 		         BYTECODE_CHUNK_SIZE + (to - from));
457     }
458 
459   memcpy (_gst_cur_bytecodes->ptr, from, to - from);
460   _gst_cur_bytecodes->ptr += to - from;
461 }
462 
463 void
_gst_alloc_bytecodes()464 _gst_alloc_bytecodes ()
465 {
466   bc_vector newBytecodes;
467 
468   newBytecodes = (bc_vector) xmalloc (sizeof (struct bytecode_array));
469   newBytecodes->base = (gst_uchar *) xmalloc (BYTECODE_CHUNK_SIZE);
470   newBytecodes->ptr = newBytecodes->base;
471   newBytecodes->maxLen = BYTECODE_CHUNK_SIZE;
472 
473   newBytecodes->stack_depth = 0;
474   newBytecodes->max_stack_depth = 0;
475 
476   _gst_cur_bytecodes = newBytecodes;
477 }
478 
479 void
realloc_bytecodes(bc_vector bytecodes,int delta)480 realloc_bytecodes (bc_vector bytecodes,
481 		   int delta)
482 {
483   int size;
484 
485   size = bytecodes->ptr - bytecodes->base;
486 
487   bytecodes->base =
488     (gst_uchar *) xrealloc (bytecodes->base, bytecodes->maxLen + delta);
489   bytecodes->ptr = bytecodes->base + size;
490   bytecodes->maxLen += delta;
491 }
492