8 static void jsR_run(js_State *J, js_Function *F);
10 /* Push values on stack */
12 #define STACK (J->stack)
16 static void js_stackoverflow(js_State *J)
18 STACK[TOP].type = JS_TLITSTR;
19 STACK[TOP].u.litstr = "stack overflow";
24 static void js_outofmemory(js_State *J)
26 STACK[TOP].type = JS_TLITSTR;
27 STACK[TOP].u.litstr = "out of memory";
32 void *js_malloc(js_State *J, unsigned int size)
34 void *ptr = J->alloc(J->actx, NULL, size);
40 void *js_realloc(js_State *J, void *ptr, unsigned int size)
42 ptr = J->alloc(J->actx, ptr, size);
48 void js_free(js_State *J, void *ptr)
50 J->alloc(J->actx, ptr, 0);
53 js_String *jsV_newmemstring(js_State *J, const char *s, int n)
55 js_String *v = js_malloc(J, offsetof(js_String, p) + n + 1);
65 #define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J)
67 void js_pushvalue(js_State *J, js_Value v)
74 void js_pushundefined(js_State *J)
77 STACK[TOP].type = JS_TUNDEFINED;
81 void js_pushnull(js_State *J)
84 STACK[TOP].type = JS_TNULL;
88 void js_pushboolean(js_State *J, int v)
91 STACK[TOP].type = JS_TBOOLEAN;
92 STACK[TOP].u.boolean = !!v;
96 void js_pushnumber(js_State *J, double v)
99 STACK[TOP].type = JS_TNUMBER;
100 STACK[TOP].u.number = v;
104 void js_pushstring(js_State *J, const char *v)
106 unsigned int n = strlen(v);
108 if (n <= offsetof(js_Value, type)) {
109 char *s = STACK[TOP].u.shrstr;
110 while (n--) *s++ = *v++;
112 STACK[TOP].type = JS_TSHRSTR;
114 STACK[TOP].type = JS_TMEMSTR;
115 STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
120 void js_pushlstring(js_State *J, const char *v, unsigned int n)
123 if (n <= offsetof(js_Value, type)) {
124 char *s = STACK[TOP].u.shrstr;
125 while (n--) *s++ = *v++;
127 STACK[TOP].type = JS_TSHRSTR;
129 STACK[TOP].type = JS_TMEMSTR;
130 STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
135 void js_pushliteral(js_State *J, const char *v)
138 STACK[TOP].type = JS_TLITSTR;
139 STACK[TOP].u.litstr = v;
143 void js_pushobject(js_State *J, js_Object *v)
146 STACK[TOP].type = JS_TOBJECT;
147 STACK[TOP].u.object = v;
151 void js_pushglobal(js_State *J)
153 js_pushobject(J, J->G);
156 void js_pushundefinedthis(js_State *J)
161 js_pushobject(J, J->G);
164 void js_currentfunction(js_State *J)
167 STACK[TOP] = STACK[BOT-1];
171 /* Read values from stack */
173 static js_Value *stackidx(js_State *J, int idx)
175 static js_Value undefined = { {0}, {0}, JS_TUNDEFINED };
176 idx = idx < 0 ? TOP + idx : BOT + idx;
177 if (idx < 0 || idx >= TOP)
182 js_Value *js_tovalue(js_State *J, int idx)
184 return stackidx(J, idx);
187 int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; }
188 int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; }
189 int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; }
190 int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; }
191 int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; }
192 int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; }
193 int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }
194 int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }
196 int js_iscallable(js_State *J, int idx)
198 js_Value *v = stackidx(J, idx);
199 if (v->type == JS_TOBJECT)
200 return v->u.object->type == JS_CFUNCTION ||
201 v->u.object->type == JS_CSCRIPT ||
202 v->u.object->type == JS_CCFUNCTION;
206 int js_isarray(js_State *J, int idx)
208 js_Value *v = stackidx(J, idx);
209 return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
212 int js_isregexp(js_State *J, int idx)
214 js_Value *v = stackidx(J, idx);
215 return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
218 int js_isuserdata(js_State *J, int idx, const char *tag)
220 js_Value *v = stackidx(J, idx);
221 if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
222 return !strcmp(tag, v->u.object->u.user.tag);
226 static const char *js_typeof(js_State *J, int idx)
228 js_Value *v = stackidx(J, idx);
231 case JS_TSHRSTR: return "string";
232 case JS_TUNDEFINED: return "undefined";
233 case JS_TNULL: return "object";
234 case JS_TBOOLEAN: return "boolean";
235 case JS_TNUMBER: return "number";
236 case JS_TLITSTR: return "string";
237 case JS_TMEMSTR: return "string";
239 if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
245 int js_toboolean(js_State *J, int idx)
247 return jsV_toboolean(J, stackidx(J, idx));
250 double js_tonumber(js_State *J, int idx)
252 return jsV_tonumber(J, stackidx(J, idx));
255 double js_tointeger(js_State *J, int idx)
257 return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx)));
260 int js_toint32(js_State *J, int idx)
262 return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx)));
265 unsigned int js_touint32(js_State *J, int idx)
267 return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx)));
270 short js_toint16(js_State *J, int idx)
272 return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx)));
275 unsigned short js_touint16(js_State *J, int idx)
277 return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx)));
280 const char *js_tostring(js_State *J, int idx)
282 return jsV_tostring(J, stackidx(J, idx));
285 js_Object *js_toobject(js_State *J, int idx)
287 return jsV_toobject(J, stackidx(J, idx));
290 void js_toprimitive(js_State *J, int idx, int hint)
292 jsV_toprimitive(J, stackidx(J, idx), hint);
295 js_Regexp *js_toregexp(js_State *J, int idx)
297 js_Value *v = stackidx(J, idx);
298 if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
299 return &v->u.object->u.r;
300 js_typeerror(J, "not a regexp");
303 void *js_touserdata(js_State *J, int idx, const char *tag)
305 js_Value *v = stackidx(J, idx);
306 if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
307 if (!strcmp(tag, v->u.object->u.user.tag))
308 return v->u.object->u.user.data;
309 js_typeerror(J, "not a %s", tag);
312 static js_Object *jsR_tofunction(js_State *J, int idx)
314 js_Value *v = stackidx(J, idx);
315 if (v->type == JS_TUNDEFINED || v->type == JS_TNULL)
317 if (v->type == JS_TOBJECT)
318 if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
320 js_typeerror(J, "not a function");
323 /* Stack manipulation */
325 int js_gettop(js_State *J)
330 void js_pop(js_State *J, int n)
335 js_error(J, "stack underflow!");
339 void js_remove(js_State *J, int idx)
341 idx = idx < 0 ? TOP + idx : BOT + idx;
342 if (idx < BOT || idx >= TOP)
343 js_error(J, "stack error!");
344 for (;idx < TOP - 1; ++idx)
345 STACK[idx] = STACK[idx+1];
349 void js_copy(js_State *J, int idx)
352 STACK[TOP] = *stackidx(J, idx);
356 void js_dup(js_State *J)
359 STACK[TOP] = STACK[TOP-1];
363 void js_dup2(js_State *J)
366 STACK[TOP] = STACK[TOP-2];
367 STACK[TOP+1] = STACK[TOP-1];
371 void js_rot2(js_State *J)
374 js_Value tmp = STACK[TOP-1]; /* A B (B) */
375 STACK[TOP-1] = STACK[TOP-2]; /* A A */
376 STACK[TOP-2] = tmp; /* B A */
379 void js_rot3(js_State *J)
382 js_Value tmp = STACK[TOP-1]; /* A B C (C) */
383 STACK[TOP-1] = STACK[TOP-2]; /* A B B */
384 STACK[TOP-2] = STACK[TOP-3]; /* A A B */
385 STACK[TOP-3] = tmp; /* C A B */
388 void js_rot4(js_State *J)
390 /* A B C D -> D A B C */
391 js_Value tmp = STACK[TOP-1]; /* A B C D (D) */
392 STACK[TOP-1] = STACK[TOP-2]; /* A B C C */
393 STACK[TOP-2] = STACK[TOP-3]; /* A B B C */
394 STACK[TOP-3] = STACK[TOP-4]; /* A A B C */
395 STACK[TOP-4] = tmp; /* D A B C */
398 void js_rot2pop1(js_State *J)
401 STACK[TOP-2] = STACK[TOP-1];
405 void js_rot3pop2(js_State *J)
408 STACK[TOP-3] = STACK[TOP-1];
412 void js_rot(js_State *J, int n)
415 js_Value tmp = STACK[TOP-1];
416 for (i = 1; i < n; ++i)
417 STACK[TOP-i] = STACK[TOP-i-1];
421 /* Property access that takes care of attributes and getters/setters */
423 int js_isarrayindex(js_State *J, const char *str, unsigned int *idx)
426 *idx = jsV_numbertouint32(jsV_stringtonumber(J, str));
427 sprintf(buf, "%u", *idx);
428 return !strcmp(buf, str);
431 static void js_pushrune(js_State *J, Rune rune)
433 char buf[UTFmax + 1];
435 buf[runetochar(buf, &rune)] = 0;
436 js_pushstring(J, buf);
443 static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name)
448 if (obj->type == JS_CARRAY) {
449 if (!strcmp(name, "length")) {
450 js_pushnumber(J, obj->u.a.length);
455 if (obj->type == JS_CSTRING) {
456 if (!strcmp(name, "length")) {
457 js_pushnumber(J, obj->u.s.length);
460 if (js_isarrayindex(J, name, &k)) {
461 js_pushrune(J, js_runeat(J, obj->u.s.string, k));
466 if (obj->type == JS_CREGEXP) {
467 if (!strcmp(name, "source")) {
468 js_pushliteral(J, obj->u.r.source);
471 if (!strcmp(name, "global")) {
472 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G);
475 if (!strcmp(name, "ignoreCase")) {
476 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I);
479 if (!strcmp(name, "multiline")) {
480 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M);
483 if (!strcmp(name, "lastIndex")) {
484 js_pushnumber(J, obj->u.r.last);
489 ref = jsV_getproperty(J, obj, name);
492 js_pushobject(J, ref->getter);
493 js_pushobject(J, obj);
496 js_pushvalue(J, ref->value);
504 static void jsR_getproperty(js_State *J, js_Object *obj, const char *name)
506 if (!jsR_hasproperty(J, obj, name))
510 static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, js_Value *value)
516 if (obj->type == JS_CARRAY) {
517 if (!strcmp(name, "length")) {
518 double rawlen = jsV_tonumber(J, value);
519 unsigned int newlen = jsV_numbertouint32(rawlen);
520 if (newlen != rawlen)
521 js_rangeerror(J, "array length");
522 jsV_resizearray(J, obj, newlen);
525 if (js_isarrayindex(J, name, &k))
526 if (k >= obj->u.a.length)
527 obj->u.a.length = k + 1;
530 if (obj->type == JS_CSTRING) {
531 if (!strcmp(name, "length"))
533 if (js_isarrayindex(J, name, &k))
534 if (js_runeat(J, obj->u.s.string, k))
538 if (obj->type == JS_CREGEXP) {
539 if (!strcmp(name, "source")) goto readonly;
540 if (!strcmp(name, "global")) goto readonly;
541 if (!strcmp(name, "ignoreCase")) goto readonly;
542 if (!strcmp(name, "multiline")) goto readonly;
543 if (!strcmp(name, "lastIndex")) {
544 obj->u.r.last = jsV_tointeger(J, value);
549 /* First try to find a setter in prototype chain */
550 ref = jsV_getpropertyx(J, obj, name, &own);
551 if (ref && ref->setter) {
552 js_pushobject(J, ref->setter);
553 js_pushobject(J, obj);
554 js_pushvalue(J, *value);
560 /* Property not found on this object, so create one */
562 ref = jsV_setproperty(J, obj, name);
565 if (!(ref->atts & JS_READONLY))
575 js_typeerror(J, "'%s' is read-only", name);
578 static void jsR_defproperty(js_State *J, js_Object *obj, const char *name,
579 int atts, js_Value *value, js_Object *getter, js_Object *setter)
584 if (obj->type == JS_CARRAY)
585 if (!strcmp(name, "length"))
588 if (obj->type == JS_CSTRING) {
589 if (!strcmp(name, "length"))
591 if (js_isarrayindex(J, name, &k))
592 if (js_runeat(J, obj->u.s.string, k))
596 if (obj->type == JS_CREGEXP) {
597 if (!strcmp(name, "source")) goto readonly;
598 if (!strcmp(name, "global")) goto readonly;
599 if (!strcmp(name, "ignoreCase")) goto readonly;
600 if (!strcmp(name, "multiline")) goto readonly;
601 if (!strcmp(name, "lastIndex")) goto readonly;
604 ref = jsV_setproperty(J, obj, name);
607 if (!(ref->atts & JS_READONLY))
610 js_typeerror(J, "'%s' is read-only", name);
613 if (!(ref->atts & JS_DONTCONF))
614 ref->getter = getter;
616 js_typeerror(J, "'%s' is non-configurable", name);
619 if (!(ref->atts & JS_DONTCONF))
620 ref->setter = setter;
622 js_typeerror(J, "'%s' is non-configurable", name);
631 js_typeerror(J, "'%s' is read-only or non-configurable", name);
634 static int jsR_delproperty(js_State *J, js_Object *obj, const char *name)
639 if (obj->type == JS_CARRAY)
640 if (!strcmp(name, "length"))
643 if (obj->type == JS_CSTRING) {
644 if (!strcmp(name, "length"))
646 if (js_isarrayindex(J, name, &k))
647 if (js_runeat(J, obj->u.s.string, k))
651 if (obj->type == JS_CREGEXP) {
652 if (!strcmp(name, "source")) goto dontconf;
653 if (!strcmp(name, "global")) goto dontconf;
654 if (!strcmp(name, "ignoreCase")) goto dontconf;
655 if (!strcmp(name, "multiline")) goto dontconf;
656 if (!strcmp(name, "lastIndex")) goto dontconf;
659 ref = jsV_getownproperty(J, obj, name);
661 if (ref->atts & JS_DONTCONF)
663 jsV_delproperty(J, obj, name);
669 js_typeerror(J, "'%s' is non-configurable", name);
673 /* Registry, global and object property accessors */
675 const char *js_ref(js_State *J)
677 js_Value *v = stackidx(J, -1);
681 case JS_TUNDEFINED: s = "_Undefined"; break;
682 case JS_TNULL: s = "_Null"; break;
684 s = v->u.boolean ? "_True" : "_False";
687 sprintf(buf, "%p", (void*)v->u.object);
688 s = js_intern(J, buf);
691 sprintf(buf, "%d", J->nextref++);
692 s = js_intern(J, buf);
695 js_setregistry(J, s);
699 void js_unref(js_State *J, const char *ref)
701 js_delregistry(J, ref);
704 void js_getregistry(js_State *J, const char *name)
706 jsR_getproperty(J, J->R, name);
709 void js_setregistry(js_State *J, const char *name)
711 jsR_setproperty(J, J->R, name, stackidx(J, -1));
715 void js_delregistry(js_State *J, const char *name)
717 jsR_delproperty(J, J->R, name);
720 void js_getglobal(js_State *J, const char *name)
722 jsR_getproperty(J, J->G, name);
725 void js_setglobal(js_State *J, const char *name)
727 jsR_setproperty(J, J->G, name, stackidx(J, -1));
731 void js_defglobal(js_State *J, const char *name, int atts)
733 jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL);
737 void js_getproperty(js_State *J, int idx, const char *name)
739 jsR_getproperty(J, js_toobject(J, idx), name);
742 void js_setproperty(js_State *J, int idx, const char *name)
744 jsR_setproperty(J, js_toobject(J, idx), name, stackidx(J, -1));
748 void js_defproperty(js_State *J, int idx, const char *name, int atts)
750 jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL);
754 void js_delproperty(js_State *J, int idx, const char *name)
756 jsR_delproperty(J, js_toobject(J, idx), name);
759 void js_defaccessor(js_State *J, int idx, const char *name, int atts)
761 jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1));
765 int js_hasproperty(js_State *J, int idx, const char *name)
767 return jsR_hasproperty(J, js_toobject(J, idx), name);
772 void js_pushiterator(js_State *J, int idx, int own)
774 js_pushobject(J, jsV_newiterator(J, js_toobject(J, idx), own));
777 const char *js_nextiterator(js_State *J, int idx)
779 return jsV_nextiterator(J, js_toobject(J, idx));
782 /* Environment records */
784 js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
786 js_Environment *E = js_malloc(J, sizeof *E);
788 E->gcnext = J->gcenv;
797 static void js_initvar(js_State *J, const char *name, int idx)
799 jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL);
802 static void js_defvar(js_State *J, const char *name)
804 jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, NULL, NULL, NULL);
807 static int js_hasvar(js_State *J, const char *name)
809 js_Environment *E = J->E;
811 js_Property *ref = jsV_getproperty(J, E->variables, name);
814 js_pushobject(J, ref->getter);
815 js_pushobject(J, E->variables);
818 js_pushvalue(J, ref->value);
827 static void js_setvar(js_State *J, const char *name)
829 js_Environment *E = J->E;
831 js_Property *ref = jsV_getproperty(J, E->variables, name);
834 js_pushobject(J, ref->setter);
835 js_pushobject(J, E->variables);
841 if (!(ref->atts & JS_READONLY))
842 ref->value = *stackidx(J, -1);
844 js_typeerror(J, "'%s' is read-only", name);
850 js_referenceerror(J, "assignment to undeclared variable '%s'", name);
851 jsR_setproperty(J, J->G, name, stackidx(J, -1));
854 static int js_delvar(js_State *J, const char *name)
856 js_Environment *E = J->E;
858 js_Property *ref = jsV_getownproperty(J, E->variables, name);
860 if (ref->atts & JS_DONTCONF) {
862 js_typeerror(J, "'%s' is non-configurable", name);
865 jsV_delproperty(J, E->variables, name);
870 return jsR_delproperty(J, J->G, name);
875 static void jsR_savescope(js_State *J, js_Environment *newE)
877 if (J->envtop + 1 >= JS_ENVLIMIT)
879 J->envstack[J->envtop++] = J->E;
883 static void jsR_restorescope(js_State *J)
885 J->E = J->envstack[--J->envtop];
888 static void jsR_calllwfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
893 jsR_savescope(J, scope);
895 if (n > F->numparams) {
896 js_pop(J, F->numparams - n);
899 for (i = n; i < F->varlen; ++i)
903 v = *stackidx(J, -1);
904 TOP = --BOT; /* clear stack */
910 static void jsR_callfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
915 scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
917 jsR_savescope(J, scope);
922 js_currentfunction(J);
923 js_defproperty(J, -2, "callee", JS_DONTENUM);
926 js_defproperty(J, -2, "length", JS_DONTENUM);
927 for (i = 0; i < n; ++i) {
929 js_setindex(J, -2, i);
931 js_initvar(J, "arguments", -1);
935 for (i = 0; i < F->numparams; ++i) {
937 js_initvar(J, F->vartab[i], i + 1);
940 js_initvar(J, F->vartab[i], -1);
947 v = *stackidx(J, -1);
948 TOP = --BOT; /* clear stack */
954 static void jsR_callscript(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
959 jsR_savescope(J, scope);
963 v = *stackidx(J, -1);
964 TOP = --BOT; /* clear stack */
971 static void jsR_callcfunction(js_State *J, unsigned int n, unsigned int min, js_CFunction F)
976 for (i = n; i < min; ++i)
980 v = *stackidx(J, -1);
981 TOP = --BOT; /* clear stack */
985 static void jsR_pushtrace(js_State *J, const char *name, const char *file, int line)
987 if (++J->tracetop == JS_ENVLIMIT)
988 js_error(J, "call stack overflow");
989 J->trace[J->tracetop].name = name;
990 J->trace[J->tracetop].file = file;
991 J->trace[J->tracetop].line = line;
994 void js_call(js_State *J, int n)
999 if (!js_iscallable(J, -n-2))
1000 js_typeerror(J, "called object is not a function");
1002 obj = js_toobject(J, -n-2);
1007 if (obj->type == JS_CFUNCTION) {
1008 jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
1009 if (obj->u.f.function->lightweight)
1010 jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope);
1012 jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope);
1014 } else if (obj->type == JS_CSCRIPT) {
1015 jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
1016 jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope);
1018 } else if (obj->type == JS_CCFUNCTION) {
1019 jsR_pushtrace(J, obj->u.c.name, "[C]", 0);
1020 jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function);
1027 void js_construct(js_State *J, int n)
1030 js_Object *prototype;
1033 if (!js_iscallable(J, -n-1))
1034 js_typeerror(J, "called object is not a function");
1036 obj = js_toobject(J, -n-1);
1038 /* built-in constructors create their own objects, give them a 'null' this */
1039 if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) {
1046 jsR_pushtrace(J, obj->u.c.name, "[C]", 0);
1047 jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor);
1054 /* extract the function object's prototype property */
1055 js_getproperty(J, -n - 1, "prototype");
1056 if (js_isobject(J, -1))
1057 prototype = js_toobject(J, -1);
1059 prototype = J->Object_prototype;
1062 /* create a new object with above prototype, and shift it into the 'this' slot */
1063 newobj = jsV_newobject(J, JS_COBJECT, prototype);
1064 js_pushobject(J, newobj);
1068 /* call the function */
1071 /* if result is not an object, return the original object we created */
1072 if (!js_isobject(J, -1)) {
1074 js_pushobject(J, newobj);
1078 void js_eval(js_State *J)
1080 if (!js_isstring(J, -1))
1082 js_loadeval(J, "(eval)", js_tostring(J, -1));
1084 js_copy(J, 0); /* copy 'this' */
1088 int js_pconstruct(js_State *J, int n)
1097 int js_pcall(js_State *J, int n)
1108 void js_savetry(js_State *J, js_Instruction *pc)
1110 if (J->trytop == JS_TRYLIMIT)
1111 js_error(J, "try: exception stack overflow");
1112 J->trybuf[J->trytop].E = J->E;
1113 J->trybuf[J->trytop].envtop = J->envtop;
1114 J->trybuf[J->trytop].tracetop = J->tracetop;
1115 J->trybuf[J->trytop].top = J->top;
1116 J->trybuf[J->trytop].bot = J->bot;
1117 J->trybuf[J->trytop].pc = pc;
1120 void js_throw(js_State *J)
1122 if (J->trytop > 0) {
1123 js_Value v = *stackidx(J, -1);
1125 J->E = J->trybuf[J->trytop].E;
1126 J->envtop = J->trybuf[J->trytop].envtop;
1127 J->tracetop = J->trybuf[J->trytop].tracetop;
1128 J->top = J->trybuf[J->trytop].top;
1129 J->bot = J->trybuf[J->trytop].bot;
1131 longjmp(J->trybuf[J->trytop].buf, 1);
1138 /* Main interpreter loop */
1140 static void jsR_dumpstack(js_State *J)
1143 printf("stack {\n");
1144 for (i = 0; i < TOP; ++i) {
1145 putchar(i == BOT ? '>' : ' ');
1146 printf("% 4d: ", i);
1147 js_dumpvalue(J, STACK[i]);
1153 static void jsR_dumpenvironment(js_State *J, js_Environment *E, int d)
1155 printf("scope %d ", d);
1156 js_dumpobject(J, E->variables);
1158 jsR_dumpenvironment(J, E->outer, d+1);
1161 void js_stacktrace(js_State *J)
1164 printf("stack trace:\n");
1165 for (n = J->tracetop; n >= 0; --n) {
1166 const char *name = J->trace[n].name;
1167 const char *file = J->trace[n].file;
1168 int line = J->trace[n].line;
1170 printf("\t%s:%d: in function '%s'\n", file, line, name);
1172 printf("\t%s: in function '%s'\n", file, name);
1176 void js_trap(js_State *J, int pc)
1179 js_Function *F = STACK[BOT-1].u.object->u.f.function;
1180 printf("trap at %d in function ", pc);
1181 jsC_dumpfunction(J, F);
1184 jsR_dumpenvironment(J, J->E, 0);
1188 static void jsR_run(js_State *J, js_Function *F)
1190 js_Function **FT = F->funtab;
1191 double *NT = F->numtab;
1192 const char **ST = F->strtab;
1193 js_Instruction *pcstart = F->code;
1194 js_Instruction *pc = F->code;
1195 enum js_OpCode opcode;
1201 unsigned int ux, uy;
1206 if (J->gccounter > JS_GCLIMIT) {
1213 case OP_POP: js_pop(J, 1); break;
1214 case OP_DUP: js_dup(J); break;
1215 case OP_DUP2: js_dup2(J); break;
1216 case OP_ROT2: js_rot2(J); break;
1217 case OP_ROT3: js_rot3(J); break;
1218 case OP_ROT4: js_rot4(J); break;
1220 case OP_NUMBER_0: js_pushnumber(J, 0); break;
1221 case OP_NUMBER_1: js_pushnumber(J, 1); break;
1222 case OP_NUMBER_POS: js_pushnumber(J, *pc++); break;
1223 case OP_NUMBER_NEG: js_pushnumber(J, -(*pc++)); break;
1224 case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
1225 case OP_STRING: js_pushliteral(J, ST[*pc++]); break;
1227 case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
1228 case OP_NEWOBJECT: js_newobject(J); break;
1229 case OP_NEWARRAY: js_newarray(J); break;
1230 case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break;
1232 case OP_UNDEF: js_pushundefined(J); break;
1233 case OP_NULL: js_pushnull(J); break;
1234 case OP_TRUE: js_pushboolean(J, 1); break;
1235 case OP_FALSE: js_pushboolean(J, 0); break;
1237 case OP_THIS: js_copy(J, 0); break;
1238 case OP_GLOBAL: js_pushobject(J, J->G); break;
1239 case OP_CURRENT: js_currentfunction(J); break;
1242 STACK[BOT + *pc++] = STACK[--TOP];
1247 STACK[TOP++] = STACK[BOT + *pc++];
1251 STACK[BOT + *pc++] = STACK[TOP-1];
1256 js_pushboolean(J, 0);
1260 js_initvar(J, ST[*pc++], -1);
1265 js_defvar(J, ST[*pc++]);
1270 if (!js_hasvar(J, str))
1271 js_referenceerror(J, "'%s' is not defined", str);
1275 if (!js_hasvar(J, ST[*pc++]))
1276 js_pushundefined(J);
1280 js_setvar(J, ST[*pc++]);
1284 b = js_delvar(J, ST[*pc++]);
1285 js_pushboolean(J, b);
1289 str = js_tostring(J, -2);
1290 if (!js_isobject(J, -1))
1291 js_typeerror(J, "operand to 'in' is not an object");
1292 b = js_hasproperty(J, -1, str);
1294 js_pushboolean(J, b);
1298 obj = js_toobject(J, -3);
1299 str = js_tostring(J, -2);
1300 jsR_setproperty(J, obj, str, stackidx(J, -1));
1305 obj = js_toobject(J, -3);
1306 str = js_tostring(J, -2);
1307 jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL);
1312 obj = js_toobject(J, -3);
1313 str = js_tostring(J, -2);
1314 jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1));
1319 str = js_tostring(J, -1);
1320 obj = js_toobject(J, -2);
1321 jsR_getproperty(J, obj, str);
1327 obj = js_toobject(J, -1);
1328 jsR_getproperty(J, obj, str);
1333 str = js_tostring(J, -2);
1334 obj = js_toobject(J, -3);
1335 jsR_setproperty(J, obj, str, stackidx(J, -1));
1341 obj = js_toobject(J, -2);
1342 jsR_setproperty(J, obj, str, stackidx(J, -1));
1347 str = js_tostring(J, -1);
1348 obj = js_toobject(J, -2);
1349 b = jsR_delproperty(J, obj, str);
1351 js_pushboolean(J, b);
1356 obj = js_toobject(J, -1);
1357 b = jsR_delproperty(J, obj, str);
1359 js_pushboolean(J, b);
1363 if (!js_isundefined(J, -1) && !js_isnull(J, -1)) {
1364 obj = jsV_newiterator(J, js_toobject(J, -1), 0);
1366 js_pushobject(J, obj);
1371 obj = js_toobject(J, -1);
1372 str = jsV_nextiterator(J, obj);
1374 js_pushliteral(J, str);
1375 js_pushboolean(J, 1);
1378 js_pushboolean(J, 0);
1382 /* Function calls */
1393 js_construct(J, *pc++);
1396 /* Unary operators */
1399 str = js_typeof(J, -1);
1401 js_pushliteral(J, str);
1405 x = js_tonumber(J, -1);
1407 js_pushnumber(J, x);
1411 x = js_tonumber(J, -1);
1413 js_pushnumber(J, -x);
1417 ix = js_toint32(J, -1);
1419 js_pushnumber(J, ~ix);
1423 b = js_toboolean(J, -1);
1425 js_pushboolean(J, !b);
1429 x = js_tonumber(J, -1);
1431 js_pushnumber(J, x + 1);
1435 x = js_tonumber(J, -1);
1437 js_pushnumber(J, x - 1);
1441 x = js_tonumber(J, -1);
1443 js_pushnumber(J, x + 1);
1444 js_pushnumber(J, x);
1448 x = js_tonumber(J, -1);
1450 js_pushnumber(J, x - 1);
1451 js_pushnumber(J, x);
1454 /* Multiplicative operators */
1457 x = js_tonumber(J, -2);
1458 y = js_tonumber(J, -1);
1460 js_pushnumber(J, x * y);
1464 x = js_tonumber(J, -2);
1465 y = js_tonumber(J, -1);
1467 js_pushnumber(J, x / y);
1471 x = js_tonumber(J, -2);
1472 y = js_tonumber(J, -1);
1474 js_pushnumber(J, fmod(x, y));
1477 /* Additive operators */
1484 x = js_tonumber(J, -2);
1485 y = js_tonumber(J, -1);
1487 js_pushnumber(J, x - y);
1490 /* Shift operators */
1493 ix = js_toint32(J, -2);
1494 uy = js_touint32(J, -1);
1496 js_pushnumber(J, ix << (uy & 0x1F));
1500 ix = js_toint32(J, -2);
1501 uy = js_touint32(J, -1);
1503 js_pushnumber(J, ix >> (uy & 0x1F));
1507 ux = js_touint32(J, -2);
1508 uy = js_touint32(J, -1);
1510 js_pushnumber(J, ux >> (uy & 0x1F));
1513 /* Relational operators */
1515 case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break;
1516 case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break;
1517 case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break;
1518 case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break;
1521 b = js_instanceof(J);
1523 js_pushboolean(J, b);
1528 case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break;
1529 case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
1530 case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break;
1531 case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
1535 b = js_strictequal(J);
1538 pc = pcstart + offset;
1544 /* Binary bitwise operators */
1547 ix = js_toint32(J, -2);
1548 iy = js_toint32(J, -1);
1550 js_pushnumber(J, ix & iy);
1554 ix = js_toint32(J, -2);
1555 iy = js_toint32(J, -1);
1557 js_pushnumber(J, ix ^ iy);
1561 ix = js_toint32(J, -2);
1562 iy = js_toint32(J, -1);
1564 js_pushnumber(J, ix | iy);
1574 if (js_trypc(J, pc)) {
1575 pc = J->trybuf[J->trytop].pc;
1577 pc = pcstart + offset;
1587 obj = jsV_newobject(J, JS_COBJECT, NULL);
1588 js_pushobject(J, obj);
1590 js_setproperty(J, -2, str);
1591 J->E = jsR_newenvironment(J, obj, J->E);
1602 obj = js_toobject(J, -1);
1603 J->E = jsR_newenvironment(J, obj, J->E);
1614 js_trap(J, (int)(pc - pcstart) - 1);
1623 b = js_toboolean(J, -1);
1626 pc = pcstart + offset;
1631 b = js_toboolean(J, -1);
1634 pc = pcstart + offset;
1641 J->trace[J->tracetop].line = *pc++;