2 * Optimized `jumps' 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/vmjumps.c,v $
32 #if __GNUC__ && !DISABLE_JUMPS
35 * Types and definitions.
39 reloc[cp - code_start - 1] = &f->code[cpos]; \
40 f->code[cpos++].u.ptr = (a)
42 #define SAVE_INT8(a) f->code[cpos++].u.i8 = (a)
43 #define SAVE_INT16(a) f->code[cpos++].u.i16 = (a)
44 #define SAVE_INT32(a) f->code[cpos++].u.i32 = (a)
46 #define ARG_INT32() f->code[cpos].u.i32
52 if (++vm->hook_operand_count >= vm->hook_operand_count_trigger) \
54 JS_CALL_HOOK (JS_VM_EVENT_OPERAND_COUNT); \
55 vm->hook_operand_count = 0; \
57 goto *((pc++)->u.ptr); \
60 #else /* not BC_OPERAND_HOOKS */
62 #define NEXT() goto *((pc++)->u.ptr)
64 #endif /* not BC_OPERAND_HOOKS */
66 #define READ_INT8(var) (var) = (pc++)->u.i8
67 #define READ_INT16(var) (var) = (pc++)->u.i16
68 #define READ_INT32(var) (var) = (pc++)->u.i32
70 #define SETPC(ofs) pc = (ofs)
71 #define SETPC_RELATIVE(ofs) pc += (ofs)
73 #define CALL_USER_FUNC(f) pc = ((Function *) (f))->code
75 #define DONE() goto done
80 strcpy (vm->error, (msg)); \
86 #define OPERAND(op) vm->prof_op = (op)
102 typedef struct compiled_st Compiled
;
104 /* Debug information. */
108 unsigned int linenum
;
111 typedef struct debug_info_st DebugInfo
;
115 JSHeapDestroyableCB destroy
;
124 unsigned int num_info
;
129 typedef struct function_st Function
;
136 function_destroy (void *ptr
)
149 js_free (f
->debug
.file
);
151 js_free (f
->debug
.info
);
155 #endif /* not (__GNUC__ && !DISABLE_JUMPS) */
162 js_vm_jumps_exec (JSVirtualMachine
*vm
, JSByteCode
*bc
, JSSymtabEntry
*symtab
,
163 unsigned int num_symtab_entries
, unsigned int consts_offset
,
164 unsigned int anonymous_function_offset
,
165 unsigned char *debug_info
, unsigned int debug_info_len
,
166 JSNode
*object
, JSNode
*func
,
167 unsigned int argc
, JSNode
*argv
)
169 #if __GNUC__ && !DISABLE_JUMPS
172 Function
*global_f
= NULL
;
174 unsigned char *code
= NULL
;
178 char *debug_filename
= "unknown";
180 unsigned int opcount
= 0;
184 /* Executing byte-code. */
186 /* Find the code section. */
187 for (s
= 0; s
< bc
->num_sects
; s
++)
188 if (bc
->sects
[s
].type
== JS_BCST_CODE
)
189 code
= bc
->sects
[s
].data
;
190 assert (code
!= NULL
);
192 /* Enter all functions to the known functions of the VM. */
193 for (s
= 0; s
< num_symtab_entries
; s
++)
195 /* We need one function. */
196 f
= js_vm_alloc_destroyable (vm
, sizeof (*f
));
197 f
->destroy
= function_destroy
;
198 f
->name
= js_strdup (vm
, symtab
[s
].name
);
200 if (strcmp (symtab
[s
].name
, JS_GLOBAL_NAME
) == 0)
204 int is_anonymous
= 0;
206 /* Check for the anonymous function. */
207 if (symtab
[s
].name
[0] == '.' && symtab
[s
].name
[1] == 'F'
208 && symtab
[s
].name
[2] == ':')
213 sprintf (buf
, "VM: link: %s(): start=%d, length=%d",
214 symtab
[s
].name
, symtab
[s
].offset
,
215 symtab
[s
+ 1].offset
- symtab
[s
].offset
);
217 sprintf (buf
+ strlen (buf
),
218 ", relocating with offset %u",
219 anonymous_function_offset
);
220 strcat (buf
, JS_HOST_LINE_BREAK
);
221 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
226 sprintf (buf
, ".F:%u",
227 (unsigned int) atoi (symtab
[s
].name
+ 3)
228 + anonymous_function_offset
);
229 ui
= js_vm_intern (vm
, buf
);
232 ui
= js_vm_intern (vm
, symtab
[s
].name
);
234 vm
->globals
[ui
].type
= JS_FUNC
;
235 vm
->globals
[ui
].u
.vfunction
= js_vm_make_function (vm
, f
);
238 /* Link the code to our environment.*/
241 unsigned char *code_start
, *code_end
;
242 unsigned char *fixed_code
;
248 length
= symtab
[s
+ 1].offset
- symtab
[s
].offset
+ 1;
251 * Allocate space for our compiled code. <length> is enought,
252 * but is is almost always too much. Who cares?
254 f
->code
= js_malloc (vm
, length
* sizeof (Compiled
));
255 reloc
= js_calloc (vm
, 1, length
* sizeof (Compiled
*));
256 fixed_code
= js_malloc (vm
, length
);
258 memcpy (fixed_code
, code
+ symtab
[s
].offset
, length
);
259 fixed_code
[length
- 1] = 1; /* op `done'. */
261 code_start
= fixed_code
;
262 code_end
= code_start
+ length
;
264 /* Link phase 1: constants and symbols. */
267 while (cp
< code_end
)
271 /* include c1jumps.h */
273 /* end include c1jumps.h */
278 /* Link phase 2: relative jumps. */
281 while (cp
< code_end
)
285 /* include c2jumps.h */
287 /* end include c2jumps.h */
291 /* Handle debug info. */
294 unsigned int di_start
= symtab
[s
].offset
;
295 unsigned int di_end
= symtab
[s
+ 1].offset
;
298 for (; debug_info_len
> 0;)
306 JS_BC_READ_INT32 (debug_info
, ui
);
310 f
->debug
.file
= js_malloc (vm
, ui
+ 1);
311 memcpy (f
->debug
.file
, debug_info
, ui
);
312 f
->debug
.file
[ui
] = '\0';
314 debug_filename
= f
->debug
.file
;
317 debug_info_len
-= ui
;
320 case JS_DI_LINENUMBER
:
321 JS_BC_READ_INT32 (debug_info
+ 1, ui
);
323 goto debug_info_done
;
325 /* This belongs to us (maybe). */
329 JS_BC_READ_INT32 (debug_info
, ln
);
333 if (di_start
<= ui
&& ui
<= di_end
)
336 f
->debug
.info
= js_realloc (vm
, f
->debug
.info
,
337 (f
->debug
.num_info
+ 1)
338 * sizeof (DebugInfo
));
340 f
->debug
.info
[f
->debug
.num_info
].pc
= reloc
[ui
];
341 f
->debug
.info
[f
->debug
.num_info
].linenum
= ln
;
348 "VM: unknown debug information type %d%s",
349 *debug_info
, JS_HOST_LINE_BREAK
);
350 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
351 js_iostream_flush (vm
->s_stderr
);
359 if (f
->debug
.file
== NULL
)
360 f
->debug
.file
= js_strdup (vm
, debug_filename
);
364 js_free (fixed_code
);
372 /* Applying arguments to function. */
373 if (func
->type
!= JS_FUNC
)
375 sprintf (vm
->error
, "illegal function in apply");
381 sprintf (buf
, "VM: calling function%s",
383 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
385 f
= func
->u
.vfunction
->implementation
;
391 * Save the applied function to the stack. If our script
392 * overwrites the function, the function will not be deleted
393 * under us, since it is protected from the gc in the stack.
395 JS_COPY (JS_SP0
, func
);
398 /* Push arguments to the stack. */
399 for (i
= argc
- 1; i
>= 0; i
--)
401 JS_COPY (JS_SP0
, &argv
[i
]);
407 JS_COPY (JS_SP0
, object
);
409 JS_SP0
->type
= JS_NULL
;
412 /* Init fp and pc so our SUBROUTINE_CALL will work. */
416 JS_SUBROUTINE_CALL (f
);
426 sprintf (buf
, "VM: exec: %s%s", JS_GLOBAL_NAME
,
428 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
431 /* Create the initial stack frame by hand. */
435 * Push the global function to the stack. There it is protected
436 * from the garbage collection, as long, as we are executing the
437 * global code. It is also removed automatically, when the
440 JS_SP0
->type
= JS_FUNC
;
441 JS_SP0
->u
.vfunction
= js_vm_make_function (vm
, global_f
);
444 /* Empty this pointer. */
445 JS_SP0
->type
= JS_NULL
;
448 /* Init fp and pc so our JS_SUBROUTINE_CALL macro works. */
452 JS_SUBROUTINE_CALL (global_f
);
458 /* The smart done label. */
463 * The return value from function calls and global evals is at JS_SP1.
464 * If <sp> is NULL, then we were linking byte-code that didn't have
468 JS_COPY (&vm
->exec_result
, JS_SP1
);
470 vm
->exec_result
.type
= JS_UNDEFINED
;
475 /* And finally, include the operands. */
477 JSNode builtin_result
;
482 /* include ejumps.h */
484 /* end include ejumps.h */
486 #else /* not (__GNUC__ && !DISABLE_JUMPS) */
488 #endif /* not (__GNUC__ && !DISABLE_JUMPS) */
493 js_vm_jumps_func_name (JSVirtualMachine
*vm
, void *program_counter
)
495 #if __GNUC__ && !DISABLE_JUMPS
498 Compiled
*pc
= program_counter
;
501 /* Check the globals. */
502 for (i
= 0; i
< vm
->num_globals
; i
++)
503 if (vm
->globals
[i
].type
== JS_FUNC
)
505 f
= (Function
*) vm
->globals
[i
].u
.vfunction
->implementation
;
506 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
510 /* No luck. Let's try the stack. */
511 for (sp
++; sp
< vm
->stack
+ vm
->stack_size
; sp
++)
512 if (sp
->type
== JS_FUNC
)
514 f
= (Function
*) sp
->u
.vfunction
->implementation
;
515 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
519 /* Still no matches. This shouldn't be reached... ok, who cares? */
520 return JS_GLOBAL_NAME
;
522 #else /* not (__GNUC__ && !DISABLE_JUMPS) */
524 #endif /* not (__GNUC__ && !DISABLE_JUMPS) */
529 js_vm_jumps_debug_position (JSVirtualMachine
*vm
, unsigned int *linenum_return
)
531 #if __GNUC__ && !DISABLE_JUMPS
534 void *program_counter
= vm
->pc
;
535 Compiled
*pc
= vm
->pc
;
537 unsigned int linenum
= 0;
539 /* Check the globals. */
540 for (i
= 0; i
< vm
->num_globals
; i
++)
541 if (vm
->globals
[i
].type
== JS_FUNC
)
543 f
= (Function
*) vm
->globals
[i
].u
.vfunction
->implementation
;
544 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
549 if (f
->debug
.file
== NULL
)
550 /* No debugging information available for this function. */
553 /* Find the correct pc position. */
554 for (i
= 0; i
< f
->debug
.num_info
; i
++)
556 if (f
->debug
.info
[i
].pc
> program_counter
)
559 linenum
= f
->debug
.info
[i
].linenum
;
562 *linenum_return
= linenum
;
563 return f
->debug
.file
;
567 /* No luck. Let's try the stack. */
568 for (sp
++; sp
< vm
->stack
+ vm
->stack_size
; sp
++)
569 if (sp
->type
== JS_FUNC
)
571 f
= (Function
*) sp
->u
.vfunction
->implementation
;
572 if (f
->code
< pc
&& pc
< f
->code
+ f
->length
)
577 /* Couldn't find the function we are executing. */
580 #else /* not (__GNUC__ && !DISABLE_JUMPS) */
582 #endif /* not (__GNUC__ && !DISABLE_JUMPS) */