static int sort_js_cmp_func (const void *aptr, const void *bptr, void *context) { ArraySortCtx *ctx = context; const JSNode *a = aptr; const JSNode *b = bptr; /* * Finalize the argument array. The argumnet count has already been set. * when the context were initialized. */ JS_COPY (&ctx->argv[1], a); JS_COPY (&ctx->argv[2], b); /* Call the function. */ if (!js_vm_apply (ctx->vm, NULL, ctx->func, 3, ctx->argv)) /* Raise an error. */ js_vm_error (ctx->vm); /* Fetch the return value. */ if (ctx->vm->exec_result.type != JS_INTEGER) { sprintf (ctx->vm->error, "Array.sort(): comparison function didn't return integer"); js_vm_error (ctx->vm); } return ctx->vm->exec_result.u.vinteger; }
void js_vm_object_load_array (JSVirtualMachine *vm, JSObject *obj, JSNode *sel, JSNode *value_return) { if (sel->type == JS_INTEGER) { if (sel->u.vinteger < 0 || sel->u.vinteger >= obj->num_props) value_return->type = JS_UNDEFINED; else JS_COPY (value_return, &obj->props[sel->u.vinteger].value); } else if (sel->type == JS_STRING) { int pos; if (obj->hash == NULL) hash_create (vm, obj); pos = hash_lookup (obj, (char *) sel->u.vstring->data, sel->u.vstring->len); if (pos < 0) value_return->type = JS_UNDEFINED; else JS_COPY (value_return, &obj->props[pos].value); } else { sprintf (vm->error, "load_property: illegal array index"); js_vm_error (vm); } }
static void eval_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { JSInterpPtr interp = instance_context; if (args->u.vinteger != 1) { sprintf (vm->error, "eval: illegal amount of arguments"); js_vm_error (vm); } if (args[1].type != JS_STRING) { sprintf (vm->error, "eval: illegal argument"); js_vm_error (vm); } /* * Ok, we'r ready to eval it. The source strings is our argument, so, * it is in the stack and therefore, protected for gc. */ if (!js_eval_source (interp, &args[1], "JSC$compile_string")) { /* The evaluation failed. */ fprintf (stderr, "eval: evaluation failed: %s\n", vm->error); result_return->type = JS_UNDEFINED; } else /* Pass the return value to our caller. */ JS_COPY (result_return, &vm->exec_result); }
int js_vm_object_load_property (JSVirtualMachine *vm, JSObject *obj, JSSymbol prop, JSNode *value_return) { unsigned int ui; JSSymbol link_sym = vm->syms.s___proto__; JSObject *link_obj = NULL; follow_link: /* Check if we know this property. */ for (ui = 0; ui < obj->num_props; ui++) if (obj->props[ui].name == prop) { JS_COPY (value_return, &obj->props[ui].value); return JS_PROPERTY_FOUND; } else if (obj->props[ui].name == link_sym && obj->props[ui].value.type == JS_OBJECT) link_obj = obj->props[ui].value.u.vobject; /* Undefined so far. */ if (link_obj) { /* Follow the link. */ obj = link_obj; link_obj = NULL; goto follow_link; } /* Undefined. Make it undef. */ value_return->type = JS_UNDEFINED; return JS_PROPERTY_UNKNOWN; }
void js_vm_object_store_property (JSVirtualMachine *vm, JSObject *obj, JSSymbol prop, JSNode *val) { unsigned int ui; JSSymbol free_slot = JS_SYMBOL_NULL; /* Check if we already know this property. */ for (ui = 0; ui < obj->num_props; ui++) if (obj->props[ui].name == prop) { JS_COPY (&obj->props[ui].value, val); return; } else if (obj->props[ui].name == JS_SYMBOL_NULL) free_slot = ui; /* Must create a new property. */ if (free_slot == JS_SYMBOL_NULL) { /* Expand our array of properties. */ obj->props = js_vm_realloc (vm, obj->props, (obj->num_props + 1) * sizeof (JSProperty)); free_slot = obj->num_props++; } obj->props[free_slot].name = prop; obj->props[free_slot].attributes = 0; JS_COPY (&obj->props[free_slot].value, val); /* Insert it to the hash (if the hash has been created). */ if (obj->hash) { const char *name; name = js_vm_symname (vm, prop); hash_insert (vm, obj, name, strlen (name), free_slot); } }
/* New proc. */ static void new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args, JSNode *result_return) { int i; if (args->u.vinteger == 1 && args[1].type == JS_INTEGER) { /* Create a fixed length array. */ js_vm_make_array (vm, result_return, args[1].u.vinteger); } else { js_vm_make_array (vm, result_return, args->u.vinteger); for (i = 0; i < args->u.vinteger; i++) JS_COPY (&result_return->u.varray->data[i], &args[i + 1]); } }
static void execute_code (JSVirtualMachine *vm, JSNode *object, Function *f, unsigned int argc, JSNode *argv) { JSNode *sp; JSNode *fp; JSNode *function; JSNode builtin_result; unsigned char *pc; JSInt32 i, j; JSInt8 i8; char buf[512]; /* Create the initial stack frame by hand. */ sp = vm->sp; /* Protect the function from gc. */ JS_SP0->type = JS_FUNC; JS_SP0->u.vfunction = js_vm_make_function (vm, f); JS_PUSH (); /* Push arguments to the stack. */ i = argc; for (i--; i >= 0; i--) { JS_COPY (JS_SP0, &argv[i]); JS_PUSH (); } /* This pointer. */ if (object) JS_COPY (JS_SP0, object); else JS_SP0->type = JS_NULL; JS_PUSH (); /* Init fp and pc so our SUBROUTINE_CALL will work. */ fp = NULL; pc = NULL; JS_SUBROUTINE_CALL (f); /* Ok, now we are ready to run. */ while (1) { switch (*pc++) { /* include eswt0.h */ #include "eswt0.h" /* end include eswt0.h */ default: sprintf_P (buf, vmswt0_string_5, *(pc - 1), JS_HOST_LINE_BREAK); //js_iostream_write (vm->s_stderr, buf, strlen (buf)); //js_iostream_flush (vm->s_stderr); abort (); break; } } done: /* All done. */ JS_COPY (&vm->exec_result, JS_SP1); }
/* * Static functions. */ static int js_eval_source (JSInterpPtr interp, JSNode *source, char *compiler_function) { JSNode argv[5]; int i = 0; int result; JSByteCode *bc; /* Let's compile the code. */ /* Argument count. */ argv[i].type = JS_INTEGER; argv[i].u.vinteger = 4; i++; /* Source to compiler. */ JS_COPY (&argv[i], source); i++; /* Flags. */ argv[i].type = JS_INTEGER; argv[i].u.vinteger = 0; if (interp->options.verbose) argv[i].u.vinteger = JSC_FLAG_VERBOSE; argv[i].u.vinteger |= JSC_FLAG_GENERATE_DEBUG_INFO; argv[i].u.vinteger |= JSC_FLAG_OPTIMIZE_PEEPHOLE; argv[i].u.vinteger |= JSC_FLAG_OPTIMIZE_JUMPS; argv[i].u.vinteger |= JSC_FLAG_WARN_MASK; i++; /* Assembler file. */ argv[i].type = JS_NULL; i++; /* Byte-code file. */ argv[i].type = JS_NULL; i++; /* Call the compiler entry point. */ result = js_vm_apply (interp->vm, compiler_function, NULL, i, argv); if (result == 0) return 0; /* * The resulting byte-code file is now at vm->exec_result. * * Note! The byte-code is a string allocated form the vm heap. * The garbage collector can free it when it wants since the result * isn't protected. However, we have no risk here because we * first convert the byte-code data block to our internal * JSByteCode block that shares no memory with the original data. */ assert (interp->vm->exec_result.type == JS_STRING); bc = js_bc_read_data (interp->vm->exec_result.u.vstring->data, interp->vm->exec_result.u.vstring->len); /* And finally, execute it. */ result = js_vm_execute (interp->vm, bc); /* Free the byte-code. */ js_bc_free (bc); return result; }
void js_get_var (JSInterpPtr interp, char *name, JSType *value) { JSNode *n = &interp->vm->globals[js_vm_intern (interp->vm, name)]; JS_COPY ((JSNode *) value, n); }
static void execute_code (JSVirtualMachine *vm, Function *f, unsigned int argc, JSNode *argv) { JSNode *sp; JSNode *fp; JSNode *function; JSNode builtin_result; Compiled *pc; JSInt32 i, j; JSInt8 i8; /* Create the initial stack frame by hand. */ sp = vm->sp; /* Protect the function from gc. */ JS_SP0->type = JS_FUNC; JS_SP0->u.vfunction = js_vm_make_function (vm, f); JS_PUSH (); /* Push arguments to the stack. */ i = argc; for (i--; i >= 0; i--) { JS_COPY (JS_SP0, &argv[i]); JS_PUSH (); } /* Empty this pointer. */ JS_SP0->type = JS_NULL; JS_PUSH (); /* Init fp and pc so our SUBROUTINE_CALL will work. */ fp = NULL; pc = NULL; JS_SUBROUTINE_CALL (f); /* Ok, now we are ready to run. */ while (1) { switch ((pc++)->u.op) { /* include eswitch.h */ #include "eswitch.h" /* end include eswitch.h */ default: fprintf (stderr, "execute_code: unknown opcode %d\n", (pc - 1)->u.op); exit (1); break; } } done: /* All done. */ JS_COPY (&vm->exec_result, JS_SP1); }
/* Method proc. */ static int method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol method, JSNode *result_return, JSNode *args) { ArrayCtx *ctx = builtin_info->obj_context; JSNode *n = instance_context; int i; /* Set the default result type. */ result_return->type = JS_UNDEFINED; if (method == ctx->s_concat) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_ARRAY) goto argument_type_error; js_vm_make_array (vm, result_return, n->u.varray->length + args[1].u.varray->length); memcpy (result_return->u.varray->data, n->u.varray->data, n->u.varray->length * sizeof (JSNode)); memcpy (&result_return->u.varray->data[n->u.varray->length], args[1].u.varray->data, args[1].u.varray->length * sizeof (JSNode)); } /* ********************************************************************** */ else if (method == ctx->s_join || method == vm->syms.s_toString) { char *glue = NULL; if (method == vm->syms.s_toString) { if (args->u.vinteger != 0) goto argument_error; } else { if (args->u.vinteger == 0) ; else if (args->u.vinteger == 1) { JSNode glue_result; js_vm_to_string (vm, &args[1], &glue_result); glue = js_string_to_c_string (vm, &glue_result); } else goto argument_error; } /* Ok, ready to run. */ if (n->u.varray->length == 0) js_vm_make_static_string (vm, result_return, "", 0); else { int len; int glue_len = glue ? strlen (glue) : 1; /* Estimate the result length. */ len = (n->u.varray->length * 5 + (n->u.varray->length - 1) * glue_len); js_vm_make_string (vm, result_return, NULL, len); result_return->u.vstring->len = 0; /* Do the join. */ for (i = 0; i < n->u.varray->length; i++) { JSNode sitem; int delta; js_vm_to_string (vm, &n->u.varray->data[i], &sitem); delta = sitem.u.vstring->len; if (i + 1 < n->u.varray->length) delta += glue_len; result_return->u.vstring->data = js_vm_realloc (vm, result_return->u.vstring->data, result_return->u.vstring->len + delta); memcpy (result_return->u.vstring->data + result_return->u.vstring->len, sitem.u.vstring->data, sitem.u.vstring->len); result_return->u.vstring->len += sitem.u.vstring->len; if (i + 1 < n->u.varray->length) { if (glue) { memcpy (result_return->u.vstring->data + result_return->u.vstring->len, glue, glue_len); result_return->u.vstring->len += glue_len; } else result_return->u.vstring->data [result_return->u.vstring->len++] = ','; } } } if (glue) js_free (glue); } /* ********************************************************************** */ else if (method == ctx->s_pop) { if (args->u.vinteger != 0) goto argument_error; if (n->u.varray->length == 0) result_return->type = JS_UNDEFINED; else { JS_COPY (result_return, &n->u.varray->data[n->u.varray->length - 1]); n->u.varray->length--; } } /* ********************************************************************** */ else if (method == ctx->s_push) { int old_len; if (args->u.vinteger == 0) goto argument_error; old_len = n->u.varray->length; js_vm_expand_array (vm, n, n->u.varray->length + args->u.vinteger); for (i = 0; i < args->u.vinteger; i++) JS_COPY (&n->u.varray->data[old_len + i], &args[i + 1]); JS_COPY (result_return, &args[i]); } /* ********************************************************************** */ else if (method == ctx->s_reverse) { if (args->u.vinteger != 0) goto argument_error; for (i = 0; i < n->u.varray->length / 2; i++) { JSNode tmp; JS_COPY (&tmp, &n->u.varray->data[i]); JS_COPY (&n->u.varray->data[i], &n->u.varray->data[n->u.varray->length - i - 1]); JS_COPY (&n->u.varray->data[n->u.varray->length - i - 1], &tmp); } } /* ********************************************************************** */ else if (method == ctx->s_shift) { if (args->u.vinteger != 0) goto argument_error; if (n->u.varray->length == 0) result_return->type = JS_UNDEFINED; else { JS_COPY (result_return, &n->u.varray->data[0]); memmove (&n->u.varray->data[0], &n->u.varray->data[1], (n->u.varray->length - 1) * sizeof (JSNode)); n->u.varray->length--; } } /* ********************************************************************** */ else if (method == ctx->s_slice) { int start, end; if (args->u.vinteger < 1 || args->u.vinteger > 2) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; start = args[1].u.vinteger; if (args->u.vinteger == 2) { if (args[2].type != JS_INTEGER) goto argument_type_error; end = args[2].u.vinteger; } else end = n->u.varray->length; if (end < 0) end += n->u.varray->length; if (end < 0) end = start; js_vm_make_array (vm, result_return, end - start); /* Copy items. */ for (i = 0; i < end - start; i++) JS_COPY (&result_return->u.varray->data[i], &n->u.varray->data[start + i]); } /* ********************************************************************** */ else if (method == ctx->s_splice) { unsigned int new_length; unsigned int old_length; int delta; if (args->u.vinteger < 2) goto argument_error; if (args[1].type != JS_INTEGER || args[2].type != JS_INTEGER) goto argument_type_error; if (args[2].u.vinteger == 0 && args->u.vinteger == 2) /* No deletions: must specify at least one item to insert. */ goto argument_error; old_length = new_length = n->u.varray->length; if (args[1].u.vinteger < new_length) { if (args[2].u.vinteger > new_length - args[1].u.vinteger) { args[2].u.vinteger = new_length - args[1].u.vinteger; new_length = args[1].u.vinteger; } else new_length -= args[2].u.vinteger; } else { new_length = args[1].u.vinteger; args[2].u.vinteger = 0; } new_length += args->u.vinteger - 2; if (new_length > n->u.varray->length) js_vm_expand_array (vm, n, new_length); else /* Cut the array. */ n->u.varray->length = new_length; /* Do the stuffs we must do. */ /* Create the result array. */ if (args[2].u.vinteger == 0) result_return->type = JS_UNDEFINED; else { js_vm_make_array (vm, result_return, args[2].u.vinteger); for (i = 0; i < args[2].u.vinteger; i++) JS_COPY (&result_return->u.varray->data[i], &n->u.varray->data[args[1].u.vinteger + i]); } /* Delete and move. */ delta = args->u.vinteger - 2 - args[2].u.vinteger; memmove (&n->u.varray->data[args[1].u.vinteger + args[2].u.vinteger + delta], &n->u.varray->data[args[1].u.vinteger + args[2].u.vinteger], (old_length - (args[1].u.vinteger + args[2].u.vinteger)) * sizeof (JSNode)); /* Insert. */ for (i = 0; i < args->u.vinteger - 2; i++) JS_COPY (&n->u.varray->data[args[1].u.vinteger + i], &args[i + 3]); } /* ********************************************************************** */ else if (method == ctx->s_sort) { MergesortCompFunc func; ArraySortCtx array_sort_ctx; void *func_ctx = NULL; /* Initialized to keep compiler quiet. */ if (args->u.vinteger == 0) { func = sort_default_cmp_func; func_ctx = vm; } else if (args->u.vinteger == 1) { if (args[1].type != JS_FUNC && args[1].type != JS_BUILTIN) goto argument_type_error; func = sort_js_cmp_func; /* Init context. */ array_sort_ctx.vm = vm; array_sort_ctx.func = &args[1]; /* Init the argc part of the argument vector here. */ array_sort_ctx.argv[0].type = JS_INTEGER; array_sort_ctx.argv[0].u.vinteger = 3; func_ctx = &array_sort_ctx; } else goto argument_error; mergesort_r (n->u.varray->data, n->u.varray->length, sizeof (JSNode), func, func_ctx); } /* ********************************************************************** */ else if (method == ctx->s_unshift) { int old_len; if (args->u.vinteger == 0) goto argument_error; old_len = n->u.varray->length; js_vm_expand_array (vm, n, n->u.varray->length + args->u.vinteger); memmove (&n->u.varray->data[args->u.vinteger], n->u.varray->data, old_len * sizeof (JSNode)); for (i = 0; i < args->u.vinteger; i++) JS_COPY (&n->u.varray->data[i], &args[args->u.vinteger - i]); result_return->type = JS_INTEGER; result_return->u.vinteger = n->u.varray->length; } /* ********************************************************************** */ else return JS_PROPERTY_UNKNOWN; return JS_PROPERTY_FOUND; /* * Error handling. */ argument_error: sprintf (vm->error, "Array.%s(): illegal amount of arguments", js_vm_symname (vm, method)); js_vm_error (vm); argument_type_error: sprintf (vm->error, "Array.%s(): illegal argument", js_vm_symname (vm, method)); js_vm_error (vm); /* NOTREACHED */ return 0; }
void js_vm_object_store_array (JSVirtualMachine *vm, JSObject *obj, JSNode *sel, JSNode *value) { if (sel->type == JS_INTEGER) { if (sel->u.vinteger < 0) { sprintf (vm->error, "store_array: array index can't be nagative"); js_vm_error (vm); } if (sel->u.vinteger >= obj->num_props) { /* Expand properties. */ obj->props = js_vm_realloc (vm, obj->props, (sel->u.vinteger + 1) * sizeof (JSProperty)); /* Init the possible gap. */ for (; obj->num_props <= sel->u.vinteger; obj->num_props++) { obj->props[obj->num_props].name = 0; obj->props[obj->num_props].attributes = 0; obj->props[obj->num_props].value.type = JS_UNDEFINED; } } JS_COPY (&obj->props[sel->u.vinteger].value, value); } else if (sel->type == JS_STRING) { int pos; if (obj->hash == NULL) hash_create (vm, obj); pos = hash_lookup (obj, (char *) sel->u.vstring->data, sel->u.vstring->len); if (pos < 0) { /* It is undefined, define it. */ obj->props = js_vm_realloc (vm, obj->props, (obj->num_props + 1) * sizeof (JSProperty)); /* * XXX if <sel> is a valid symbol, intern it and set symbol's * name below. */ obj->props[obj->num_props].name = JS_SYMBOL_NULL; obj->props[obj->num_props].attributes = 0; JS_COPY (&obj->props[obj->num_props].value, value); hash_insert (vm, obj, (char *) sel->u.vstring->data, sel->u.vstring->len, obj->num_props); obj->num_props++; } else JS_COPY (&obj->props[pos].value, value); } }