2 * Optimized `switch' instruction dispatcher.
3 * Copyright (c) 1998 New Generation Software (NGS) Oy
5 * Author: Markku Rossi <mtr@ngs.fi>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/src/vmswitch.c,v $
33 * Types and definitions.
37 reloc[cp - fixed_code - 1] = &f->code[cpos]; \
38 f->code[cpos++].u.op = (a)
40 #define SAVE_INT8(a) f->code[cpos++].u.i8 = (a)
41 #define SAVE_INT16(a) f->code[cpos++].u.i16 = (a)
42 #define SAVE_INT32(a) f->code[cpos++].u.i32 = (a)
44 #define ARG_INT32() f->code[cpos].u.i32
46 #define READ_INT8(var) (var) = (pc++)->u.i8
47 #define READ_INT16(var) (var) = (pc++)->u.i16
48 #define READ_INT32(var) (var) = (pc++)->u.i32
50 #define SETPC(ofs) pc = (ofs)
51 #define SETPC_RELATIVE(ofs) pc += (ofs)
53 #define CALL_USER_FUNC(f) pc = ((Function *) (f))->code
55 #define DONE() goto done
60 strcpy (vm->error, (msg)); \
78 typedef struct compiled_st Compiled
;
80 /* Debug information. */
87 typedef struct debug_info_st DebugInfo
;
91 JSHeapDestroyableCB destroy
;
100 unsigned int num_info
;
105 typedef struct function_st Function
;
109 * Prototypes for static functions.
112 static void function_destroy (void *ptr
);
114 static Function
*link_code (JSVirtualMachine
*vm
, unsigned char *code
,
115 unsigned int code_len
,
116 unsigned int consts_offset
,
117 unsigned char *debug_info
,
118 unsigned int debug_info_len
,
119 unsigned int code_offset
);
121 static void execute_code (JSVirtualMachine
*vm
, JSNode
*object
, Function
*f
,
122 unsigned int argc
, JSNode
*argv
);
130 js_vm_switch_exec (JSVirtualMachine
*vm
, JSByteCode
*bc
, JSSymtabEntry
*symtab
,
131 unsigned int num_symtab_entries
,
132 unsigned int consts_offset
,
133 unsigned int anonymous_function_offset
,
134 unsigned char *debug_info
, unsigned int debug_info_len
,
135 JSNode
*object
, JSNode
*func
,
136 unsigned int argc
, JSNode
*argv
)
140 Function
*global_f
= NULL
;
142 unsigned char *code
= NULL
;
147 /* Executing byte-code. */
149 /* Find the code section. */
150 for (i
= 0; i
< bc
->num_sects
; i
++)
151 if (bc
->sects
[i
].type
== JS_BCST_CODE
)
152 code
= bc
->sects
[i
].data
;
153 assert (code
!= NULL
);
155 /* Enter all functions to the known functions of the VM. */
156 for (i
= 0; i
< num_symtab_entries
; i
++)
158 /* Link the code to our environment. */
159 f
= link_code (vm
, code
+ symtab
[i
].offset
,
160 symtab
[i
+ 1].offset
- symtab
[i
].offset
,
161 consts_offset
, debug_info
, debug_info_len
,
163 f
->name
= js_strdup (vm
, symtab
[i
].name
);
165 if (strcmp (symtab
[i
].name
, JS_GLOBAL_NAME
) == 0)
169 int is_anonymous
= 0;
171 /* Check for the anonymous function. */
172 if (symtab
[i
].name
[0] == '.' && symtab
[i
].name
[1] == 'F'
173 && symtab
[i
].name
[2] == ':')
178 sprintf (buf
, "VM: link: %s(): start=%d, length=%d",
179 symtab
[i
].name
, symtab
[i
].offset
,
180 symtab
[i
+ 1].offset
- symtab
[i
].offset
);
182 sprintf (buf
+ strlen (buf
),
183 ", relocating with offset %u",
184 anonymous_function_offset
);
185 strcat (buf
, JS_HOST_LINE_BREAK
);
186 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
191 sprintf (buf
, ".F:%u",
192 (unsigned int) atoi (symtab
[i
].name
+ 3)
193 + anonymous_function_offset
);
194 ui
= js_vm_intern (vm
, buf
);
197 ui
= js_vm_intern (vm
, symtab
[i
].name
);
199 vm
->globals
[ui
].type
= JS_FUNC
;
200 vm
->globals
[ui
].u
.vfunction
= js_vm_make_function (vm
, f
);
206 /* Applying arguments to function. */
208 if (func
->type
!= JS_FUNC
)
210 sprintf (vm
->error
, "illegal function in apply");
216 sprintf (buf
, "VM: calling function%s",
218 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
220 f
= func
->u
.vfunction
->implementation
;
222 execute_code (vm
, object
, f
, argc
, argv
);
229 sprintf (buf
, "VM: exec: %s%s", global_f
->name
,
231 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
235 execute_code (vm
, NULL
, global_f
, 0, NULL
);
243 js_vm_switch_func_name (JSVirtualMachine
*vm
, void *program_counter
)
247 Compiled
*pc
= program_counter
;
250 /* Check the globals. */
251 for (i
= 0; i
< vm
->num_globals
; i
++)
252 if (vm
->globals
[i
].type
== JS_FUNC
)
254 f
= (Function
*) vm
->globals
[i
].u
.vfunction
->implementation
;
255 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
259 /* No luck. Let's try the stack. */
260 for (sp
++; sp
< vm
->stack
+ vm
->stack_size
; sp
++)
261 if (sp
->type
== JS_FUNC
)
263 f
= (Function
*) sp
->u
.vfunction
->implementation
;
264 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
268 /* Still no matches. This shouldn't be reached... ok, who cares? */
269 return JS_GLOBAL_NAME
;
274 js_vm_switch_debug_position (JSVirtualMachine
*vm
,
275 unsigned int *linenum_return
)
279 void *program_counter
= vm
->pc
;
280 Compiled
*pc
= vm
->pc
;
282 unsigned int linenum
= 0;
284 /* Check the globals. */
285 for (i
= 0; i
< vm
->num_globals
; i
++)
286 if (vm
->globals
[i
].type
== JS_FUNC
)
288 f
= (Function
*) vm
->globals
[i
].u
.vfunction
->implementation
;
289 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
294 if (f
->debug
.file
== NULL
)
295 /* No debugging information available for this function. */
298 /* Find the correct pc position. */
299 for (i
= 0; i
< f
->debug
.num_info
; i
++)
301 if (f
->debug
.info
[i
].pc
> program_counter
)
304 linenum
= f
->debug
.info
[i
].linenum
;
307 *linenum_return
= linenum
;
308 return f
->debug
.file
;
312 /* No luck. Let's try the stack. */
313 for (sp
++; sp
< vm
->stack
+ vm
->stack_size
; sp
++)
314 if (sp
->type
== JS_FUNC
)
316 f
= (Function
*) sp
->u
.vfunction
->implementation
;
317 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
322 /* Couldn't find the function we are executing. */
332 function_destroy (void *ptr
)
340 js_free (f
->debug
.file
);
342 js_free (f
->debug
.info
);
347 link_code (JSVirtualMachine
*vm
, unsigned char *code
, unsigned int code_len
,
348 unsigned int consts_offset
, unsigned char *debug_info
,
349 unsigned int debug_info_len
, unsigned int code_offset
)
351 unsigned char *cp
, *end
;
356 unsigned char *fixed_code
;
358 char *debug_filename
= "unknown";
361 /* Terminate the code with op `done'. */
362 fixed_code
= js_malloc (vm
, code_len
+ 1);
363 memcpy (fixed_code
, code
, code_len
);
364 fixed_code
[code_len
] = 1; /* op `done' */
367 end
= fixed_code
+ code_len
+ 1;
369 /* Alloc function closure. */
370 f
= js_vm_alloc_destroyable (vm
, sizeof (*f
));
371 f
->destroy
= function_destroy
;
373 /* Allocate space for our compiled code. <length> is enought. */
374 f
->code
= js_malloc (vm
, (code_len
+ 1) * sizeof (Compiled
));
375 reloc
= js_calloc (vm
, code_len
+ 1, sizeof (Compiled
*));
377 /* Link phase 1: constants and symbols. */
383 /* include c1switch.h */
384 #include "c1switch.h"
385 /* end include c1switch.h */
390 /* Link phase 2: relative jumps. */
397 /* include c2switch.h */
398 #include "c2switch.h"
399 /* end include c2switch.h */
402 /* Handle debug info. */
405 unsigned int di_start
= code_offset
;
406 unsigned int di_end
= code_offset
+ code_len
;
409 for (; debug_info_len
> 0;)
417 JS_BC_READ_INT32 (debug_info
, ui
);
421 f
->debug
.file
= js_malloc (vm
, ui
+ 1);
422 memcpy (f
->debug
.file
, debug_info
, ui
);
423 f
->debug
.file
[ui
] = '\0';
425 debug_filename
= f
->debug
.file
;
428 debug_info_len
-= ui
;
431 case JS_DI_LINENUMBER
:
432 JS_BC_READ_INT32 (debug_info
+ 1, ui
);
434 goto debug_info_done
;
436 /* This belongs to us (maybe). */
440 JS_BC_READ_INT32 (debug_info
, ln
);
444 if (di_start
<= ui
&& ui
<= di_end
)
447 f
->debug
.info
= js_realloc (vm
, f
->debug
.info
,
448 (f
->debug
.num_info
+ 1)
449 * sizeof (DebugInfo
));
451 f
->debug
.info
[f
->debug
.num_info
].pc
= reloc
[ui
];
452 f
->debug
.info
[f
->debug
.num_info
].linenum
= ln
;
459 "VM: unknown debug information type %d%s",
460 *debug_info
, JS_HOST_LINE_BREAK
);
462 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
463 js_iostream_flush (vm
->s_stderr
);
471 if (f
->debug
.file
== NULL
)
472 f
->debug
.file
= js_strdup (vm
, debug_filename
);
476 js_free (fixed_code
);
483 * Execute byte code by using the `switch' dispatch technique.
487 execute_code (JSVirtualMachine
*vm
, JSNode
*object
, Function
*f
,
488 unsigned int argc
, JSNode
*argv
)
493 JSNode builtin_result
;
499 /* Create the initial stack frame by hand. */
502 /* Protect the function from gc. */
503 JS_SP0
->type
= JS_FUNC
;
504 JS_SP0
->u
.vfunction
= js_vm_make_function (vm
, f
);
507 /* Push arguments to the stack. */
509 for (i
--; i
>= 0; i
--)
511 JS_COPY (JS_SP0
, &argv
[i
]);
517 JS_COPY (JS_SP0
, object
);
519 JS_SP0
->type
= JS_NULL
;
522 /* Init fp and pc so our SUBROUTINE_CALL will work. */
526 JS_SUBROUTINE_CALL (f
);
528 /* Ok, now we are ready to run. */
532 switch ((pc
++)->u
.op
)
534 /* include eswitch.h */
536 /* end include eswitch.h */
539 sprintf (buf
, "execute_code: unknown opcode %d%s",
540 (pc
- 1)->u
.op
, JS_HOST_LINE_BREAK
);
541 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
542 js_iostream_flush (vm
->s_stderr
);
553 JS_COPY (&vm
->exec_result
, JS_SP1
);