Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
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
}
1646
1647