1 #include "jsi.h"
2 #include "jscompile.h"
3 #include "jsvalue.h"
4 #include "jsrun.h"
5
6 #include "utf.h"
7
8 static void jsR_run(js_State *J, js_Function *F);
9
10 /* Push values on stack */
11
12 #define STACK (J->stack)
13 #define TOP (J->top)
14 #define BOT (J->bot)
15
js_stackoverflow(js_State * J)16 static void js_stackoverflow(js_State *J)
17 {
18 STACK[TOP].type = JS_TLITSTR;
19 STACK[TOP].u.litstr = "stack overflow";
20 ++TOP;
21 js_throw(J);
22 }
23
js_outofmemory(js_State * J)24 static void js_outofmemory(js_State *J)
25 {
26 STACK[TOP].type = JS_TLITSTR;
27 STACK[TOP].u.litstr = "out of memory";
28 ++TOP;
29 js_throw(J);
30 }
31
js_malloc(js_State * J,int size)32 void *js_malloc(js_State *J, int size)
33 {
34 void *ptr = J->alloc(J->actx, NULL, size);
35 if (!ptr)
36 js_outofmemory(J);
37 return ptr;
38 }
39
js_realloc(js_State * J,void * ptr,int size)40 void *js_realloc(js_State *J, void *ptr, int size)
41 {
42 ptr = J->alloc(J->actx, ptr, size);
43 if (!ptr)
44 js_outofmemory(J);
45 return ptr;
46 }
47
js_strdup(js_State * J,const char * s)48 char *js_strdup(js_State *J, const char *s)
49 {
50 int n = strlen(s) + 1;
51 char *p = js_malloc(J, n);
52 memcpy(p, s, n);
53 return p;
54 }
55
js_free(js_State * J,void * ptr)56 void js_free(js_State *J, void *ptr)
57 {
58 J->alloc(J->actx, ptr, 0);
59 }
60
jsV_newmemstring(js_State * J,const char * s,int n)61 js_String *jsV_newmemstring(js_State *J, const char *s, int n)
62 {
63 js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1);
64 memcpy(v->p, s, n);
65 v->p[n] = 0;
66 v->gcmark = 0;
67 v->gcnext = J->gcstr;
68 J->gcstr = v;
69 ++J->gccounter;
70 return v;
71 }
72
73 #define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J)
74
js_pushvalue(js_State * J,js_Value v)75 void js_pushvalue(js_State *J, js_Value v)
76 {
77 CHECKSTACK(1);
78 STACK[TOP] = v;
79 ++TOP;
80 }
81
js_pushundefined(js_State * J)82 void js_pushundefined(js_State *J)
83 {
84 CHECKSTACK(1);
85 STACK[TOP].type = JS_TUNDEFINED;
86 ++TOP;
87 }
88
js_pushnull(js_State * J)89 void js_pushnull(js_State *J)
90 {
91 CHECKSTACK(1);
92 STACK[TOP].type = JS_TNULL;
93 ++TOP;
94 }
95
js_pushboolean(js_State * J,int v)96 void js_pushboolean(js_State *J, int v)
97 {
98 CHECKSTACK(1);
99 STACK[TOP].type = JS_TBOOLEAN;
100 STACK[TOP].u.boolean = !!v;
101 ++TOP;
102 }
103
js_pushnumber(js_State * J,double v)104 void js_pushnumber(js_State *J, double v)
105 {
106 CHECKSTACK(1);
107 STACK[TOP].type = JS_TNUMBER;
108 STACK[TOP].u.number = v;
109 ++TOP;
110 }
111
js_pushstring(js_State * J,const char * v)112 void js_pushstring(js_State *J, const char *v)
113 {
114 int n = strlen(v);
115 CHECKSTACK(1);
116 if (n <= soffsetof(js_Value, type)) {
117 char *s = STACK[TOP].u.shrstr;
118 while (n--) *s++ = *v++;
119 *s = 0;
120 STACK[TOP].type = JS_TSHRSTR;
121 } else {
122 STACK[TOP].type = JS_TMEMSTR;
123 STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
124 }
125 ++TOP;
126 }
127
js_pushlstring(js_State * J,const char * v,int n)128 void js_pushlstring(js_State *J, const char *v, int n)
129 {
130 CHECKSTACK(1);
131 if (n <= soffsetof(js_Value, type)) {
132 char *s = STACK[TOP].u.shrstr;
133 while (n--) *s++ = *v++;
134 *s = 0;
135 STACK[TOP].type = JS_TSHRSTR;
136 } else {
137 STACK[TOP].type = JS_TMEMSTR;
138 STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
139 }
140 ++TOP;
141 }
142
js_pushliteral(js_State * J,const char * v)143 void js_pushliteral(js_State *J, const char *v)
144 {
145 CHECKSTACK(1);
146 STACK[TOP].type = JS_TLITSTR;
147 STACK[TOP].u.litstr = v;
148 ++TOP;
149 }
150
js_pushobject(js_State * J,js_Object * v)151 void js_pushobject(js_State *J, js_Object *v)
152 {
153 CHECKSTACK(1);
154 STACK[TOP].type = JS_TOBJECT;
155 STACK[TOP].u.object = v;
156 ++TOP;
157 }
158
js_pushglobal(js_State * J)159 void js_pushglobal(js_State *J)
160 {
161 js_pushobject(J, J->G);
162 }
163
js_currentfunction(js_State * J)164 void js_currentfunction(js_State *J)
165 {
166 CHECKSTACK(1);
167 STACK[TOP] = STACK[BOT-1];
168 ++TOP;
169 }
170
171 /* Read values from stack */
172
stackidx(js_State * J,int idx)173 static js_Value *stackidx(js_State *J, int idx)
174 {
175 static js_Value undefined = { {0}, {0}, JS_TUNDEFINED };
176 idx = idx < 0 ? TOP + idx : BOT + idx;
177 if (idx < 0 || idx >= TOP)
178 return &undefined;
179 return STACK + idx;
180 }
181
js_tovalue(js_State * J,int idx)182 js_Value *js_tovalue(js_State *J, int idx)
183 {
184 return stackidx(J, idx);
185 }
186
js_isdefined(js_State * J,int idx)187 int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; }
js_isundefined(js_State * J,int idx)188 int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; }
js_isnull(js_State * J,int idx)189 int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; }
js_isboolean(js_State * J,int idx)190 int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; }
js_isnumber(js_State * J,int idx)191 int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; }
js_isstring(js_State * J,int idx)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; }
js_isprimitive(js_State * J,int idx)193 int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }
js_isobject(js_State * J,int idx)194 int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }
js_iscoercible(js_State * J,int idx)195 int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type != JS_TUNDEFINED && v->type != JS_TNULL; }
196
js_iscallable(js_State * J,int idx)197 int js_iscallable(js_State *J, int idx)
198 {
199 js_Value *v = stackidx(J, idx);
200 if (v->type == JS_TOBJECT)
201 return v->u.object->type == JS_CFUNCTION ||
202 v->u.object->type == JS_CSCRIPT ||
203 v->u.object->type == JS_CCFUNCTION;
204 return 0;
205 }
206
js_isarray(js_State * J,int idx)207 int js_isarray(js_State *J, int idx)
208 {
209 js_Value *v = stackidx(J, idx);
210 return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
211 }
212
js_isregexp(js_State * J,int idx)213 int js_isregexp(js_State *J, int idx)
214 {
215 js_Value *v = stackidx(J, idx);
216 return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
217 }
218
js_isuserdata(js_State * J,int idx,const char * tag)219 int js_isuserdata(js_State *J, int idx, const char *tag)
220 {
221 js_Value *v = stackidx(J, idx);
222 if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
223 return !strcmp(tag, v->u.object->u.user.tag);
224 return 0;
225 }
226
js_typeof(js_State * J,int idx)227 static const char *js_typeof(js_State *J, int idx)
228 {
229 js_Value *v = stackidx(J, idx);
230 switch (v->type) {
231 default:
232 case JS_TSHRSTR: return "string";
233 case JS_TUNDEFINED: return "undefined";
234 case JS_TNULL: return "object";
235 case JS_TBOOLEAN: return "boolean";
236 case JS_TNUMBER: return "number";
237 case JS_TLITSTR: return "string";
238 case JS_TMEMSTR: return "string";
239 case JS_TOBJECT:
240 if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
241 return "function";
242 return "object";
243 }
244 }
245
js_toboolean(js_State * J,int idx)246 int js_toboolean(js_State *J, int idx)
247 {
248 return jsV_toboolean(J, stackidx(J, idx));
249 }
250
js_tonumber(js_State * J,int idx)251 double js_tonumber(js_State *J, int idx)
252 {
253 return jsV_tonumber(J, stackidx(J, idx));
254 }
255
js_tointeger(js_State * J,int idx)256 int js_tointeger(js_State *J, int idx)
257 {
258 return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx)));
259 }
260
js_toint32(js_State * J,int idx)261 int js_toint32(js_State *J, int idx)
262 {
263 return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx)));
264 }
265
js_touint32(js_State * J,int idx)266 unsigned int js_touint32(js_State *J, int idx)
267 {
268 return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx)));
269 }
270
js_toint16(js_State * J,int idx)271 short js_toint16(js_State *J, int idx)
272 {
273 return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx)));
274 }
275
js_touint16(js_State * J,int idx)276 unsigned short js_touint16(js_State *J, int idx)
277 {
278 return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx)));
279 }
280
js_tostring(js_State * J,int idx)281 const char *js_tostring(js_State *J, int idx)
282 {
283 return jsV_tostring(J, stackidx(J, idx));
284 }
285
js_toobject(js_State * J,int idx)286 js_Object *js_toobject(js_State *J, int idx)
287 {
288 return jsV_toobject(J, stackidx(J, idx));
289 }
290
js_toprimitive(js_State * J,int idx,int hint)291 void js_toprimitive(js_State *J, int idx, int hint)
292 {
293 jsV_toprimitive(J, stackidx(J, idx), hint);
294 }
295
js_toregexp(js_State * J,int idx)296 js_Regexp *js_toregexp(js_State *J, int idx)
297 {
298 js_Value *v = stackidx(J, idx);
299 if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
300 return &v->u.object->u.r;
301 js_typeerror(J, "not a regexp");
302 }
303
js_touserdata(js_State * J,int idx,const char * tag)304 void *js_touserdata(js_State *J, int idx, const char *tag)
305 {
306 js_Value *v = stackidx(J, idx);
307 if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
308 if (!strcmp(tag, v->u.object->u.user.tag))
309 return v->u.object->u.user.data;
310 js_typeerror(J, "not a %s", tag);
311 }
312
jsR_tofunction(js_State * J,int idx)313 static js_Object *jsR_tofunction(js_State *J, int idx)
314 {
315 js_Value *v = stackidx(J, idx);
316 if (v->type == JS_TUNDEFINED || v->type == JS_TNULL)
317 return NULL;
318 if (v->type == JS_TOBJECT)
319 if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
320 return v->u.object;
321 js_typeerror(J, "not a function");
322 }
323
324 /* Stack manipulation */
325
js_gettop(js_State * J)326 int js_gettop(js_State *J)
327 {
328 return TOP - BOT;
329 }
330
js_pop(js_State * J,int n)331 void js_pop(js_State *J, int n)
332 {
333 TOP -= n;
334 if (TOP < BOT) {
335 TOP = BOT;
336 js_error(J, "stack underflow!");
337 }
338 }
339
js_remove(js_State * J,int idx)340 void js_remove(js_State *J, int idx)
341 {
342 idx = idx < 0 ? TOP + idx : BOT + idx;
343 if (idx < BOT || idx >= TOP)
344 js_error(J, "stack error!");
345 for (;idx < TOP - 1; ++idx)
346 STACK[idx] = STACK[idx+1];
347 --TOP;
348 }
349
js_insert(js_State * J,int idx)350 void js_insert(js_State *J, int idx)
351 {
352 js_error(J, "not implemented yet");
353 }
354
js_replace(js_State * J,int idx)355 void js_replace(js_State* J, int idx)
356 {
357 idx = idx < 0 ? TOP + idx : BOT + idx;
358 if (idx < BOT || idx >= TOP)
359 js_error(J, "stack error!");
360 STACK[idx] = STACK[--TOP];
361 }
362
js_copy(js_State * J,int idx)363 void js_copy(js_State *J, int idx)
364 {
365 CHECKSTACK(1);
366 STACK[TOP] = *stackidx(J, idx);
367 ++TOP;
368 }
369
js_dup(js_State * J)370 void js_dup(js_State *J)
371 {
372 CHECKSTACK(1);
373 STACK[TOP] = STACK[TOP-1];
374 ++TOP;
375 }
376
js_dup2(js_State * J)377 void js_dup2(js_State *J)
378 {
379 CHECKSTACK(2);
380 STACK[TOP] = STACK[TOP-2];
381 STACK[TOP+1] = STACK[TOP-1];
382 TOP += 2;
383 }
384
js_rot2(js_State * J)385 void js_rot2(js_State *J)
386 {
387 /* A B -> B A */
388 js_Value tmp = STACK[TOP-1]; /* A B (B) */
389 STACK[TOP-1] = STACK[TOP-2]; /* A A */
390 STACK[TOP-2] = tmp; /* B A */
391 }
392
js_rot3(js_State * J)393 void js_rot3(js_State *J)
394 {
395 /* A B C -> C A B */
396 js_Value tmp = STACK[TOP-1]; /* A B C (C) */
397 STACK[TOP-1] = STACK[TOP-2]; /* A B B */
398 STACK[TOP-2] = STACK[TOP-3]; /* A A B */
399 STACK[TOP-3] = tmp; /* C A B */
400 }
401
js_rot4(js_State * J)402 void js_rot4(js_State *J)
403 {
404 /* A B C D -> D A B C */
405 js_Value tmp = STACK[TOP-1]; /* A B C D (D) */
406 STACK[TOP-1] = STACK[TOP-2]; /* A B C C */
407 STACK[TOP-2] = STACK[TOP-3]; /* A B B C */
408 STACK[TOP-3] = STACK[TOP-4]; /* A A B C */
409 STACK[TOP-4] = tmp; /* D A B C */
410 }
411
js_rot2pop1(js_State * J)412 void js_rot2pop1(js_State *J)
413 {
414 /* A B -> B */
415 STACK[TOP-2] = STACK[TOP-1];
416 --TOP;
417 }
418
js_rot3pop2(js_State * J)419 void js_rot3pop2(js_State *J)
420 {
421 /* A B C -> C */
422 STACK[TOP-3] = STACK[TOP-1];
423 TOP -= 2;
424 }
425
js_rot(js_State * J,int n)426 void js_rot(js_State *J, int n)
427 {
428 int i;
429 js_Value tmp = STACK[TOP-1];
430 for (i = 1; i < n; ++i)
431 STACK[TOP-i] = STACK[TOP-i-1];
432 STACK[TOP-i] = tmp;
433 }
434
435 /* Property access that takes care of attributes and getters/setters */
436
js_isarrayindex(js_State * J,const char * p,int * idx)437 int js_isarrayindex(js_State *J, const char *p, int *idx)
438 {
439 int n = 0;
440 while (*p) {
441 int c = *p++;
442 if (c >= '0' && c <= '9') {
443 if (n > INT_MAX / 10 - 1)
444 return 0;
445 n = n * 10 + (c - '0');
446 } else {
447 return 0;
448 }
449 }
450 return *idx = n, 1;
451 }
452
js_pushrune(js_State * J,Rune rune)453 static void js_pushrune(js_State *J, Rune rune)
454 {
455 char buf[UTFmax + 1];
456 if (rune > 0) {
457 buf[runetochar(buf, &rune)] = 0;
458 js_pushstring(J, buf);
459 } else {
460 js_pushundefined(J);
461 }
462 }
463
jsR_hasproperty(js_State * J,js_Object * obj,const char * name)464 static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name)
465 {
466 js_Property *ref;
467 int k;
468
469 if (obj->type == JS_CARRAY) {
470 if (!strcmp(name, "length")) {
471 js_pushnumber(J, obj->u.a.length);
472 return 1;
473 }
474 }
475
476 else if (obj->type == JS_CSTRING) {
477 if (!strcmp(name, "length")) {
478 js_pushnumber(J, obj->u.s.length);
479 return 1;
480 }
481 if (js_isarrayindex(J, name, &k)) {
482 if (k >= 0 && k < obj->u.s.length) {
483 js_pushrune(J, js_runeat(J, obj->u.s.string, k));
484 return 1;
485 }
486 }
487 }
488
489 else if (obj->type == JS_CREGEXP) {
490 if (!strcmp(name, "source")) {
491 js_pushliteral(J, obj->u.r.source);
492 return 1;
493 }
494 if (!strcmp(name, "global")) {
495 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G);
496 return 1;
497 }
498 if (!strcmp(name, "ignoreCase")) {
499 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I);
500 return 1;
501 }
502 if (!strcmp(name, "multiline")) {
503 js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M);
504 return 1;
505 }
506 if (!strcmp(name, "lastIndex")) {
507 js_pushnumber(J, obj->u.r.last);
508 return 1;
509 }
510 }
511
512 else if (obj->type == JS_CUSERDATA) {
513 if (obj->u.user.has && obj->u.user.has(J, obj->u.user.data, name))
514 return 1;
515 }
516
517 ref = jsV_getproperty(J, obj, name);
518 if (ref) {
519 if (ref->getter) {
520 js_pushobject(J, ref->getter);
521 js_pushobject(J, obj);
522 js_call(J, 0);
523 } else {
524 js_pushvalue(J, ref->value);
525 }
526 return 1;
527 }
528
529 return 0;
530 }
531
jsR_getproperty(js_State * J,js_Object * obj,const char * name)532 static void jsR_getproperty(js_State *J, js_Object *obj, const char *name)
533 {
534 if (!jsR_hasproperty(J, obj, name))
535 js_pushundefined(J);
536 }
537
jsR_setproperty(js_State * J,js_Object * obj,const char * name)538 static void jsR_setproperty(js_State *J, js_Object *obj, const char *name)
539 {
540 js_Value *value = stackidx(J, -1);
541 js_Property *ref;
542 int k;
543 int own;
544
545 if (obj->type == JS_CARRAY) {
546 if (!strcmp(name, "length")) {
547 double rawlen = jsV_tonumber(J, value);
548 int newlen = jsV_numbertointeger(rawlen);
549 if (newlen != rawlen || newlen < 0)
550 js_rangeerror(J, "array length");
551 jsV_resizearray(J, obj, newlen);
552 return;
553 }
554 if (js_isarrayindex(J, name, &k))
555 if (k >= obj->u.a.length)
556 obj->u.a.length = k + 1;
557 }
558
559 else if (obj->type == JS_CSTRING) {
560 if (!strcmp(name, "length"))
561 goto readonly;
562 if (js_isarrayindex(J, name, &k))
563 if (k >= 0 && k < obj->u.s.length)
564 goto readonly;
565 }
566
567 else if (obj->type == JS_CREGEXP) {
568 if (!strcmp(name, "source")) goto readonly;
569 if (!strcmp(name, "global")) goto readonly;
570 if (!strcmp(name, "ignoreCase")) goto readonly;
571 if (!strcmp(name, "multiline")) goto readonly;
572 if (!strcmp(name, "lastIndex")) {
573 obj->u.r.last = jsV_tointeger(J, value);
574 return;
575 }
576 }
577
578 else if (obj->type == JS_CUSERDATA) {
579 if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
580 return;
581 }
582
583 /* First try to find a setter in prototype chain */
584 ref = jsV_getpropertyx(J, obj, name, &own);
585 if (ref) {
586 if (ref->setter) {
587 js_pushobject(J, ref->setter);
588 js_pushobject(J, obj);
589 js_pushvalue(J, *value);
590 js_call(J, 1);
591 js_pop(J, 1);
592 return;
593 } else {
594 if (J->strict)
595 if (ref->getter)
596 js_typeerror(J, "setting property '%s' that only has a getter", name);
597 }
598 }
599
600 /* Property not found on this object, so create one */
601 if (!ref || !own)
602 ref = jsV_setproperty(J, obj, name);
603
604 if (ref) {
605 if (!(ref->atts & JS_READONLY))
606 ref->value = *value;
607 else
608 goto readonly;
609 }
610
611 return;
612
613 readonly:
614 if (J->strict)
615 js_typeerror(J, "'%s' is read-only", name);
616 }
617
jsR_defproperty(js_State * J,js_Object * obj,const char * name,int atts,js_Value * value,js_Object * getter,js_Object * setter)618 static void jsR_defproperty(js_State *J, js_Object *obj, const char *name,
619 int atts, js_Value *value, js_Object *getter, js_Object *setter)
620 {
621 js_Property *ref;
622 int k;
623
624 if (obj->type == JS_CARRAY) {
625 if (!strcmp(name, "length"))
626 goto readonly;
627 }
628
629 else if (obj->type == JS_CSTRING) {
630 if (!strcmp(name, "length"))
631 goto readonly;
632 if (js_isarrayindex(J, name, &k))
633 if (k >= 0 && k < obj->u.s.length)
634 goto readonly;
635 }
636
637 else if (obj->type == JS_CREGEXP) {
638 if (!strcmp(name, "source")) goto readonly;
639 if (!strcmp(name, "global")) goto readonly;
640 if (!strcmp(name, "ignoreCase")) goto readonly;
641 if (!strcmp(name, "multiline")) goto readonly;
642 if (!strcmp(name, "lastIndex")) goto readonly;
643 }
644
645 else if (obj->type == JS_CUSERDATA) {
646 if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
647 return;
648 }
649
650 ref = jsV_setproperty(J, obj, name);
651 if (ref) {
652 if (value) {
653 if (!(ref->atts & JS_READONLY))
654 ref->value = *value;
655 else if (J->strict)
656 js_typeerror(J, "'%s' is read-only", name);
657 }
658 if (getter) {
659 if (!(ref->atts & JS_DONTCONF))
660 ref->getter = getter;
661 else if (J->strict)
662 js_typeerror(J, "'%s' is non-configurable", name);
663 }
664 if (setter) {
665 if (!(ref->atts & JS_DONTCONF))
666 ref->setter = setter;
667 else if (J->strict)
668 js_typeerror(J, "'%s' is non-configurable", name);
669 }
670 ref->atts |= atts;
671 }
672
673 return;
674
675 readonly:
676 if (J->strict)
677 js_typeerror(J, "'%s' is read-only or non-configurable", name);
678 }
679
jsR_delproperty(js_State * J,js_Object * obj,const char * name)680 static int jsR_delproperty(js_State *J, js_Object *obj, const char *name)
681 {
682 js_Property *ref;
683 int k;
684
685 if (obj->type == JS_CARRAY) {
686 if (!strcmp(name, "length"))
687 goto dontconf;
688 }
689
690 else if (obj->type == JS_CSTRING) {
691 if (!strcmp(name, "length"))
692 goto dontconf;
693 if (js_isarrayindex(J, name, &k))
694 if (k >= 0 && k < obj->u.s.length)
695 goto dontconf;
696 }
697
698 else if (obj->type == JS_CREGEXP) {
699 if (!strcmp(name, "source")) goto dontconf;
700 if (!strcmp(name, "global")) goto dontconf;
701 if (!strcmp(name, "ignoreCase")) goto dontconf;
702 if (!strcmp(name, "multiline")) goto dontconf;
703 if (!strcmp(name, "lastIndex")) goto dontconf;
704 }
705
706 else if (obj->type == JS_CUSERDATA) {
707 if (obj->u.user.delete && obj->u.user.delete(J, obj->u.user.data, name))
708 return 1;
709 }
710
711 ref = jsV_getownproperty(J, obj, name);
712 if (ref) {
713 if (ref->atts & JS_DONTCONF)
714 goto dontconf;
715 jsV_delproperty(J, obj, name);
716 }
717 return 1;
718
719 dontconf:
720 if (J->strict)
721 js_typeerror(J, "'%s' is non-configurable", name);
722 return 0;
723 }
724
725 /* Registry, global and object property accessors */
726
js_ref(js_State * J)727 const char *js_ref(js_State *J)
728 {
729 js_Value *v = stackidx(J, -1);
730 const char *s;
731 char buf[32];
732 switch (v->type) {
733 case JS_TUNDEFINED: s = "_Undefined"; break;
734 case JS_TNULL: s = "_Null"; break;
735 case JS_TBOOLEAN:
736 s = v->u.boolean ? "_True" : "_False";
737 break;
738 case JS_TOBJECT:
739 sprintf(buf, "%p", (void*)v->u.object);
740 s = js_intern(J, buf);
741 break;
742 default:
743 sprintf(buf, "%d", J->nextref++);
744 s = js_intern(J, buf);
745 break;
746 }
747 js_setregistry(J, s);
748 return s;
749 }
750
js_unref(js_State * J,const char * ref)751 void js_unref(js_State *J, const char *ref)
752 {
753 js_delregistry(J, ref);
754 }
755
js_getregistry(js_State * J,const char * name)756 void js_getregistry(js_State *J, const char *name)
757 {
758 jsR_getproperty(J, J->R, name);
759 }
760
js_setregistry(js_State * J,const char * name)761 void js_setregistry(js_State *J, const char *name)
762 {
763 jsR_setproperty(J, J->R, name);
764 js_pop(J, 1);
765 }
766
js_delregistry(js_State * J,const char * name)767 void js_delregistry(js_State *J, const char *name)
768 {
769 jsR_delproperty(J, J->R, name);
770 }
771
js_getglobal(js_State * J,const char * name)772 void js_getglobal(js_State *J, const char *name)
773 {
774 jsR_getproperty(J, J->G, name);
775 }
776
js_setglobal(js_State * J,const char * name)777 void js_setglobal(js_State *J, const char *name)
778 {
779 jsR_setproperty(J, J->G, name);
780 js_pop(J, 1);
781 }
782
js_defglobal(js_State * J,const char * name,int atts)783 void js_defglobal(js_State *J, const char *name, int atts)
784 {
785 jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL);
786 js_pop(J, 1);
787 }
788
js_getproperty(js_State * J,int idx,const char * name)789 void js_getproperty(js_State *J, int idx, const char *name)
790 {
791 jsR_getproperty(J, js_toobject(J, idx), name);
792 }
793
js_setproperty(js_State * J,int idx,const char * name)794 void js_setproperty(js_State *J, int idx, const char *name)
795 {
796 jsR_setproperty(J, js_toobject(J, idx), name);
797 js_pop(J, 1);
798 }
799
js_defproperty(js_State * J,int idx,const char * name,int atts)800 void js_defproperty(js_State *J, int idx, const char *name, int atts)
801 {
802 jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL);
803 js_pop(J, 1);
804 }
805
js_delproperty(js_State * J,int idx,const char * name)806 void js_delproperty(js_State *J, int idx, const char *name)
807 {
808 jsR_delproperty(J, js_toobject(J, idx), name);
809 }
810
js_defaccessor(js_State * J,int idx,const char * name,int atts)811 void js_defaccessor(js_State *J, int idx, const char *name, int atts)
812 {
813 jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1));
814 js_pop(J, 2);
815 }
816
js_hasproperty(js_State * J,int idx,const char * name)817 int js_hasproperty(js_State *J, int idx, const char *name)
818 {
819 return jsR_hasproperty(J, js_toobject(J, idx), name);
820 }
821
822 /* Iterator */
823
js_pushiterator(js_State * J,int idx,int own)824 void js_pushiterator(js_State *J, int idx, int own)
825 {
826 js_pushobject(J, jsV_newiterator(J, js_toobject(J, idx), own));
827 }
828
js_nextiterator(js_State * J,int idx)829 const char *js_nextiterator(js_State *J, int idx)
830 {
831 return jsV_nextiterator(J, js_toobject(J, idx));
832 }
833
834 /* Environment records */
835
jsR_newenvironment(js_State * J,js_Object * vars,js_Environment * outer)836 js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
837 {
838 js_Environment *E = js_malloc(J, sizeof *E);
839 E->gcmark = 0;
840 E->gcnext = J->gcenv;
841 J->gcenv = E;
842 ++J->gccounter;
843
844 E->outer = outer;
845 E->variables = vars;
846 return E;
847 }
848
js_initvar(js_State * J,const char * name,int idx)849 static void js_initvar(js_State *J, const char *name, int idx)
850 {
851 jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL);
852 }
853
js_defvar(js_State * J,const char * name)854 static void js_defvar(js_State *J, const char *name)
855 {
856 jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, NULL, NULL, NULL);
857 }
858
js_hasvar(js_State * J,const char * name)859 static int js_hasvar(js_State *J, const char *name)
860 {
861 js_Environment *E = J->E;
862 do {
863 js_Property *ref = jsV_getproperty(J, E->variables, name);
864 if (ref) {
865 if (ref->getter) {
866 js_pushobject(J, ref->getter);
867 js_pushobject(J, E->variables);
868 js_call(J, 0);
869 } else {
870 js_pushvalue(J, ref->value);
871 }
872 return 1;
873 }
874 E = E->outer;
875 } while (E);
876 return 0;
877 }
878
js_setvar(js_State * J,const char * name)879 static void js_setvar(js_State *J, const char *name)
880 {
881 js_Environment *E = J->E;
882 do {
883 js_Property *ref = jsV_getproperty(J, E->variables, name);
884 if (ref) {
885 if (ref->setter) {
886 js_pushobject(J, ref->setter);
887 js_pushobject(J, E->variables);
888 js_copy(J, -3);
889 js_call(J, 1);
890 js_pop(J, 1);
891 return;
892 }
893 if (!(ref->atts & JS_READONLY))
894 ref->value = *stackidx(J, -1);
895 else if (J->strict)
896 js_typeerror(J, "'%s' is read-only", name);
897 return;
898 }
899 E = E->outer;
900 } while (E);
901 if (J->strict)
902 js_referenceerror(J, "assignment to undeclared variable '%s'", name);
903 jsR_setproperty(J, J->G, name);
904 }
905
js_delvar(js_State * J,const char * name)906 static int js_delvar(js_State *J, const char *name)
907 {
908 js_Environment *E = J->E;
909 do {
910 js_Property *ref = jsV_getownproperty(J, E->variables, name);
911 if (ref) {
912 if (ref->atts & JS_DONTCONF) {
913 if (J->strict)
914 js_typeerror(J, "'%s' is non-configurable", name);
915 return 0;
916 }
917 jsV_delproperty(J, E->variables, name);
918 return 1;
919 }
920 E = E->outer;
921 } while (E);
922 return jsR_delproperty(J, J->G, name);
923 }
924
925 /* Function calls */
926
jsR_savescope(js_State * J,js_Environment * newE)927 static void jsR_savescope(js_State *J, js_Environment *newE)
928 {
929 if (J->envtop + 1 >= JS_ENVLIMIT)
930 js_stackoverflow(J);
931 J->envstack[J->envtop++] = J->E;
932 J->E = newE;
933 }
934
jsR_restorescope(js_State * J)935 static void jsR_restorescope(js_State *J)
936 {
937 J->E = J->envstack[--J->envtop];
938 }
939
jsR_calllwfunction(js_State * J,int n,js_Function * F,js_Environment * scope)940 static void jsR_calllwfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
941 {
942 js_Value v;
943 int i;
944
945 jsR_savescope(J, scope);
946
947 if (n > F->numparams) {
948 js_pop(J, n - F->numparams);
949 n = F->numparams;
950 }
951 for (i = n; i < F->varlen; ++i)
952 js_pushundefined(J);
953
954 jsR_run(J, F);
955 v = *stackidx(J, -1);
956 TOP = --BOT; /* clear stack */
957 js_pushvalue(J, v);
958
959 jsR_restorescope(J);
960 }
961
jsR_callfunction(js_State * J,int n,js_Function * F,js_Environment * scope)962 static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
963 {
964 js_Value v;
965 int i;
966
967 scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
968
969 jsR_savescope(J, scope);
970
971 if (F->arguments) {
972 js_newobject(J);
973 if (!J->strict) {
974 js_currentfunction(J);
975 js_defproperty(J, -2, "callee", JS_DONTENUM);
976 }
977 js_pushnumber(J, n);
978 js_defproperty(J, -2, "length", JS_DONTENUM);
979 for (i = 0; i < n; ++i) {
980 js_copy(J, i + 1);
981 js_setindex(J, -2, i);
982 }
983 js_initvar(J, "arguments", -1);
984 js_pop(J, 1);
985 }
986
987 for (i = 0; i < F->numparams; ++i) {
988 if (i < n)
989 js_initvar(J, F->vartab[i], i + 1);
990 else {
991 js_pushundefined(J);
992 js_initvar(J, F->vartab[i], -1);
993 js_pop(J, 1);
994 }
995 }
996 js_pop(J, n);
997
998 jsR_run(J, F);
999 v = *stackidx(J, -1);
1000 TOP = --BOT; /* clear stack */
1001 js_pushvalue(J, v);
1002
1003 jsR_restorescope(J);
1004 }
1005
jsR_callscript(js_State * J,int n,js_Function * F,js_Environment * scope)1006 static void jsR_callscript(js_State *J, int n, js_Function *F, js_Environment *scope)
1007 {
1008 js_Value v;
1009
1010 if (scope)
1011 jsR_savescope(J, scope);
1012
1013 js_pop(J, n);
1014 jsR_run(J, F);
1015 v = *stackidx(J, -1);
1016 TOP = --BOT; /* clear stack */
1017 js_pushvalue(J, v);
1018
1019 if (scope)
1020 jsR_restorescope(J);
1021 }
1022
jsR_callcfunction(js_State * J,int n,int min,js_CFunction F)1023 static void jsR_callcfunction(js_State *J, int n, int min, js_CFunction F)
1024 {
1025 int i;
1026 js_Value v;
1027
1028 for (i = n; i < min; ++i)
1029 js_pushundefined(J);
1030
1031 F(J);
1032 v = *stackidx(J, -1);
1033 TOP = --BOT; /* clear stack */
1034 js_pushvalue(J, v);
1035 }
1036
jsR_pushtrace(js_State * J,const char * name,const char * file,int line)1037 static void jsR_pushtrace(js_State *J, const char *name, const char *file, int line)
1038 {
1039 if (J->tracetop + 1 == JS_ENVLIMIT)
1040 js_error(J, "call stack overflow");
1041 ++J->tracetop;
1042 J->trace[J->tracetop].name = name;
1043 J->trace[J->tracetop].file = file;
1044 J->trace[J->tracetop].line = line;
1045 }
1046
js_call(js_State * J,int n)1047 void js_call(js_State *J, int n)
1048 {
1049 js_Object *obj;
1050 int savebot;
1051
1052 if (!js_iscallable(J, -n-2))
1053 js_typeerror(J, "called object is not a function");
1054
1055 obj = js_toobject(J, -n-2);
1056
1057 savebot = BOT;
1058 BOT = TOP - n - 1;
1059
1060 if (obj->type == JS_CFUNCTION) {
1061 jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
1062 if (obj->u.f.function->lightweight)
1063 jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope);
1064 else
1065 jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope);
1066 --J->tracetop;
1067 } else if (obj->type == JS_CSCRIPT) {
1068 jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
1069 jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope);
1070 --J->tracetop;
1071 } else if (obj->type == JS_CCFUNCTION) {
1072 jsR_pushtrace(J, obj->u.c.name, "native", 0);
1073 jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function);
1074 --J->tracetop;
1075 }
1076
1077 BOT = savebot;
1078 }
1079
js_construct(js_State * J,int n)1080 void js_construct(js_State *J, int n)
1081 {
1082 js_Object *obj;
1083 js_Object *prototype;
1084 js_Object *newobj;
1085
1086 if (!js_iscallable(J, -n-1))
1087 js_typeerror(J, "called object is not a function");
1088
1089 obj = js_toobject(J, -n-1);
1090
1091 /* built-in constructors create their own objects, give them a 'null' this */
1092 if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) {
1093 int savebot = BOT;
1094 js_pushnull(J);
1095 if (n > 0)
1096 js_rot(J, n + 1);
1097 BOT = TOP - n - 1;
1098
1099 jsR_pushtrace(J, obj->u.c.name, "native", 0);
1100 jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor);
1101 --J->tracetop;
1102
1103 BOT = savebot;
1104 return;
1105 }
1106
1107 /* extract the function object's prototype property */
1108 js_getproperty(J, -n - 1, "prototype");
1109 if (js_isobject(J, -1))
1110 prototype = js_toobject(J, -1);
1111 else
1112 prototype = J->Object_prototype;
1113 js_pop(J, 1);
1114
1115 /* create a new object with above prototype, and shift it into the 'this' slot */
1116 newobj = jsV_newobject(J, JS_COBJECT, prototype);
1117 js_pushobject(J, newobj);
1118 if (n > 0)
1119 js_rot(J, n + 1);
1120
1121 /* call the function */
1122 js_call(J, n);
1123
1124 /* if result is not an object, return the original object we created */
1125 if (!js_isobject(J, -1)) {
1126 js_pop(J, 1);
1127 js_pushobject(J, newobj);
1128 }
1129 }
1130
js_eval(js_State * J)1131 void js_eval(js_State *J)
1132 {
1133 if (!js_isstring(J, -1))
1134 return;
1135 js_loadeval(J, "(eval)", js_tostring(J, -1));
1136 js_rot2pop1(J);
1137 js_copy(J, 0); /* copy 'this' */
1138 js_call(J, 0);
1139 }
1140
js_pconstruct(js_State * J,int n)1141 int js_pconstruct(js_State *J, int n)
1142 {
1143 int savetop = TOP - n - 2;
1144 if (js_try(J)) {
1145 /* clean up the stack to only hold the error object */
1146 STACK[savetop] = STACK[TOP-1];
1147 TOP = savetop + 1;
1148 return 1;
1149 }
1150 js_construct(J, n);
1151 js_endtry(J);
1152 return 0;
1153 }
1154
js_pcall(js_State * J,int n)1155 int js_pcall(js_State *J, int n)
1156 {
1157 int savetop = TOP - n - 2;
1158 if (js_try(J)) {
1159 /* clean up the stack to only hold the error object */
1160 STACK[savetop] = STACK[TOP-1];
1161 TOP = savetop + 1;
1162 return 1;
1163 }
1164 js_call(J, n);
1165 js_endtry(J);
1166 return 0;
1167 }
1168
1169 /* Exceptions */
1170
js_savetrypc(js_State * J,js_Instruction * pc)1171 void *js_savetrypc(js_State *J, js_Instruction *pc)
1172 {
1173 if (J->trytop == JS_TRYLIMIT)
1174 js_error(J, "try: exception stack overflow");
1175 J->trybuf[J->trytop].E = J->E;
1176 J->trybuf[J->trytop].envtop = J->envtop;
1177 J->trybuf[J->trytop].tracetop = J->tracetop;
1178 J->trybuf[J->trytop].top = J->top;
1179 J->trybuf[J->trytop].bot = J->bot;
1180 J->trybuf[J->trytop].strict = J->strict;
1181 J->trybuf[J->trytop].pc = pc;
1182 return J->trybuf[J->trytop++].buf;
1183 }
1184
js_savetry(js_State * J)1185 void *js_savetry(js_State *J)
1186 {
1187 if (J->trytop == JS_TRYLIMIT)
1188 js_error(J, "try: exception stack overflow");
1189 J->trybuf[J->trytop].E = J->E;
1190 J->trybuf[J->trytop].envtop = J->envtop;
1191 J->trybuf[J->trytop].tracetop = J->tracetop;
1192 J->trybuf[J->trytop].top = J->top;
1193 J->trybuf[J->trytop].bot = J->bot;
1194 J->trybuf[J->trytop].strict = J->strict;
1195 J->trybuf[J->trytop].pc = NULL;
1196 return J->trybuf[J->trytop++].buf;
1197 }
1198
js_endtry(js_State * J)1199 void js_endtry(js_State *J)
1200 {
1201 if (J->trytop == 0)
1202 js_error(J, "endtry: exception stack underflow");
1203 --J->trytop;
1204 }
1205
js_throw(js_State * J)1206 void js_throw(js_State *J)
1207 {
1208 if (J->trytop > 0) {
1209 js_Value v = *stackidx(J, -1);
1210 --J->trytop;
1211 J->E = J->trybuf[J->trytop].E;
1212 J->envtop = J->trybuf[J->trytop].envtop;
1213 J->tracetop = J->trybuf[J->trytop].tracetop;
1214 J->top = J->trybuf[J->trytop].top;
1215 J->bot = J->trybuf[J->trytop].bot;
1216 J->strict = J->trybuf[J->trytop].strict;
1217 js_pushvalue(J, v);
1218 longjmp(J->trybuf[J->trytop].buf, 1);
1219 }
1220 if (J->panic)
1221 J->panic(J);
1222 abort();
1223 }
1224
1225 /* Main interpreter loop */
1226
jsR_dumpstack(js_State * J)1227 static void jsR_dumpstack(js_State *J)
1228 {
1229 int i;
1230 printf("stack {\n");
1231 for (i = 0; i < TOP; ++i) {
1232 putchar(i == BOT ? '>' : ' ');
1233 printf("% 4d: ", i);
1234 js_dumpvalue(J, STACK[i]);
1235 putchar('\n');
1236 }
1237 printf("}\n");
1238 }
1239
jsR_dumpenvironment(js_State * J,js_Environment * E,int d)1240 static void jsR_dumpenvironment(js_State *J, js_Environment *E, int d)
1241 {
1242 printf("scope %d ", d);
1243 js_dumpobject(J, E->variables);
1244 if (E->outer)
1245 jsR_dumpenvironment(J, E->outer, d+1);
1246 }
1247
js_stacktrace(js_State * J)1248 void js_stacktrace(js_State *J)
1249 {
1250 int n;
1251 printf("stack trace:\n");
1252 for (n = J->tracetop; n >= 0; --n) {
1253 const char *name = J->trace[n].name;
1254 const char *file = J->trace[n].file;
1255 int line = J->trace[n].line;
1256 if (line > 0) {
1257 if (name[0])
1258 printf("\tat %s (%s:%d)\n", name, file, line);
1259 else
1260 printf("\tat %s:%d\n", file, line);
1261 } else
1262 printf("\tat %s (%s)\n", name, file);
1263 }
1264 }
1265
js_trap(js_State * J,int pc)1266 void js_trap(js_State *J, int pc)
1267 {
1268 if (pc > 0) {
1269 js_Function *F = STACK[BOT-1].u.object->u.f.function;
1270 printf("trap at %d in function ", pc);
1271 jsC_dumpfunction(J, F);
1272 }
1273 jsR_dumpstack(J);
1274 jsR_dumpenvironment(J, J->E, 0);
1275 js_stacktrace(J);
1276 }
1277
jsR_run(js_State * J,js_Function * F)1278 static void jsR_run(js_State *J, js_Function *F)
1279 {
1280 js_Function **FT = F->funtab;
1281 double *NT = F->numtab;
1282 const char **ST = F->strtab;
1283 js_Instruction *pcstart = F->code;
1284 js_Instruction *pc = F->code;
1285 enum js_OpCode opcode;
1286 int offset;
1287 int savestrict;
1288
1289 const char *str;
1290 js_Object *obj;
1291 double x, y;
1292 unsigned int ux, uy;
1293 int ix, iy, okay;
1294 int b;
1295
1296 savestrict = J->strict;
1297 J->strict = F->strict;
1298
1299 while (1) {
1300 if (J->gccounter > JS_GCLIMIT) {
1301 J->gccounter = 0;
1302 js_gc(J, 0);
1303 }
1304
1305 opcode = *pc++;
1306 switch (opcode) {
1307 case OP_POP: js_pop(J, 1); break;
1308 case OP_DUP: js_dup(J); break;
1309 case OP_DUP2: js_dup2(J); break;
1310 case OP_ROT2: js_rot2(J); break;
1311 case OP_ROT3: js_rot3(J); break;
1312 case OP_ROT4: js_rot4(J); break;
1313
1314 case OP_NUMBER_0: js_pushnumber(J, 0); break;
1315 case OP_NUMBER_1: js_pushnumber(J, 1); break;
1316 case OP_NUMBER_POS: js_pushnumber(J, *pc++); break;
1317 case OP_NUMBER_NEG: js_pushnumber(J, -(*pc++)); break;
1318 case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
1319 case OP_STRING: js_pushliteral(J, ST[*pc++]); break;
1320
1321 case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
1322 case OP_NEWOBJECT: js_newobject(J); break;
1323 case OP_NEWARRAY: js_newarray(J); break;
1324 case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break;
1325
1326 case OP_UNDEF: js_pushundefined(J); break;
1327 case OP_NULL: js_pushnull(J); break;
1328 case OP_TRUE: js_pushboolean(J, 1); break;
1329 case OP_FALSE: js_pushboolean(J, 0); break;
1330
1331 case OP_THIS:
1332 if (J->strict) {
1333 js_copy(J, 0);
1334 } else {
1335 if (js_iscoercible(J, 0))
1336 js_copy(J, 0);
1337 else
1338 js_pushglobal(J);
1339 }
1340 break;
1341
1342 case OP_CURRENT:
1343 js_currentfunction(J);
1344 break;
1345
1346 case OP_INITLOCAL:
1347 STACK[BOT + *pc++] = STACK[--TOP];
1348 break;
1349
1350 case OP_GETLOCAL:
1351 CHECKSTACK(1);
1352 STACK[TOP++] = STACK[BOT + *pc++];
1353 break;
1354
1355 case OP_SETLOCAL:
1356 STACK[BOT + *pc++] = STACK[TOP-1];
1357 break;
1358
1359 case OP_DELLOCAL:
1360 ++pc;
1361 js_pushboolean(J, 0);
1362 break;
1363
1364 case OP_INITVAR:
1365 js_initvar(J, ST[*pc++], -1);
1366 js_pop(J, 1);
1367 break;
1368
1369 case OP_DEFVAR:
1370 js_defvar(J, ST[*pc++]);
1371 break;
1372
1373 case OP_GETVAR:
1374 str = ST[*pc++];
1375 if (!js_hasvar(J, str))
1376 js_referenceerror(J, "'%s' is not defined", str);
1377 break;
1378
1379 case OP_HASVAR:
1380 if (!js_hasvar(J, ST[*pc++]))
1381 js_pushundefined(J);
1382 break;
1383
1384 case OP_SETVAR:
1385 js_setvar(J, ST[*pc++]);
1386 break;
1387
1388 case OP_DELVAR:
1389 b = js_delvar(J, ST[*pc++]);
1390 js_pushboolean(J, b);
1391 break;
1392
1393 case OP_IN:
1394 str = js_tostring(J, -2);
1395 if (!js_isobject(J, -1))
1396 js_typeerror(J, "operand to 'in' is not an object");
1397 b = js_hasproperty(J, -1, str);
1398 js_pop(J, 2 + b);
1399 js_pushboolean(J, b);
1400 break;
1401
1402 case OP_INITPROP:
1403 obj = js_toobject(J, -3);
1404 str = js_tostring(J, -2);
1405 jsR_setproperty(J, obj, str);
1406 js_pop(J, 2);
1407 break;
1408
1409 case OP_INITGETTER:
1410 obj = js_toobject(J, -3);
1411 str = js_tostring(J, -2);
1412 jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL);
1413 js_pop(J, 2);
1414 break;
1415
1416 case OP_INITSETTER:
1417 obj = js_toobject(J, -3);
1418 str = js_tostring(J, -2);
1419 jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1));
1420 js_pop(J, 2);
1421 break;
1422
1423 case OP_GETPROP:
1424 str = js_tostring(J, -1);
1425 obj = js_toobject(J, -2);
1426 jsR_getproperty(J, obj, str);
1427 js_rot3pop2(J);
1428 break;
1429
1430 case OP_GETPROP_S:
1431 str = ST[*pc++];
1432 obj = js_toobject(J, -1);
1433 jsR_getproperty(J, obj, str);
1434 js_rot2pop1(J);
1435 break;
1436
1437 case OP_SETPROP:
1438 str = js_tostring(J, -2);
1439 obj = js_toobject(J, -3);
1440 jsR_setproperty(J, obj, str);
1441 js_rot3pop2(J);
1442 break;
1443
1444 case OP_SETPROP_S:
1445 str = ST[*pc++];
1446 obj = js_toobject(J, -2);
1447 jsR_setproperty(J, obj, str);
1448 js_rot2pop1(J);
1449 break;
1450
1451 case OP_DELPROP:
1452 str = js_tostring(J, -1);
1453 obj = js_toobject(J, -2);
1454 b = jsR_delproperty(J, obj, str);
1455 js_pop(J, 2);
1456 js_pushboolean(J, b);
1457 break;
1458
1459 case OP_DELPROP_S:
1460 str = ST[*pc++];
1461 obj = js_toobject(J, -1);
1462 b = jsR_delproperty(J, obj, str);
1463 js_pop(J, 1);
1464 js_pushboolean(J, b);
1465 break;
1466
1467 case OP_ITERATOR:
1468 if (!js_isundefined(J, -1) && !js_isnull(J, -1)) {
1469 obj = jsV_newiterator(J, js_toobject(J, -1), 0);
1470 js_pop(J, 1);
1471 js_pushobject(J, obj);
1472 }
1473 break;
1474
1475 case OP_NEXTITER:
1476 obj = js_toobject(J, -1);
1477 str = jsV_nextiterator(J, obj);
1478 if (str) {
1479 js_pushliteral(J, str);
1480 js_pushboolean(J, 1);
1481 } else {
1482 js_pop(J, 1);
1483 js_pushboolean(J, 0);
1484 }
1485 break;
1486
1487 /* Function calls */
1488
1489 case OP_EVAL:
1490 js_eval(J);
1491 break;
1492
1493 case OP_CALL:
1494 js_call(J, *pc++);
1495 break;
1496
1497 case OP_NEW:
1498 js_construct(J, *pc++);
1499 break;
1500
1501 /* Unary operators */
1502
1503 case OP_TYPEOF:
1504 str = js_typeof(J, -1);
1505 js_pop(J, 1);
1506 js_pushliteral(J, str);
1507 break;
1508
1509 case OP_POS:
1510 x = js_tonumber(J, -1);
1511 js_pop(J, 1);
1512 js_pushnumber(J, x);
1513 break;
1514
1515 case OP_NEG:
1516 x = js_tonumber(J, -1);
1517 js_pop(J, 1);
1518 js_pushnumber(J, -x);
1519 break;
1520
1521 case OP_BITNOT:
1522 ix = js_toint32(J, -1);
1523 js_pop(J, 1);
1524 js_pushnumber(J, ~ix);
1525 break;
1526
1527 case OP_LOGNOT:
1528 b = js_toboolean(J, -1);
1529 js_pop(J, 1);
1530 js_pushboolean(J, !b);
1531 break;
1532
1533 case OP_INC:
1534 x = js_tonumber(J, -1);
1535 js_pop(J, 1);
1536 js_pushnumber(J, x + 1);
1537 break;
1538
1539 case OP_DEC:
1540 x = js_tonumber(J, -1);
1541 js_pop(J, 1);
1542 js_pushnumber(J, x - 1);
1543 break;
1544
1545 case OP_POSTINC:
1546 x = js_tonumber(J, -1);
1547 js_pop(J, 1);
1548 js_pushnumber(J, x + 1);
1549 js_pushnumber(J, x);
1550 break;
1551
1552 case OP_POSTDEC:
1553 x = js_tonumber(J, -1);
1554 js_pop(J, 1);
1555 js_pushnumber(J, x - 1);
1556 js_pushnumber(J, x);
1557 break;
1558
1559 /* Multiplicative operators */
1560
1561 case OP_MUL:
1562 x = js_tonumber(J, -2);
1563 y = js_tonumber(J, -1);
1564 js_pop(J, 2);
1565 js_pushnumber(J, x * y);
1566 break;
1567
1568 case OP_DIV:
1569 x = js_tonumber(J, -2);
1570 y = js_tonumber(J, -1);
1571 js_pop(J, 2);
1572 js_pushnumber(J, x / y);
1573 break;
1574
1575 case OP_MOD:
1576 x = js_tonumber(J, -2);
1577 y = js_tonumber(J, -1);
1578 js_pop(J, 2);
1579 js_pushnumber(J, fmod(x, y));
1580 break;
1581
1582 /* Additive operators */
1583
1584 case OP_ADD:
1585 js_concat(J);
1586 break;
1587
1588 case OP_SUB:
1589 x = js_tonumber(J, -2);
1590 y = js_tonumber(J, -1);
1591 js_pop(J, 2);
1592 js_pushnumber(J, x - y);
1593 break;
1594
1595 /* Shift operators */
1596
1597 case OP_SHL:
1598 ix = js_toint32(J, -2);
1599 uy = js_touint32(J, -1);
1600 js_pop(J, 2);
1601 js_pushnumber(J, ix << (uy & 0x1F));
1602 break;
1603
1604 case OP_SHR:
1605 ix = js_toint32(J, -2);
1606 uy = js_touint32(J, -1);
1607 js_pop(J, 2);
1608 js_pushnumber(J, ix >> (uy & 0x1F));
1609 break;
1610
1611 case OP_USHR:
1612 ux = js_touint32(J, -2);
1613 uy = js_touint32(J, -1);
1614 js_pop(J, 2);
1615 js_pushnumber(J, ux >> (uy & 0x1F));
1616 break;
1617
1618 /* Relational operators */
1619
1620 case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break;
1621 case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break;
1622 case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break;
1623 case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break;
1624
1625 case OP_INSTANCEOF:
1626 b = js_instanceof(J);
1627 js_pop(J, 2);
1628 js_pushboolean(J, b);
1629 break;
1630
1631 /* Equality */
1632
1633 case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break;
1634 case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
1635 case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break;
1636 case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
1637
1638 case OP_JCASE:
1639 offset = *pc++;
1640 b = js_strictequal(J);
1641 if (b) {
1642 js_pop(J, 2);
1643 pc = pcstart + offset;
1644 } else {
1645 js_pop(J, 1);
1646 }
1647 break;
1648
1649 /* Binary bitwise operators */
1650
1651 case OP_BITAND:
1652 ix = js_toint32(J, -2);
1653 iy = js_toint32(J, -1);
1654 js_pop(J, 2);
1655 js_pushnumber(J, ix & iy);
1656 break;
1657
1658 case OP_BITXOR:
1659 ix = js_toint32(J, -2);
1660 iy = js_toint32(J, -1);
1661 js_pop(J, 2);
1662 js_pushnumber(J, ix ^ iy);
1663 break;
1664
1665 case OP_BITOR:
1666 ix = js_toint32(J, -2);
1667 iy = js_toint32(J, -1);
1668 js_pop(J, 2);
1669 js_pushnumber(J, ix | iy);
1670 break;
1671
1672 /* Try and Catch */
1673
1674 case OP_THROW:
1675 js_throw(J);
1676
1677 case OP_TRY:
1678 offset = *pc++;
1679 if (js_trypc(J, pc)) {
1680 pc = J->trybuf[J->trytop].pc;
1681 } else {
1682 pc = pcstart + offset;
1683 }
1684 break;
1685
1686 case OP_ENDTRY:
1687 js_endtry(J);
1688 break;
1689
1690 case OP_CATCH:
1691 str = ST[*pc++];
1692 obj = jsV_newobject(J, JS_COBJECT, NULL);
1693 js_pushobject(J, obj);
1694 js_rot2(J);
1695 js_setproperty(J, -2, str);
1696 J->E = jsR_newenvironment(J, obj, J->E);
1697 js_pop(J, 1);
1698 break;
1699
1700 case OP_ENDCATCH:
1701 J->E = J->E->outer;
1702 break;
1703
1704 /* With */
1705
1706 case OP_WITH:
1707 obj = js_toobject(J, -1);
1708 J->E = jsR_newenvironment(J, obj, J->E);
1709 js_pop(J, 1);
1710 break;
1711
1712 case OP_ENDWITH:
1713 J->E = J->E->outer;
1714 break;
1715
1716 /* Branching */
1717
1718 case OP_DEBUGGER:
1719 js_trap(J, (int)(pc - pcstart) - 1);
1720 break;
1721
1722 case OP_JUMP:
1723 pc = pcstart + *pc;
1724 break;
1725
1726 case OP_JTRUE:
1727 offset = *pc++;
1728 b = js_toboolean(J, -1);
1729 js_pop(J, 1);
1730 if (b)
1731 pc = pcstart + offset;
1732 break;
1733
1734 case OP_JFALSE:
1735 offset = *pc++;
1736 b = js_toboolean(J, -1);
1737 js_pop(J, 1);
1738 if (!b)
1739 pc = pcstart + offset;
1740 break;
1741
1742 case OP_RETURN:
1743 J->strict = savestrict;
1744 return;
1745
1746 case OP_LINE:
1747 J->trace[J->tracetop].line = *pc++;
1748 break;
1749 }
1750 }
1751 }
1752