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