📄 vm.c
字号:
JS_BC_READ_INT32 (cp + ui, se->offset);
ui += 4;
}
break;
}
/* Check if we have debugging information. */
debug_info = NULL;
debug_info_len = 0;
for (sect = 0; sect < bc->num_sects; sect++)
if (bc->sects[sect].type == JS_BCST_DEBUG)
{
debug_info = bc->sects[sect].data;
debug_info_len = bc->sects[sect].length;
}
/* Clear error message and old exec result. */
vm->error[0] = '\0';
vm->exec_result.type = JS_UNDEFINED;
PROFILING_ON ();
/* Execute. */
result = (*vm->dispatch_execute) (vm, bc, symtab, num_symtab_entries,
consts_offset,
anonymous_function_offset,
debug_info, debug_info_len,
NULL, NULL, 0, NULL);
}
PROFILING_OFF ();
if (symtab)
{
for (ui = 0; ui < num_symtab_entries; ui++)
js_free (symtab[ui].name);
js_free (symtab);
}
/* Pop all error handler frames from the handler chain. */
for (; vm->error_handler != saved_handler; vm->error_handler = handler)
{
handler = vm->error_handler->next;
js_free (vm->error_handler);
}
/* Restore virtual machine's idea about the stack top. */
vm->sp = saved_sp;
return result;
}
int
js_vm_apply (JSVirtualMachine *vm, char *func_name, JSNode *func,
unsigned int argc, JSNode *argv)
{
int result = 1;
JSNode *saved_sp;
JSErrorHandlerFrame *handler, *saved_handler;
/* Initialize error handler. */
saved_sp = vm->sp;
saved_handler = vm->error_handler;
handler = js_calloc (NULL, 1, sizeof (*handler));
if (handler == NULL)
{
sprintf (vm->error, "VM: out of memory");
return 0;
}
handler->next = vm->error_handler;
vm->error_handler = handler;
if (setjmp (vm->error_handler->error_jmp))
{
/* An error occurred. */
result = 0;
}
else
{
/* Clear error message and old exec result. */
vm->error[0] = '\0';
vm->exec_result.type = JS_UNDEFINED;
if (func_name)
/* Lookup the function. */
func = &vm->globals[js_vm_intern (vm, func_name)];
/* Check what kind of function should be called. */
if (func->type == JS_FUNC)
{
PROFILING_ON ();
/* Call function. */
result = (*vm->dispatch_execute) (vm, NULL, NULL, 0, 0, 0,
NULL, 0,
NULL, func, argc, argv);
}
else if (func->type == JS_BUILTIN
&& func->u.vbuiltin->info->global_method_proc != NULL)
{
(*func->u.vbuiltin->info->global_method_proc) (
vm,
func->u.vbuiltin->info,
func->u.vbuiltin->instance_context,
&vm->exec_result,
argv);
}
else
{
if (func_name)
sprintf (vm->error, "undefined function `%s' in apply",
func_name);
else
sprintf (vm->error, "undefiend function in apply");
result = 0;
}
}
PROFILING_OFF ();
/* Pop all error handler frames from the handler chain. */
for (; vm->error_handler != saved_handler; vm->error_handler = handler)
{
handler = vm->error_handler->next;
js_free (vm->error_handler);
}
/* Restore virtual machine's idea about the stack top. */
vm->sp = saved_sp;
return result;
}
int
js_vm_call_method (JSVirtualMachine *vm, JSNode *object,
const char *method_name, unsigned int argc, JSNode *argv)
{
int result = 1;
JSNode *saved_sp;
JSErrorHandlerFrame *handler, *saved_handler;
JSSymbol symbol;
/* Initialize error handler. */
saved_sp = vm->sp;
saved_handler = vm->error_handler;
handler = js_calloc (NULL, 1, sizeof (*handler));
if (handler == NULL)
{
sprintf (vm->error, "VM: out of memory");
return 0;
}
handler->next = vm->error_handler;
vm->error_handler = handler;
if (setjmp (vm->error_handler->error_jmp))
{
/* An error occurred. */
result = 0;
}
else
{
/* Intern the method name. */
symbol = js_vm_intern (vm, method_name);
/* Clear error message and old exec result. */
vm->error[0] = '\0';
vm->exec_result.type = JS_UNDEFINED;
/* What kind of object was called? */
if (object->type == JS_BUILTIN)
{
if (object->u.vbuiltin->info->method_proc)
{
if ((*object->u.vbuiltin->info->method_proc) (
vm,
object->u.vbuiltin->info,
object->u.vbuiltin->instance_context,
symbol,
&vm->exec_result, argv)
== JS_PROPERTY_UNKNOWN)
{
sprintf (vm->error, "call_method: unknown method");
result = 0;
}
}
else
{
sprintf (vm->error, "illegal builtin object for call_method");
result = 0;
}
}
else if (object->type == JS_OBJECT)
{
JSNode method;
/* Fetch the method's implementation. */
if (js_vm_object_load_property (vm, object->u.vobject, symbol,
&method)
== JS_PROPERTY_FOUND)
{
/* The property has been defined in the object. */
if (method.type != JS_FUNC)
{
sprintf (vm->error, "call_method: unknown method");
result = 0;
}
else
{
PROFILING_ON ();
result = (*vm->dispatch_execute) (vm, NULL, NULL, 0, 0, 0,
NULL, 0,
object, &method, argc,
argv);
}
}
else
/* Let the built-in Object handle this. */
goto to_builtin_please;
}
else if (vm->prim[object->type])
{
/* The primitive language types. */
to_builtin_please:
if ((*vm->prim[object->type]->method_proc) (vm,
vm->prim[object->type],
object, symbol,
&vm->exec_result,
argv)
== JS_PROPERTY_UNKNOWN)
{
sprintf (vm->error, "call_method: unknown method");
result = 0;
}
}
else
{
sprintf (vm->error, "illegal object for call_method");
result = 0;
}
}
PROFILING_OFF ();
/* Pop all error handler frames from the handler chain. */
for (; vm->error_handler != saved_handler; vm->error_handler = handler)
{
handler = vm->error_handler->next;
js_free (vm->error_handler);
}
/* Restore virtual machine's idea about the stack top. */
vm->sp = saved_sp;
return result;
}
const char *
js_vm_func_name (JSVirtualMachine *vm, void *pc)
{
return (*vm->dispatch_func_name) (vm, pc);
}
const char *
js_vm_debug_position (JSVirtualMachine *vm, unsigned int *linenum_return)
{
return (*vm->dispatch_debug_position) (vm, linenum_return);
}
unsigned int
js_vm_intern_with_len (JSVirtualMachine *vm, const char *name,
unsigned int len)
{
JSHashBucket *b;
unsigned int pos = js_count_hash (name, len) % JS_HASH_TABLE_SIZE;
for (b = vm->globals_hash[pos]; b; b = b->next)
if (strcmp (b->name, name) == 0)
return b->u.ui;
b = js_malloc (vm, sizeof (*b));
b->name = js_strdup (vm, name);
b->next = vm->globals_hash[pos];
vm->globals_hash[pos] = b;
/* Alloc space from the globals array. */
if (vm->num_globals >= vm->globals_alloc)
{
vm->globals = js_realloc (vm, vm->globals,
(vm->globals_alloc + 1024) * sizeof (JSNode));
vm->globals_alloc += 1024;
}
/* Initialize symbol's name spaces. */
vm->globals[vm->num_globals].type = JS_UNDEFINED;
b->u.ui = vm->num_globals++;
return b->u.ui;
}
const char *
js_vm_symname (JSVirtualMachine *vm, JSSymbol sym)
{
int i;
JSHashBucket *b;
for (i = 0; i < JS_HASH_TABLE_SIZE; i++)
for (b = vm->globals_hash[i]; b; b = b->next)
if (b->u.ui == sym)
return b->name;
return "???";
}
void
js_vm_error (JSVirtualMachine *vm)
{
const char *file;
unsigned int ln;
char error[1024];
file = js_vm_debug_position (vm, &ln);
if (file)
{
sprintf (error, "%s:%u: %s", file, ln, vm->error);
strcpy (vm->error, error);
}
if (vm->stacktrace_on_error)
{
sprintf (error, "VM: error: %s%s", vm->error,
JS_HOST_LINE_BREAK);
js_iostream_write (vm->s_stderr, error, strlen (error));
js_vm_stacktrace (vm, (unsigned int) -1);
}
if (vm->error_handler->sp)
/*
* We are jumping to a catch-block. Format our error message to
* the `thrown' node.
*/
js_vm_make_string (vm, &vm->error_handler->thrown,
vm->error, strlen (vm->error));
longjmp (vm->error_handler->error_jmp, 1);
/* NOTREACHED (I hope). */
sprintf (error, "VM: no valid error handler initialized%s",
JS_HOST_LINE_BREAK);
js_iostream_write (vm->s_stderr, error, strlen (error));
js_iostream_flush (vm->s_stderr);
abort ();
}
/* Delete proc for garbaged built-in objects. */
static void
destroy_builtin (void *ptr)
{
JSBuiltin *bi = ptr;
if (bi->info->delete_proc)
(*bi->info->delete_proc) (bi->info, bi->instance_context);
}
/* Delete proc for garbaged built-in info. */
static void
destroy_builtin_info (void *ptr)
{
JSBuiltinInfo *i = ptr;
if (i->obj_context_delete)
(*i->obj_context_delete) (i->obj_context);
}
JSBuiltinInfo *
js_vm_builtin_info_create (JSVirtualMachine *vm)
{
JSNode prototype;
JSBuiltinInfo *i = js_vm_alloc_destroyable (vm, sizeof (*i));
i->destroy = destroy_builtin_info;
i->prototype = js_vm_object_new (vm);
/*
* Set the __proto__ property to null. We have no prototype object
* above us.
*/
prototype.type = JS_NULL;
js_vm_object_store_property (vm, i->prototype, vm->syms.s___proto__,
&prototype);
return i;
}
void
js_vm_builtin_create (JSVirtualMachine *vm, JSNode *result,
JSBuiltinInfo *info, void *instance_context)
{
result->type = JS_BUILTIN;
result->u.vbuiltin = js_vm_alloc_destroyable (vm, sizeof (JSBuiltin));
result->u.vbuiltin->destroy = destroy_builtin;
result->u.vbuiltin->info = info;
if (instance_context)
{
JSNode prototype;
result->u.vbuiltin->instance_context = instance_context;
result->u.vbuiltin->prototype = js_vm_object_new (vm);
/* Set the __proto__ chain. */
prototype.type = JS_OBJECT;
prototype.u.vobject = info->prototype;
js_vm_object_store_property (vm, result->u.vbuiltin->prototype,
vm->syms.s___proto__, &prototype);
}
}
/*
* Static functions.
*/
extern void js_builtin_core (JSVirtualMachine *vm);
extern void js_builtin_Array (JSVirtualMachine *vm);
extern void js_builtin_Boolean (JSVirtualMachine *vm);
extern void js_builtin_Function (JSVirtualMachine *vm);
extern void js_builtin_Number (JSVirtualMachine *vm);
extern void js_builtin_Object (JSVirtualMachine *vm);
extern void js_builtin_String (JSVirtualMachine *vm);
extern void js_builtin_File (JSVirtualMachine *vm);
extern void js_builtin_System (PKJS kjs);
extern void js_builtin_RegExp (JSVirtualMachine *vm);
extern void js_builtin_VM (JSVirtualMachine *vm);
static void
intern_builtins (PKJS kjs)
{
JSVirtualMachine *vm = kjs->vm;
/*
* The initialization order is significant. The RegExp object must be
* initialized before String.
*/
/* The core global methods. */
js_builtin_core (vm);
js_builtin_RegExp (vm);
js_builtin_VM (vm);
/* Language objects. */
js_builtin_Array (vm);
js_builtin_Boolean (vm);
js_builtin_Function (vm);
js_builtin_String (vm);
js_builtin_Number (vm);
js_builtin_Object (vm);
js_builtin_File (vm);
js_builtin_System (kjs);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -