0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2006 by Digital Mars
|
|
5 * All Rights Reserved
|
|
6 * written by Walter Bright
|
|
7 * www.digitalmars.com
|
|
8 * Use at your own risk. There is no warranty, express or implied.
|
|
9 * License for redistribution is by the GNU General Public License in gpl.txt.
|
|
10 *
|
|
11 * A binary, non-exclusive license for commercial use can be
|
|
12 * purchased from www.digitalmars.com/dscript/buy.html.
|
|
13 *
|
|
14 * DMDScript is implemented in the D Programming Language,
|
|
15 * www.digitalmars.com/d/
|
|
16 *
|
|
17 * For a C++ implementation of DMDScript, including COM support,
|
|
18 * see www.digitalmars.com/dscript/cppscript.html.
|
|
19 */
|
|
20
|
|
21
|
|
22 module dmdscript.opcodes;
|
|
23
|
|
24 import std.stdio;
|
|
25 import std.string;
|
|
26
|
|
27 import dmdscript.script;
|
|
28 import dmdscript.dobject;
|
|
29 import dmdscript.statement;
|
|
30 import dmdscript.functiondefinition;
|
|
31 import dmdscript.value;
|
|
32 import dmdscript.iterator;
|
|
33 import dmdscript.scopex;
|
|
34 import dmdscript.identifier;
|
|
35 import dmdscript.ir;
|
|
36 import dmdscript.errmsgs;
|
|
37 import dmdscript.property;
|
|
38 import dmdscript.ddeclaredfunction;
|
|
39 import dmdscript.dfunction;
|
|
40
|
|
41 //debug=VERIFY; // verify integrity of code
|
|
42
|
|
43 version = SCOPECACHING; // turn scope caching on
|
|
44 //version = SCOPECACHE_LOG; // log statistics on it
|
|
45
|
|
46 // Catch & Finally are "fake" Dobjects that sit in the scope
|
|
47 // chain to implement our exception handling context.
|
|
48
|
|
49 class Catch : Dobject
|
|
50 {
|
|
51 // This is so scope_get() will skip over these objects
|
|
52 Value* Get(d_string PropertyName) { return null; }
|
|
53 Value* Get(d_string PropertyName, uint hash) { return null; }
|
|
54
|
|
55 // This is so we can distinguish between a real Dobject
|
|
56 // and these fakers
|
|
57 d_string getTypeof() { return null; }
|
|
58
|
|
59 uint offset; // offset of CatchBlock
|
|
60 d_string name; // catch identifier
|
|
61
|
|
62 this(uint offset, d_string name)
|
|
63 {
|
|
64 super(null);
|
|
65 this.offset = offset;
|
|
66 this.name = name;
|
|
67 }
|
|
68
|
|
69 int isCatch() { return true; }
|
|
70 }
|
|
71
|
|
72 class Finally : Dobject
|
|
73 {
|
|
74 Value* Get(d_string PropertyName) { return null; }
|
|
75 Value* Get(d_string PropertyName, uint hash) { return null; }
|
|
76 d_string getTypeof() { return null; }
|
|
77
|
|
78 IR *finallyblock; // code for FinallyBlock
|
|
79
|
|
80 this(IR *finallyblock)
|
|
81 {
|
|
82 super(null);
|
|
83 this.finallyblock = finallyblock;
|
|
84 }
|
|
85
|
|
86 int isFinally() { return true; }
|
|
87 }
|
|
88
|
|
89
|
|
90 /************************
|
|
91 * Look for identifier in scope.
|
|
92 */
|
|
93
|
|
94 Value* scope_get(Dobject[] scopex, Identifier* id, Dobject *pthis)
|
|
95 { uint d;
|
|
96 Dobject o;
|
|
97 Value* v;
|
|
98
|
|
99 //writef("scope_get: scope = %p, scope.data = %p\n", scopex, scopex.data);
|
|
100 //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
|
|
101 d = scopex.length;
|
|
102 for (;;)
|
|
103 {
|
|
104 if (!d)
|
|
105 { v = null;
|
|
106 *pthis = null;
|
|
107 break;
|
|
108 }
|
|
109 d--;
|
|
110 o = scopex[d];
|
|
111 //writef("o = %x, hash = x%x, s = '%s'\n", o, hash, s);
|
|
112 v = o.Get(id);
|
|
113 if (v)
|
|
114 { *pthis = o;
|
|
115 break;
|
|
116 }
|
|
117 }
|
|
118 return v;
|
|
119 }
|
|
120
|
|
121 Value* scope_get_lambda(Dobject[] scopex, Identifier* id, Dobject *pthis)
|
|
122 { uint d;
|
|
123 Dobject o;
|
|
124 Value* v;
|
|
125
|
|
126 //writefln("scope_get_lambda: scope = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
|
|
127 d = scopex.length;
|
|
128 for (;;)
|
|
129 {
|
|
130 if (!d)
|
|
131 { v = null;
|
|
132 *pthis = null;
|
|
133 break;
|
|
134 }
|
|
135 d--;
|
|
136 o = scopex[d];
|
|
137 //printf("o = %p ", o);
|
|
138 //writefln("o = %s", o);
|
|
139 //printf("o = %x, hash = x%x, s = '%.*s'\n", o, hash, s);
|
|
140 //v = o.GetLambda(s, hash);
|
|
141 v = o.Get(id);
|
|
142 if (v)
|
|
143 { *pthis = o;
|
|
144 break;
|
|
145 }
|
|
146 }
|
|
147 //writefln("v = %x", cast(uint)cast(void*)v);
|
|
148 return v;
|
|
149 }
|
|
150
|
|
151 Value* scope_get(Dobject[] scopex, Identifier* id)
|
|
152 { uint d;
|
|
153 Dobject o;
|
|
154 Value* v;
|
|
155
|
|
156 //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
|
|
157 d = scopex.length;
|
|
158 // 1 is most common case for d
|
|
159 if (d == 1)
|
|
160 {
|
|
161 return scopex[0].Get(id);
|
|
162 }
|
|
163 for (;;)
|
|
164 {
|
|
165 if (!d)
|
|
166 { v = null;
|
|
167 break;
|
|
168 }
|
|
169 d--;
|
|
170 o = scopex[d];
|
|
171 //writefln("\to = %s", o);
|
|
172 v = o.Get(id);
|
|
173 if (v)
|
|
174 break;
|
|
175 //writefln("\tnot found");
|
|
176 }
|
|
177 return v;
|
|
178 }
|
|
179
|
|
180 /************************************
|
|
181 * Find last object in scopex, null if none.
|
|
182 */
|
|
183
|
|
184 Dobject scope_tos(Dobject[] scopex)
|
|
185 { uint d;
|
|
186 Dobject o;
|
|
187
|
|
188 for (d = scopex.length; d;)
|
|
189 {
|
|
190 d--;
|
|
191 o = scopex[d];
|
|
192 if (o.getTypeof() != null) // if not a Finally or a Catch
|
|
193 return o;
|
|
194 }
|
|
195 return null;
|
|
196 }
|
|
197
|
|
198 /*****************************************
|
|
199 */
|
|
200
|
|
201 void PutValue(CallContext *cc, d_string s, Value* a)
|
|
202 {
|
|
203 // ECMA v3 8.7.2
|
|
204 // Look for the object o in the scope chain.
|
|
205 // If we find it, put its value.
|
|
206 // If we don't find it, put it into the global object
|
|
207
|
|
208 uint d;
|
|
209 uint hash;
|
|
210 Value* v;
|
|
211 Dobject o;
|
|
212
|
|
213 d = cc.scopex.length;
|
|
214 if (d == cc.globalroot)
|
|
215 {
|
|
216 o = scope_tos(cc.scopex);
|
|
217 o.Put(s, a, 0);
|
|
218 return;
|
|
219 }
|
|
220
|
|
221 hash = Value.calcHash(s);
|
|
222
|
|
223 for (;; d--)
|
|
224 {
|
|
225 assert(d > 0);
|
|
226 o = cc.scopex[d - 1];
|
|
227 if (d == cc.globalroot)
|
|
228 {
|
|
229 o.Put(s, a, 0);
|
|
230 return;
|
|
231 }
|
|
232 v = o.Get(s, hash);
|
|
233 if (v)
|
|
234 {
|
|
235 // Overwrite existing property with new one
|
|
236 o.Put(s, a, 0);
|
|
237 break;
|
|
238 }
|
|
239 }
|
|
240 }
|
|
241
|
|
242
|
|
243 void PutValue(CallContext *cc, Identifier* id, Value* a)
|
|
244 {
|
|
245 // ECMA v3 8.7.2
|
|
246 // Look for the object o in the scope chain.
|
|
247 // If we find it, put its value.
|
|
248 // If we don't find it, put it into the global object
|
|
249
|
|
250 uint d;
|
|
251 Value* v;
|
|
252 Dobject o;
|
|
253
|
|
254 d = cc.scopex.length;
|
|
255 if (d == cc.globalroot)
|
|
256 {
|
|
257 o = scope_tos(cc.scopex);
|
|
258 }
|
|
259 else
|
|
260 {
|
|
261 for (;; d--)
|
|
262 {
|
|
263 assert(d > 0);
|
|
264 o = cc.scopex[d - 1];
|
|
265 if (d == cc.globalroot)
|
|
266 break;
|
|
267 v = o.Get(id);
|
|
268 if (v)
|
|
269 {
|
|
270 // Overwrite existing property with new one
|
|
271 break;
|
|
272 }
|
|
273 }
|
|
274 }
|
|
275 o.Put(id, a, 0);
|
|
276 }
|
|
277
|
|
278
|
|
279 /*****************************************
|
|
280 * Helper function for Values that cannot be converted to Objects.
|
|
281 */
|
|
282
|
|
283 Value* cannotConvert(Value* b, int linnum)
|
|
284 {
|
|
285 ErrInfo errinfo;
|
|
286
|
|
287 errinfo.linnum = linnum;
|
|
288 if (b.isUndefinedOrNull())
|
|
289 {
|
|
290 b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT4],
|
|
291 b.getType());
|
|
292 }
|
|
293 else
|
|
294 {
|
|
295 b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT2],
|
|
296 b.getType(), b.toString());
|
|
297 }
|
|
298 return b;
|
|
299 }
|
|
300
|
|
301 const uint INDEX_FACTOR = 16; // or 1
|
|
302
|
|
303 struct IR
|
|
304 {
|
|
305 union
|
|
306 {
|
|
307 struct
|
|
308 {
|
|
309 version (LittleEndian)
|
|
310 {
|
|
311 ubyte opcode;
|
|
312 ubyte padding;
|
|
313 ushort linnum;
|
|
314 }
|
|
315 else
|
|
316 {
|
|
317 ushort linnum;
|
|
318 ubyte padding;
|
|
319 ubyte opcode;
|
|
320 }
|
|
321 }
|
|
322 IR* code;
|
|
323 Value* value;
|
|
324 uint index; // index into local variable table
|
|
325 uint hash; // cached hash value
|
|
326 int offset;
|
|
327 Identifier* id;
|
|
328 d_boolean boolean;
|
|
329 Statement target; // used for backpatch fixups
|
|
330 Dobject object;
|
|
331 void* ptr;
|
|
332 }
|
|
333
|
|
334 /****************************
|
|
335 * This is the main interpreter loop.
|
|
336 */
|
|
337
|
|
338 static void *call(CallContext *cc, Dobject othis,
|
|
339 IR *code, Value* ret, Value* locals)
|
|
340 { Value* a;
|
|
341 Value* b;
|
|
342 Value* c;
|
|
343 Value* v;
|
|
344 Iterator *iter;
|
|
345 Identifier *id;
|
|
346 d_string s;
|
|
347 d_string s2;
|
|
348 d_number n;
|
|
349 d_boolean bo;
|
|
350 d_int32 i32;
|
|
351 d_uint32 u32;
|
|
352 d_boolean res;
|
|
353 tchar[] tx;
|
|
354 tchar[] ty;
|
|
355 Dobject o;
|
|
356 Dobject[] scopex;
|
|
357 uint dimsave;
|
|
358 uint offset;
|
|
359 Catch ca;
|
|
360 Finally f;
|
|
361 IR* codestart = code;
|
|
362 d_number inc;
|
|
363
|
|
364 /***************************************
|
|
365 * Cache for getscope's
|
|
366 */
|
|
367
|
|
368 version (SCOPECACHING)
|
|
369 {
|
|
370 struct ScopeCache
|
|
371 {
|
|
372 d_string s;
|
|
373 Value* v; // never null, and never from a Dcomobject
|
|
374 }
|
|
375 int si;
|
|
376 ScopeCache zero;
|
|
377 ScopeCache[16] scopecache;
|
|
378 version (SCOPECACHE_LOG) int scopecache_cnt = 0;
|
|
379
|
|
380 uint SCOPECACHE_SI(tchar* s) { return (cast(uint)(s)) & 15; }
|
|
381 void SCOPECACHE_CLEAR() { scopecache[] = zero; }
|
|
382 }
|
|
383 else
|
|
384 {
|
|
385 uint SCOPECACHE_SI(d_string s) { return 0; }
|
|
386 void SCOPECACHE_CLEAR() { }
|
|
387 }
|
|
388
|
|
389 version (all)
|
|
390 {
|
|
391 // Eliminate the scale factor of Value.sizeof by computing it at compile time
|
|
392 Value* GETa(IR* code) { return cast(Value*)(cast(void*)locals + (code + 1).index * (16 / INDEX_FACTOR)); }
|
|
393 Value* GETb(IR* code) { return cast(Value*)(cast(void*)locals + (code + 2).index * (16 / INDEX_FACTOR)); }
|
|
394 Value* GETc(IR* code) { return cast(Value*)(cast(void*)locals + (code + 3).index * (16 / INDEX_FACTOR)); }
|
|
395 Value* GETd(IR* code) { return cast(Value*)(cast(void*)locals + (code + 4).index * (16 / INDEX_FACTOR)); }
|
|
396 Value* GETe(IR* code) { return cast(Value*)(cast(void*)locals + (code + 5).index * (16 / INDEX_FACTOR)); }
|
|
397 }
|
|
398 else
|
|
399 {
|
|
400 Value* GETa(IR* code) { return &locals[(code + 1).index]; }
|
|
401 Value* GETb(IR* code) { return &locals[(code + 2).index]; }
|
|
402 Value* GETc(IR* code) { return &locals[(code + 3).index]; }
|
|
403 Value* GETd(IR* code) { return &locals[(code + 4).index]; }
|
|
404 Value* GETe(IR* code) { return &locals[(code + 5).index]; }
|
|
405 }
|
|
406
|
|
407 uint GETlinnum(IR* code) { return code.linnum; }
|
|
408
|
|
409 debug (VERIFY) uint checksum = IR.verify(__LINE__, code);
|
|
410
|
|
411 version (none)
|
|
412 {
|
|
413 writef("+printfunc\n");
|
|
414 printfunc(code);
|
|
415 writef("-printfunc\n");
|
|
416 }
|
|
417 scopex = cc.scopex;
|
|
418 //printf("call: scope = %p, length = %d\n", scopex.ptr, scopex.length);
|
|
419 dimsave = scopex.length;
|
|
420 //if (logflag)
|
|
421 // writef("IR.call(othis = %p, code = %p, locals = %p)\n",othis,code,locals);
|
|
422
|
|
423 debug
|
|
424 {
|
|
425 uint debug_scoperoot = cc.scoperoot;
|
|
426 uint debug_globalroot = cc.globalroot;
|
|
427 uint debug_scopedim = scopex.length;
|
|
428 uint debug_scopeallocdim = scopex.allocdim;
|
|
429 Dobject debug_global = cc.global;
|
|
430 Dobject debug_variable = cc.variable;
|
|
431
|
|
432 void** debug_pscoperootdata = cast(void**)mem.malloc((void*).sizeof*debug_scoperoot);
|
|
433 void** debug_pglobalrootdata = cast(void**)mem.malloc((void*).sizeof*debug_globalroot);
|
|
434
|
|
435 memcpy(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot);
|
|
436 memcpy(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot);
|
|
437 }
|
|
438
|
|
439 assert(code);
|
|
440 //Value.copy(ret, &vundefined);
|
|
441 assert(othis);
|
|
442
|
|
443 Lnext:
|
|
444 //writef("cc = %x, interrupt = %d\n", cc, cc.Interrupt);
|
|
445 if (cc.Interrupt) // see if script was interrupted
|
|
446 goto Linterrupt;
|
|
447 for (;;)
|
|
448 {
|
|
449 version (none)
|
|
450 {
|
|
451 writef("%2d:", code - codestart);
|
|
452 print(code - codestart, code);
|
|
453 }
|
|
454
|
|
455 debug
|
|
456 {
|
|
457 assert(scopex == cc.scopex);
|
|
458 assert(debug_scoperoot == cc.scoperoot);
|
|
459 assert(debug_globalroot == cc.globalroot);
|
|
460 assert(debug_global == cc.global);
|
|
461 assert(debug_variable == cc.variable);
|
|
462 assert(scopex.length >= debug_scoperoot);
|
|
463 assert(scopex.length >= debug_globalroot);
|
|
464 assert(scopex.length >= debug_scopedim);
|
|
465 assert(scopex.allocdim >= debug_scopeallocdim);
|
|
466 assert(0 == memcmp(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot));
|
|
467 assert(0 == memcmp(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot));
|
|
468 assert(scopex);
|
|
469 }
|
|
470
|
|
471
|
|
472 /+
|
|
473 v = &vundefined;
|
|
474 tx = v.getType();
|
|
475 assert(tx == TypeUndefined);
|
|
476 +/
|
|
477 //writef("\tIR%d:\n", code.opcode);
|
|
478 switch (code.opcode)
|
|
479 {
|
|
480 case IRerror:
|
|
481 assert(0);
|
|
482 break;
|
|
483
|
|
484 case IRnop:
|
|
485 code++;
|
|
486 break;
|
|
487
|
|
488 case IRget: // a = b.c
|
|
489 a = GETa(code);
|
|
490 b = GETb(code);
|
|
491 o = b.toObject();
|
|
492 if (!o)
|
|
493 {
|
|
494 a = cannotConvert(b, GETlinnum(code));
|
|
495 goto Lthrow;
|
|
496 }
|
|
497 c = GETc(code);
|
|
498 if (c.vtype == V_NUMBER &&
|
|
499 (i32 = cast(d_int32)c.number) == c.number &&
|
|
500 i32 >= 0)
|
|
501 {
|
|
502 //writef("IRget %d\n", i32);
|
|
503 v = o.Get(cast(d_uint32)i32, c);
|
|
504 }
|
|
505 else
|
|
506 {
|
|
507 s = c.toString();
|
|
508 v = o.Get(s);
|
|
509 }
|
|
510 if (!v)
|
|
511 v = &vundefined;
|
|
512 Value.copy(a,v);
|
|
513 code += 4;
|
|
514 break;
|
|
515
|
|
516 case IRput: // b.c = a
|
|
517 a = GETa(code);
|
|
518 b = GETb(code);
|
|
519 c = GETc(code);
|
|
520 if (c.vtype == V_NUMBER &&
|
|
521 (i32 = cast(d_int32)c.number) == c.number &&
|
|
522 i32 >= 0)
|
|
523 {
|
|
524 //writef("IRput %d\n", i32);
|
|
525 if (b.vtype == V_OBJECT)
|
|
526 a = b.object.Put(cast(d_uint32)i32, c, a, 0);
|
|
527 else
|
|
528 a = b.Put(cast(d_uint32)i32, c, a);
|
|
529 }
|
|
530 else
|
|
531 {
|
|
532 s = c.toString();
|
|
533 a = b.Put(s, a);
|
|
534 }
|
|
535 if (a) goto Lthrow;
|
|
536 code += 4;
|
|
537 break;
|
|
538
|
|
539 case IRgets: // a = b.s
|
|
540 a = GETa(code);
|
|
541 b = GETb(code);
|
|
542 s = (code + 3).id.value.string;
|
|
543 o = b.toObject();
|
|
544 if (!o)
|
|
545 {
|
|
546 //writef("%s %s.%s cannot convert to Object", b.getType(), b.toString(), s);
|
|
547 ErrInfo errinfo;
|
|
548 a = Dobject.RuntimeError(&errinfo,
|
|
549 errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT3],
|
|
550 b.getType(), b.toString(),
|
|
551 s);
|
|
552 goto Lthrow;
|
|
553 }
|
|
554 v = o.Get(s);
|
|
555 if (!v)
|
|
556 {
|
|
557 //writef("IRgets: %s.%s is undefined\n", b.getType(), d_string_ptr(s));
|
|
558 v = &vundefined;
|
|
559 }
|
|
560 Value.copy(a,v);
|
|
561 code += 4;
|
|
562 goto Lnext;
|
|
563
|
|
564 case IRgetscope: // a = s
|
|
565 a = GETa(code);
|
|
566 id = (code + 2).id;
|
|
567 s = id.value.string;
|
|
568 version (SCOPECACHING)
|
|
569 {
|
|
570 si = SCOPECACHE_SI(s.ptr);
|
|
571 if (s is scopecache[si].s)
|
|
572 {
|
|
573 version (SCOPECACHE_LOG) scopecache_cnt++;
|
|
574 Value.copy(a, scopecache[si].v);
|
|
575 code += 3;
|
|
576 break;
|
|
577 }
|
|
578 //writefln("miss %s, was %s, s.ptr = %x, cache.ptr = %x", s, scopecache[si].s, cast(uint)s.ptr, cast(uint)scopecache[si].s.ptr);
|
|
579 }
|
|
580 version (all)
|
|
581 {
|
|
582 // Inline scope_get() for speed
|
|
583 { uint d;
|
|
584
|
|
585 d = scopex.length;
|
|
586 // 1 is most common case for d
|
|
587 if (d == 1)
|
|
588 {
|
|
589 o = scopex[0];
|
|
590 v = o.Get(id);
|
|
591 }
|
|
592 else
|
|
593 {
|
|
594 o = null;
|
|
595 for (;;)
|
|
596 {
|
|
597 if (!d)
|
|
598 { v = null;
|
|
599 break;
|
|
600 }
|
|
601 d--;
|
|
602 o = scopex[d];
|
|
603 v = o.Get(id);
|
|
604 //writef("o = %x, v = %x\n", o, v);
|
|
605 if (v)
|
|
606 break;
|
|
607 }
|
|
608 }
|
|
609 }
|
|
610 if (!v)
|
|
611 v = &vundefined;
|
|
612 else
|
|
613 {
|
|
614 version (SCOPECACHING)
|
|
615 {
|
|
616 if (1) //!o.isDcomobject())
|
|
617 {
|
|
618 scopecache[si].s = s;
|
|
619 scopecache[si].v = v;
|
|
620 }
|
|
621 }
|
|
622 }
|
|
623 }
|
|
624 else
|
|
625 {
|
|
626 v = scope_get(scopex, id);
|
|
627 if (!v)
|
|
628 v = &vundefined;
|
|
629 }
|
|
630 //writef("v = %p\n", v);
|
|
631 //writef("v = %g\n", v.toNumber());
|
|
632 //writef("v = %s\n", d_string_ptr(v.toString()));
|
|
633 Value.copy(a, v);
|
|
634 code += 3;
|
|
635 break;
|
|
636
|
|
637 case IRaddass: // a = (b.c += a)
|
|
638 c = GETc(code);
|
|
639 s = c.toString();
|
|
640 goto Laddass;
|
|
641
|
|
642 case IRaddasss: // a = (b.s += a)
|
|
643 s = (code + 3).id.value.string;
|
|
644 Laddass:
|
|
645 b = GETb(code);
|
|
646 v = b.Get(s);
|
|
647 goto Laddass2;
|
|
648
|
|
649 case IRaddassscope: // a = (s += a)
|
|
650 b = null; // Needed for the b.Put() below to shutup a compiler use-without-init warning
|
|
651 id = (code + 2).id;
|
|
652 s = id.value.string;
|
|
653 version (SCOPECACHING)
|
|
654 {
|
|
655 si = SCOPECACHE_SI(s.ptr);
|
|
656 if (s is scopecache[si].s)
|
|
657 v = scopecache[si].v;
|
|
658 else
|
|
659 v = scope_get(scopex, id);
|
|
660 }
|
|
661 else
|
|
662 {
|
|
663 v = scope_get(scopex, id);
|
|
664 }
|
|
665 Laddass2:
|
|
666 a = GETa(code);
|
|
667 if (!v)
|
|
668 {
|
|
669 v = &vundefined;
|
|
670 a.putVundefined();
|
|
671 /+
|
|
672 if (b)
|
|
673 {
|
|
674 a = b.Put(s, v);
|
|
675 //if (a) goto Lthrow;
|
|
676 }
|
|
677 else
|
|
678 {
|
|
679 PutValue(cc, s, v);
|
|
680 }
|
|
681 +/
|
|
682 }
|
|
683 else if (a.vtype == V_NUMBER && v.vtype == V_NUMBER)
|
|
684 { a.number += v.number;
|
|
685 v.number = a.number;
|
|
686 }
|
|
687 else
|
|
688 {
|
|
689 v.toPrimitive(v, null);
|
|
690 a.toPrimitive(a, null);
|
|
691 if (v.isString())
|
|
692 {
|
|
693 s2 = v.toString() ~ a.toString();
|
|
694 a.putVstring(s2);
|
|
695 Value.copy(v, a);
|
|
696 }
|
|
697 else if (a.isString())
|
|
698 {
|
|
699 s2 = v.toString() ~ a.toString();
|
|
700 a.putVstring(s2);
|
|
701 Value.copy(v, a);
|
|
702 }
|
|
703 else
|
|
704 {
|
|
705 a.putVnumber(a.toNumber() + v.toNumber());
|
|
706 v.number = a.number;
|
|
707 }
|
|
708 }
|
|
709 code += 4;
|
|
710 break;
|
|
711
|
|
712 case IRputs: // b.s = a
|
|
713 a = GETa(code);
|
|
714 b = GETb(code);
|
|
715 o = b.toObject();
|
|
716 if (!o)
|
|
717 {
|
|
718 a = cannotConvert(b, GETlinnum(code));
|
|
719 goto Lthrow;
|
|
720 }
|
|
721 a = o.Put((code + 3).id.value.string, a, 0);
|
|
722 if (a) goto Lthrow;
|
|
723 code += 4;
|
|
724 goto Lnext;
|
|
725
|
|
726 case IRputscope: // s = a
|
|
727 PutValue(cc, (code + 2).id, GETa(code));
|
|
728 code += 3;
|
|
729 break;
|
|
730
|
|
731 case IRputdefault: // b = a
|
|
732 a = GETa(code);
|
|
733 b = GETb(code);
|
|
734 o = b.toObject();
|
|
735 if (!o)
|
|
736 {
|
|
737 ErrInfo errinfo;
|
|
738 a = Dobject.RuntimeError(&errinfo,
|
|
739 errmsgtbl[ERR_CANNOT_ASSIGN], a.getType(),
|
|
740 b.getType());
|
|
741 goto Lthrow;
|
|
742 }
|
|
743 a = o.PutDefault(a);
|
|
744 if (a)
|
|
745 goto Lthrow;
|
|
746 code += 3;
|
|
747 break;
|
|
748
|
|
749 case IRputthis: // s = a
|
|
750 a = cc.variable.Put((code + 2).id.value.string, GETa(code), 0);
|
|
751 //if (a) goto Lthrow;
|
|
752 code += 3;
|
|
753 break;
|
|
754
|
|
755 case IRmov: // a = b
|
|
756 Value.copy(GETa(code), GETb(code));
|
|
757 code += 3;
|
|
758 break;
|
|
759
|
|
760 case IRstring: // a = "string"
|
|
761 GETa(code).putVstring((code + 2).id.value.string);
|
|
762 code += 3;
|
|
763 break;
|
|
764
|
|
765 case IRobject: // a = object
|
|
766 { FunctionDefinition fd;
|
|
767 fd = cast(FunctionDefinition)(code + 2).ptr;
|
|
768 Dfunction fobject = new DdeclaredFunction(fd);
|
|
769 fobject.scopex = scopex;
|
|
770 GETa(code).putVobject(fobject);
|
|
771 code += 3;
|
|
772 break;
|
|
773 }
|
|
774
|
|
775 case IRthis: // a = this
|
|
776 GETa(code).putVobject(othis);
|
|
777 //writef("IRthis: %s, othis = %x\n", GETa(code).getType(), othis);
|
|
778 code += 2;
|
|
779 break;
|
|
780
|
|
781 case IRnumber: // a = number
|
|
782 GETa(code).putVnumber(*cast(d_number *)(code + 2));
|
|
783 code += 4;
|
|
784 break;
|
|
785
|
|
786 case IRboolean: // a = boolean
|
|
787 GETa(code).putVboolean((code + 2).boolean);
|
|
788 code += 3;
|
|
789 break;
|
|
790
|
|
791 case IRnull: // a = null
|
|
792 GETa(code).putVnull();
|
|
793 code += 2;
|
|
794 break;
|
|
795
|
|
796 case IRundefined: // a = undefined
|
|
797 GETa(code).putVundefined();
|
|
798 code += 2;
|
|
799 break;
|
|
800
|
|
801 case IRthisget: // a = othis.ident
|
|
802 a = GETa(code);
|
|
803 v = othis.Get((code + 2).id.value.string);
|
|
804 if (!v)
|
|
805 v = &vundefined;
|
|
806 Value.copy(a, v);
|
|
807 code += 3;
|
|
808 break;
|
|
809
|
|
810 case IRneg: // a = -a
|
|
811 a = GETa(code);
|
|
812 n = a.toNumber();
|
|
813 a.putVnumber(-n);
|
|
814 code += 2;
|
|
815 break;
|
|
816
|
|
817 case IRpos: // a = a
|
|
818 a = GETa(code);
|
|
819 n = a.toNumber();
|
|
820 a.putVnumber(n);
|
|
821 code += 2;
|
|
822 break;
|
|
823
|
|
824 case IRcom: // a = ~a
|
|
825 a = GETa(code);
|
|
826 i32 = a.toInt32();
|
|
827 a.putVnumber(~i32);
|
|
828 code += 2;
|
|
829 break;
|
|
830
|
|
831 case IRnot: // a = !a
|
|
832 a = GETa(code);
|
|
833 a.putVboolean(!a.toBoolean());
|
|
834 code += 2;
|
|
835 break;
|
|
836
|
|
837 case IRtypeof: // a = typeof a
|
|
838 // ECMA 11.4.3 says that if the result of (a)
|
|
839 // is a Reference and GetBase(a) is null,
|
|
840 // then the result is "undefined". I don't know
|
|
841 // what kind of script syntax will generate this.
|
|
842 a = GETa(code);
|
|
843 a.putVstring(a.getTypeof());
|
|
844 code += 2;
|
|
845 break;
|
|
846
|
|
847 case IRinstance: // a = b instanceof c
|
|
848 {
|
|
849 Dobject co;
|
|
850
|
|
851 // ECMA v3 11.8.6
|
|
852
|
|
853 b = GETb(code);
|
|
854 o = b.toObject();
|
|
855 c = GETc(code);
|
|
856 if (c.isPrimitive())
|
|
857 {
|
|
858 ErrInfo errinfo;
|
|
859 a = Dobject.RuntimeError(&errinfo,
|
|
860 errmsgtbl[ERR_RHS_MUST_BE_OBJECT],
|
|
861 "instanceof", c.getType());
|
|
862 goto Lthrow;
|
|
863 }
|
|
864 co = c.toObject();
|
|
865 a = GETa(code);
|
|
866 v = cast(Value*)co.HasInstance(a, b);
|
|
867 if (v)
|
|
868 { a = v;
|
|
869 goto Lthrow;
|
|
870 }
|
|
871 code += 4;
|
|
872 break;
|
|
873 }
|
|
874 case IRadd: // a = b + c
|
|
875 a = GETa(code);
|
|
876 b = GETb(code);
|
|
877 c = GETc(code);
|
|
878
|
|
879 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
880 {
|
|
881 a.putVnumber(b.number + c.number);
|
|
882 }
|
|
883 else
|
|
884 {
|
|
885 char vtmpb[Value.sizeof];
|
|
886 Value* vb = cast(Value*)vtmpb;
|
|
887 char vtmpc[Value.sizeof];
|
|
888 Value* vc = cast(Value*)vtmpc;
|
|
889
|
|
890 v = cast(Value*)b.toPrimitive(vb, null);
|
|
891 if (v)
|
|
892 { a = v;
|
|
893 goto Lthrow;
|
|
894 }
|
|
895 v = cast(Value*)c.toPrimitive(vc, null);
|
|
896 if (v)
|
|
897 { a = v;
|
|
898 goto Lthrow;
|
|
899 }
|
|
900 if (vb.isString() || vc.isString())
|
|
901 {
|
|
902 s = vb.toString() ~ vc.toString();
|
|
903 a.putVstring(s);
|
|
904 }
|
|
905 else
|
|
906 {
|
|
907 a.putVnumber(vb.toNumber() + vc.toNumber());
|
|
908 }
|
|
909 }
|
|
910
|
|
911 code += 4;
|
|
912 break;
|
|
913
|
|
914 case IRsub: // a = b - c
|
|
915 a = GETa(code);
|
|
916 b = GETb(code);
|
|
917 c = GETc(code);
|
|
918 a.putVnumber(b.toNumber() - c.toNumber());
|
|
919 code += 4;
|
|
920 break;
|
|
921
|
|
922 case IRmul: // a = b * c
|
|
923 a = GETa(code);
|
|
924 b = GETb(code);
|
|
925 c = GETc(code);
|
|
926 a.putVnumber(b.toNumber() * c.toNumber());
|
|
927 code += 4;
|
|
928 break;
|
|
929
|
|
930 case IRdiv: // a = b / c
|
|
931 a = GETa(code);
|
|
932 b = GETb(code);
|
|
933 c = GETc(code);
|
|
934
|
|
935 //writef("%g / %g = %g\n", b.toNumber() , c.toNumber(), b.toNumber() / c.toNumber());
|
|
936 a.putVnumber(b.toNumber() / c.toNumber());
|
|
937 code += 4;
|
|
938 break;
|
|
939
|
|
940 case IRmod: // a = b % c
|
|
941 a = GETa(code);
|
|
942 b = GETb(code);
|
|
943 c = GETc(code);
|
|
944 a.putVnumber(b.toNumber() % c.toNumber());
|
|
945 code += 4;
|
|
946 break;
|
|
947
|
|
948 case IRshl: // a = b << c
|
|
949 a = GETa(code);
|
|
950 b = GETb(code);
|
|
951 c = GETc(code);
|
|
952 i32 = b.toInt32();
|
|
953 u32 = c.toUint32() & 0x1F;
|
|
954 i32 <<= u32;
|
|
955 a.putVnumber(i32);
|
|
956 code += 4;
|
|
957 break;
|
|
958
|
|
959 case IRshr: // a = b >> c
|
|
960 a = GETa(code);
|
|
961 b = GETb(code);
|
|
962 c = GETc(code);
|
|
963 i32 = b.toInt32();
|
|
964 u32 = c.toUint32() & 0x1F;
|
|
965 i32 >>= cast(d_int32) u32;
|
|
966 a.putVnumber(i32);
|
|
967 code += 4;
|
|
968 break;
|
|
969
|
|
970 case IRushr: // a = b >>> c
|
|
971 a = GETa(code);
|
|
972 b = GETb(code);
|
|
973 c = GETc(code);
|
|
974 i32 = b.toUint32();
|
|
975 u32 = c.toUint32() & 0x1F;
|
|
976 u32 = (cast(d_uint32) i32) >> u32;
|
|
977 a.putVnumber(u32);
|
|
978 code += 4;
|
|
979 break;
|
|
980
|
|
981 case IRand: // a = b & c
|
|
982 a = GETa(code);
|
|
983 b = GETb(code);
|
|
984 c = GETc(code);
|
|
985 a.putVnumber(b.toInt32() & c.toInt32());
|
|
986 code += 4;
|
|
987 break;
|
|
988
|
|
989 case IRor: // a = b | c
|
|
990 a = GETa(code);
|
|
991 b = GETb(code);
|
|
992 c = GETc(code);
|
|
993 a.putVnumber(b.toInt32() | c.toInt32());
|
|
994 code += 4;
|
|
995 break;
|
|
996
|
|
997 case IRxor: // a = b ^ c
|
|
998 a = GETa(code);
|
|
999 b = GETb(code);
|
|
1000 c = GETc(code);
|
|
1001 a.putVnumber(b.toInt32() ^ c.toInt32());
|
|
1002 code += 4;
|
|
1003 break;
|
|
1004
|
|
1005 /********************/
|
|
1006
|
|
1007 case IRpreinc: // a = ++b.c
|
|
1008 c = GETc(code);
|
|
1009 s = c.toString();
|
|
1010 goto Lpreinc;
|
|
1011 case IRpreincs: // a = ++b.s
|
|
1012 s = (code + 3).id.value.string;
|
|
1013 Lpreinc:
|
|
1014 inc = 1;
|
|
1015 Lpre:
|
|
1016 a = GETa(code);
|
|
1017 b = GETb(code);
|
|
1018 v = b.Get(s);
|
|
1019 if (!v)
|
|
1020 v = &vundefined;
|
|
1021 n = v.toNumber();
|
|
1022 a.putVnumber(n + inc);
|
|
1023 b.Put(s, a);
|
|
1024 code += 4;
|
|
1025 break;
|
|
1026
|
|
1027 case IRpreincscope: // a = ++s
|
|
1028 inc = 1;
|
|
1029 Lprescope:
|
|
1030 a = GETa(code);
|
|
1031 id = (code + 2).id;
|
|
1032 s = id.value.string;
|
|
1033 version (SCOPECACHING)
|
|
1034 {
|
|
1035 si = SCOPECACHE_SI(s.ptr);
|
|
1036 if (s is scopecache[si].s)
|
|
1037 {
|
|
1038 v = scopecache[si].v;
|
|
1039 n = v.toNumber() + inc;
|
|
1040 v.putVnumber(n);
|
|
1041 a.putVnumber(n);
|
|
1042 }
|
|
1043 else
|
|
1044 {
|
|
1045 v = scope_get(scopex, id, &o);
|
|
1046 if (v)
|
|
1047 { n = v.toNumber() + inc;
|
|
1048 v.putVnumber(n);
|
|
1049 a.putVnumber(n);
|
|
1050 }
|
|
1051 else
|
|
1052 a.putVundefined();
|
|
1053 }
|
|
1054 }
|
|
1055 else
|
|
1056 {
|
|
1057 v = scope_get(scopex, id, &o);
|
|
1058 if (v)
|
|
1059 { n = v.toNumber();
|
|
1060 v.putVnumber(n + inc);
|
|
1061 Value.copy(a, v);
|
|
1062 }
|
|
1063 else
|
|
1064 a.putVundefined();
|
|
1065 }
|
|
1066 code += 4;
|
|
1067 break;
|
|
1068
|
|
1069 case IRpredec: // a = --b.c
|
|
1070 c = GETc(code);
|
|
1071 s = c.toString();
|
|
1072 goto Lpredec;
|
|
1073 case IRpredecs: // a = --b.s
|
|
1074 s = (code + 3).id.value.string;
|
|
1075 Lpredec:
|
|
1076 inc = -1;
|
|
1077 goto Lpre;
|
|
1078
|
|
1079 case IRpredecscope: // a = --s
|
|
1080 inc = -1;
|
|
1081 goto Lprescope;
|
|
1082
|
|
1083 /********************/
|
|
1084
|
|
1085 case IRpostinc: // a = b.c++
|
|
1086 c = GETc(code);
|
|
1087 s = c.toString();
|
|
1088 goto Lpostinc;
|
|
1089 case IRpostincs: // a = b.s++
|
|
1090 s = (code + 3).id.value.string;
|
|
1091 Lpostinc:
|
|
1092 a = GETa(code);
|
|
1093 b = GETb(code);
|
|
1094 v = b.Get(s);
|
|
1095 if (!v)
|
|
1096 v = &vundefined;
|
|
1097 n = v.toNumber();
|
|
1098 a.putVnumber(n + 1);
|
|
1099 b.Put(s, a);
|
|
1100 a.putVnumber(n);
|
|
1101 code += 4;
|
|
1102 break;
|
|
1103
|
|
1104 case IRpostincscope: // a = s++
|
|
1105 id = (code + 2).id;
|
|
1106 v = scope_get(scopex, id, &o);
|
|
1107 if (v && v != &vundefined)
|
|
1108 {
|
|
1109 n = v.toNumber();
|
|
1110 a = GETa(code);
|
|
1111 v.putVnumber(n + 1);
|
|
1112 a.putVnumber(n);
|
|
1113 }
|
|
1114 else
|
|
1115 GETa(code).putVundefined();
|
|
1116 code += 3;
|
|
1117 break;
|
|
1118
|
|
1119 case IRpostdec: // a = b.c--
|
|
1120 c = GETc(code);
|
|
1121 s = c.toString();
|
|
1122 goto Lpostdec;
|
|
1123 case IRpostdecs: // a = b.s--
|
|
1124 s = (code + 3).id.value.string;
|
|
1125 Lpostdec:
|
|
1126 a = GETa(code);
|
|
1127 b = GETb(code);
|
|
1128 v = b.Get(s);
|
|
1129 if (!v)
|
|
1130 v = &vundefined;
|
|
1131 n = v.toNumber();
|
|
1132 a.putVnumber(n - 1);
|
|
1133 b.Put(s, a);
|
|
1134 a.putVnumber(n);
|
|
1135 code += 4;
|
|
1136 break;
|
|
1137
|
|
1138 case IRpostdecscope: // a = s--
|
|
1139 id = (code + 2).id;
|
|
1140 v = scope_get(scopex, id, &o);
|
|
1141 if (v && v != &vundefined)
|
|
1142 { n = v.toNumber();
|
|
1143 a = GETa(code);
|
|
1144 v.putVnumber(n - 1);
|
|
1145 a.putVnumber(n);
|
|
1146 }
|
|
1147 else
|
|
1148 GETa(code).putVundefined();
|
|
1149 code += 3;
|
|
1150 break;
|
|
1151
|
|
1152 case IRdel: // a = delete b.c
|
|
1153 case IRdels: // a = delete b.s
|
|
1154 b = GETb(code);
|
|
1155 if (b.isPrimitive())
|
|
1156 bo = true;
|
|
1157 else
|
|
1158 {
|
|
1159 o = b.toObject();
|
|
1160 if (!o)
|
|
1161 {
|
|
1162 a = cannotConvert(b, GETlinnum(code));
|
|
1163 goto Lthrow;
|
|
1164 }
|
|
1165 s = (code.opcode == IRdel)
|
|
1166 ? GETc(code).toString()
|
|
1167 : (code + 3).id.value.string;
|
|
1168 if (o.implementsDelete())
|
|
1169 bo = o.Delete(s);
|
|
1170 else
|
|
1171 bo = !o.HasProperty(s);
|
|
1172 }
|
|
1173 GETa(code).putVboolean(bo);
|
|
1174 code += 4;
|
|
1175 break;
|
|
1176
|
|
1177 case IRdelscope: // a = delete s
|
|
1178 id = (code + 2).id;
|
|
1179 s = id.value.string;
|
|
1180 //o = scope_tos(scopex); // broken way
|
|
1181 if (!scope_get(scopex, id, &o))
|
|
1182 bo = true;
|
|
1183 else if (o.implementsDelete())
|
|
1184 bo = o.Delete(s);
|
|
1185 else
|
|
1186 bo = !o.HasProperty(s);
|
|
1187 GETa(code).putVboolean(bo);
|
|
1188 code += 3;
|
|
1189 break;
|
|
1190
|
|
1191 /* ECMA requires that if one of the numeric operands is NAN,
|
|
1192 * then the result of the comparison is false. D generates a
|
|
1193 * correct test for NAN operands.
|
|
1194 */
|
|
1195
|
|
1196 case IRclt: // a = (b < c)
|
|
1197 a = GETa(code);
|
|
1198 b = GETb(code);
|
|
1199 c = GETc(code);
|
|
1200 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1201 res = (b.number < c.number);
|
|
1202 else
|
|
1203 {
|
|
1204 b.toPrimitive(b, TypeNumber);
|
|
1205 c.toPrimitive(c, TypeNumber);
|
|
1206 if (b.isString() && c.isString())
|
|
1207 { d_string x = b.toString();
|
|
1208 d_string y = c.toString();
|
|
1209
|
|
1210 res = std.string.cmp(x, y) < 0;
|
|
1211 }
|
|
1212 else
|
|
1213 res = b.toNumber() < c.toNumber();
|
|
1214 }
|
|
1215 a.putVboolean(res);
|
|
1216 code += 4;
|
|
1217 break;
|
|
1218
|
|
1219 case IRcle: // a = (b <= c)
|
|
1220 a = GETa(code);
|
|
1221 b = GETb(code);
|
|
1222 c = GETc(code);
|
|
1223 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1224 res = (b.number <= c.number);
|
|
1225 else
|
|
1226 {
|
|
1227 b.toPrimitive(b, TypeNumber);
|
|
1228 c.toPrimitive(c, TypeNumber);
|
|
1229 if (b.isString() && c.isString())
|
|
1230 { d_string x = b.toString();
|
|
1231 d_string y = c.toString();
|
|
1232
|
|
1233 res = std.string.cmp(x, y) <= 0;
|
|
1234 }
|
|
1235 else
|
|
1236 res = b.toNumber() <= c.toNumber();
|
|
1237 }
|
|
1238 a.putVboolean(res);
|
|
1239 code += 4;
|
|
1240 break;
|
|
1241
|
|
1242 case IRcgt: // a = (b > c)
|
|
1243 a = GETa(code);
|
|
1244 b = GETb(code);
|
|
1245 c = GETc(code);
|
|
1246 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1247 res = (b.number > c.number);
|
|
1248 else
|
|
1249 {
|
|
1250 b.toPrimitive(b, TypeNumber);
|
|
1251 c.toPrimitive(c, TypeNumber);
|
|
1252 if (b.isString() && c.isString())
|
|
1253 { d_string x = b.toString();
|
|
1254 d_string y = c.toString();
|
|
1255
|
|
1256 res = std.string.cmp(x, y) > 0;
|
|
1257 }
|
|
1258 else
|
|
1259 res = b.toNumber() > c.toNumber();
|
|
1260 }
|
|
1261 a.putVboolean(res);
|
|
1262 code += 4;
|
|
1263 break;
|
|
1264
|
|
1265
|
|
1266 case IRcge: // a = (b >= c)
|
|
1267 a = GETa(code);
|
|
1268 b = GETb(code);
|
|
1269 c = GETc(code);
|
|
1270 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1271 res = (b.number >= c.number);
|
|
1272 else
|
|
1273 {
|
|
1274 b.toPrimitive(b, TypeNumber);
|
|
1275 c.toPrimitive(c, TypeNumber);
|
|
1276 if (b.isString() && c.isString())
|
|
1277 { d_string x = b.toString();
|
|
1278 d_string y = c.toString();
|
|
1279
|
|
1280 res = std.string.cmp(x, y) >= 0;
|
|
1281 }
|
|
1282 else
|
|
1283 res = b.toNumber() >= c.toNumber();
|
|
1284 }
|
|
1285 a.putVboolean(res);
|
|
1286 code += 4;
|
|
1287 break;
|
|
1288
|
|
1289 case IRceq: // a = (b == c)
|
|
1290 case IRcne: // a = (b != c)
|
|
1291 a = GETa(code);
|
|
1292 b = GETb(code);
|
|
1293 c = GETc(code);
|
|
1294 Lagain:
|
|
1295 tx = b.getType();
|
|
1296 ty = c.getType();
|
|
1297 if (logflag) writef("tx('%s', '%s')\n", tx, ty);
|
|
1298 if (tx == ty)
|
|
1299 {
|
|
1300 if (tx == TypeUndefined ||
|
|
1301 tx == TypeNull)
|
|
1302 res = true;
|
|
1303 else if (tx == TypeNumber)
|
|
1304 { d_number x = b.number;
|
|
1305 d_number y = c.number;
|
|
1306
|
|
1307 res = (x == y);
|
|
1308 //writef("x = %g, y = %g, res = %d\n", x, y, res);
|
|
1309 }
|
|
1310 else if (tx == TypeString)
|
|
1311 {
|
|
1312 if (logflag)
|
|
1313 {
|
|
1314 writef("b = %x, c = %x\n", b, c);
|
|
1315 writef("cmp('%s', '%s')\n", b.string, c.string);
|
|
1316 writef("cmp(%d, %d)\n", b.string.length, c.string.length);
|
|
1317 }
|
|
1318 res = (b.string == c.string);
|
|
1319 }
|
|
1320 else if (tx == TypeBoolean)
|
|
1321 res = (b.dbool == c.dbool);
|
|
1322 else // TypeObject
|
|
1323 {
|
|
1324 res = b.object == c.object;
|
|
1325 }
|
|
1326 }
|
|
1327 else if (tx == TypeNull && ty == TypeUndefined)
|
|
1328 res = true;
|
|
1329 else if (tx == TypeUndefined && ty == TypeNull)
|
|
1330 res = true;
|
|
1331 else if (tx == TypeNumber && ty == TypeString)
|
|
1332 {
|
|
1333 c.putVnumber(c.toNumber());
|
|
1334 goto Lagain;
|
|
1335 }
|
|
1336 else if (tx == TypeString && ty == TypeNumber)
|
|
1337 {
|
|
1338 b.putVnumber(b.toNumber());
|
|
1339 goto Lagain;
|
|
1340 }
|
|
1341 else if (tx == TypeBoolean)
|
|
1342 {
|
|
1343 b.putVnumber(b.toNumber());
|
|
1344 goto Lagain;
|
|
1345 }
|
|
1346 else if (ty == TypeBoolean)
|
|
1347 {
|
|
1348 c.putVnumber(c.toNumber());
|
|
1349 goto Lagain;
|
|
1350 }
|
|
1351 else if (ty == TypeObject)
|
|
1352 {
|
|
1353 v = cast(Value*)c.toPrimitive(c, null);
|
|
1354 if (v)
|
|
1355 { a = v;
|
|
1356 goto Lthrow;
|
|
1357 }
|
|
1358 goto Lagain;
|
|
1359 }
|
|
1360 else if (tx == TypeObject)
|
|
1361 {
|
|
1362 v = cast(Value*)b.toPrimitive(b, null);
|
|
1363 if (v)
|
|
1364 { a = v;
|
|
1365 goto Lthrow;
|
|
1366 }
|
|
1367 goto Lagain;
|
|
1368 }
|
|
1369 else
|
|
1370 {
|
|
1371 res = false;
|
|
1372 }
|
|
1373
|
|
1374 res ^= (code.opcode == IRcne);
|
|
1375 //Lceq:
|
|
1376 a.putVboolean(res);
|
|
1377 code += 4;
|
|
1378 break;
|
|
1379
|
|
1380 case IRcid: // a = (b === c)
|
|
1381 case IRcnid: // a = (b !== c)
|
|
1382 a = GETa(code);
|
|
1383 b = GETb(code);
|
|
1384 c = GETc(code);
|
|
1385 tx = b.getType();
|
|
1386 ty = c.getType();
|
|
1387 if (tx == ty)
|
|
1388 {
|
|
1389 if (tx == TypeUndefined ||
|
|
1390 tx == TypeNull)
|
|
1391 res = true;
|
|
1392 else if (tx == TypeNumber)
|
|
1393 { d_number x = b.number;
|
|
1394 d_number y = c.number;
|
|
1395
|
|
1396 // Ensure that a NAN operand produces false
|
|
1397 if (code.opcode == IRcid)
|
|
1398 res = (x == y);
|
|
1399 else
|
|
1400 res = (x <> y);
|
|
1401 goto Lcid;
|
|
1402 }
|
|
1403 else if (tx == TypeString)
|
|
1404 res = (b.string == c.string);
|
|
1405 else if (tx == TypeBoolean)
|
|
1406 res = (b.dbool == c.dbool);
|
|
1407 else // TypeObject
|
|
1408 {
|
|
1409 res = b.object == c.object;
|
|
1410 }
|
|
1411 }
|
|
1412 else
|
|
1413 {
|
|
1414 res = false;
|
|
1415 }
|
|
1416
|
|
1417 res ^= (code.opcode == IRcnid);
|
|
1418 Lcid:
|
|
1419 a.putVboolean(res);
|
|
1420 code += 4;
|
|
1421 break;
|
|
1422
|
|
1423 case IRjt: // if (b) goto t
|
|
1424 b = GETb(code);
|
|
1425 if (b.toBoolean())
|
|
1426 code += (code + 1).offset;
|
|
1427 else
|
|
1428 code += 3;
|
|
1429 break;
|
|
1430
|
|
1431 case IRjf: // if (!b) goto t
|
|
1432 b = GETb(code);
|
|
1433 if (!b.toBoolean())
|
|
1434 code += (code + 1).offset;
|
|
1435 else
|
|
1436 code += 3;
|
|
1437 break;
|
|
1438
|
|
1439 case IRjtb: // if (b) goto t
|
|
1440 b = GETb(code);
|
|
1441 if (b.dbool)
|
|
1442 code += (code + 1).offset;
|
|
1443 else
|
|
1444 code += 3;
|
|
1445 break;
|
|
1446
|
|
1447 case IRjfb: // if (!b) goto t
|
|
1448 b = GETb(code);
|
|
1449 if (!b.dbool)
|
|
1450 code += (code + 1).offset;
|
|
1451 else
|
|
1452 code += 3;
|
|
1453 break;
|
|
1454
|
|
1455 case IRjmp:
|
|
1456 code += (code + 1).offset;
|
|
1457 break;
|
|
1458
|
|
1459 case IRjlt: // if (b < c) goto c
|
|
1460 b = GETb(code);
|
|
1461 c = GETc(code);
|
|
1462 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1463 {
|
|
1464 if (b.number < c.number)
|
|
1465 code += 4;
|
|
1466 else
|
|
1467 code += (code + 1).offset;
|
|
1468 break;
|
|
1469 }
|
|
1470 else
|
|
1471 {
|
|
1472 b.toPrimitive(b, TypeNumber);
|
|
1473 c.toPrimitive(c, TypeNumber);
|
|
1474 if (b.isString() && c.isString())
|
|
1475 { d_string x = b.toString();
|
|
1476 d_string y = c.toString();
|
|
1477
|
|
1478 res = std.string.cmp(x, y) < 0;
|
|
1479 }
|
|
1480 else
|
|
1481 res = b.toNumber() < c.toNumber();
|
|
1482 }
|
|
1483 if (!res)
|
|
1484 code += (code + 1).offset;
|
|
1485 else
|
|
1486 code += 4;
|
|
1487 break;
|
|
1488
|
|
1489 case IRjle: // if (b <= c) goto c
|
|
1490 b = GETb(code);
|
|
1491 c = GETc(code);
|
|
1492 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
|
|
1493 {
|
|
1494 if (b.number <= c.number)
|
|
1495 code += 4;
|
|
1496 else
|
|
1497 code += (code + 1).offset;
|
|
1498 break;
|
|
1499 }
|
|
1500 else
|
|
1501 {
|
|
1502 b.toPrimitive(b, TypeNumber);
|
|
1503 c.toPrimitive(c, TypeNumber);
|
|
1504 if (b.isString() && c.isString())
|
|
1505 { d_string x = b.toString();
|
|
1506 d_string y = c.toString();
|
|
1507
|
|
1508 res = std.string.cmp(x, y) <= 0;
|
|
1509 }
|
|
1510 else
|
|
1511 res = b.toNumber() <= c.toNumber();
|
|
1512 }
|
|
1513 if (!res)
|
|
1514 code += (code + 1).offset;
|
|
1515 else
|
|
1516 code += 4;
|
|
1517 break;
|
|
1518
|
|
1519 case IRjltc: // if (b < constant) goto c
|
|
1520 b = GETb(code);
|
|
1521 res = (b.toNumber() < *cast(d_number *)(code + 3));
|
|
1522 if (!res)
|
|
1523 code += (code + 1).offset;
|
|
1524 else
|
|
1525 code += 5;
|
|
1526 break;
|
|
1527
|
|
1528 case IRjlec: // if (b <= constant) goto c
|
|
1529 b = GETb(code);
|
|
1530 res = (b.toNumber() <= *cast(d_number *)(code + 3));
|
|
1531 if (!res)
|
|
1532 code += (code + 1).offset;
|
|
1533 else
|
|
1534 code += 5;
|
|
1535 break;
|
|
1536
|
|
1537 case IRiter: // a = iter(b)
|
|
1538 a = GETa(code);
|
|
1539 b = GETb(code);
|
|
1540 o = b.toObject();
|
|
1541 if (!o)
|
|
1542 {
|
|
1543 a = cannotConvert(b, GETlinnum(code));
|
|
1544 goto Lthrow;
|
|
1545 }
|
|
1546 a = o.putIterator(a);
|
|
1547 if (a)
|
|
1548 goto Lthrow;
|
|
1549 code += 3;
|
|
1550 break;
|
|
1551
|
|
1552 case IRnext: // a, b.c, iter
|
|
1553 // if (!(b.c = iter)) goto a; iter = iter.next
|
|
1554 s = GETc(code).toString();
|
|
1555 goto case_next;
|
|
1556
|
|
1557 case IRnexts: // a, b.s, iter
|
|
1558 s = (code + 3).id.value.string;
|
|
1559 case_next:
|
|
1560 iter = GETd(code).iter;
|
|
1561 v = iter.next();
|
|
1562 if (!v)
|
|
1563 code += (code + 1).offset;
|
|
1564 else
|
|
1565 {
|
|
1566 b = GETb(code);
|
|
1567 b.Put(s, v);
|
|
1568 code += 5;
|
|
1569 }
|
|
1570 break;
|
|
1571
|
|
1572 case IRnextscope: // a, s, iter
|
|
1573 s = (code + 2).id.value.string;
|
|
1574 iter = GETc(code).iter;
|
|
1575 v = iter.next();
|
|
1576 if (!v)
|
|
1577 code += (code + 1).offset;
|
|
1578 else
|
|
1579 {
|
|
1580 o = scope_tos(scopex);
|
|
1581 o.Put(s, v, 0);
|
|
1582 code += 4;
|
|
1583 }
|
|
1584 break;
|
|
1585
|
|
1586 case IRcall: // a = b.c(argc, argv)
|
|
1587 s = GETc(code).toString();
|
|
1588 goto case_call;
|
|
1589
|
|
1590 case IRcalls: // a = b.s(argc, argv)
|
|
1591 s = (code + 3).id.value.string;
|
|
1592 goto case_call;
|
|
1593
|
|
1594 case_call:
|
|
1595 a = GETa(code);
|
|
1596 b = GETb(code);
|
|
1597 o = b.toObject();
|
|
1598 if (!o)
|
|
1599 {
|
|
1600 goto Lcallerror;
|
|
1601 }
|
|
1602 {
|
|
1603 //writef("v.call\n");
|
|
1604 v = o.Get(s);
|
|
1605 if (!v)
|
|
1606 goto Lcallerror;
|
|
1607 //writef("calling... '%s'\n", v.toString());
|
|
1608 cc.callerothis = othis;
|
|
1609 a.putVundefined();
|
|
1610 a = cast(Value*)v.Call(cc, o, a, GETe(code)[0 .. (code + 4).index]);
|
|
1611 //writef("regular call, a = %x\n", a);
|
|
1612 }
|
|
1613 debug (VERIFY)
|
|
1614 assert(checksum == IR.verify(__LINE__, codestart));
|
|
1615 if (a)
|
|
1616 goto Lthrow;
|
|
1617 code += 6;
|
|
1618 goto Lnext;
|
|
1619
|
|
1620 Lcallerror:
|
|
1621 {
|
|
1622 //writef("%s %s.%s is undefined and has no Call method\n", b.getType(), b.toString(), s);
|
|
1623 ErrInfo errinfo;
|
|
1624 a = Dobject.RuntimeError(&errinfo,
|
|
1625 errmsgtbl[ERR_UNDEFINED_NO_CALL3],
|
|
1626 b.getType(), b.toString(),
|
|
1627 s);
|
|
1628 goto Lthrow;
|
|
1629 }
|
|
1630
|
|
1631 case IRcallscope: // a = s(argc, argv)
|
|
1632 id = (code + 2).id;
|
|
1633 s = id.value.string;
|
|
1634 a = GETa(code);
|
|
1635 v = scope_get_lambda(scopex, id, &o);
|
|
1636 //writefln("v.toString() = '%s'", v.toString());
|
|
1637 if (!v)
|
|
1638 {
|
|
1639 ErrInfo errinfo;
|
|
1640 a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_UNDEFINED_NO_CALL2], "property", s);
|
|
1641 goto Lthrow;
|
|
1642 }
|
|
1643 // Should we pass othis or o? I think othis.
|
|
1644 cc.callerothis = othis; // pass othis to eval()
|
|
1645 a.putVundefined();
|
|
1646 a = cast(Value*)v.Call(cc, o, a, GETd(code)[0 .. (code + 3).index] );
|
|
1647 //writef("callscope result = %x\n", a);
|
|
1648 debug (VERIFY)
|
|
1649 assert(checksum == IR.verify(__LINE__, codestart));
|
|
1650 if (a)
|
|
1651 goto Lthrow;
|
|
1652 code += 5;
|
|
1653 goto Lnext;
|
|
1654
|
|
1655 case IRcallv: // v(argc, argv) = a
|
|
1656 a = GETa(code);
|
|
1657 b = GETb(code);
|
|
1658 o = b.toObject();
|
|
1659 if (!o)
|
|
1660 {
|
|
1661 //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
|
|
1662 ErrInfo errinfo;
|
|
1663 a = Dobject.RuntimeError(&errinfo,
|
|
1664 errmsgtbl[ERR_UNDEFINED_NO_CALL2],
|
|
1665 b.getType(), b.toString());
|
|
1666 goto Lthrow;
|
|
1667 }
|
|
1668 cc.callerothis = othis; // pass othis to eval()
|
|
1669 a.putVundefined();
|
|
1670 a = cast(Value*)o.Call(cc, o, a, GETd(code)[0 .. (code + 3).index]);
|
|
1671 if (a)
|
|
1672 goto Lthrow;
|
|
1673 code += 5;
|
|
1674 goto Lnext;
|
|
1675
|
|
1676 case IRputcall: // b.c(argc, argv) = a
|
|
1677 s = GETc(code).toString();
|
|
1678 goto case_putcall;
|
|
1679
|
|
1680 case IRputcalls: // b.s(argc, argv) = a
|
|
1681 s = (code + 3).id.value.string;
|
|
1682 goto case_putcall;
|
|
1683
|
|
1684 case_putcall:
|
|
1685 a = GETa(code);
|
|
1686 b = GETb(code);
|
|
1687 o = b.toObject();
|
|
1688 if (!o)
|
|
1689 goto Lcallerror;
|
|
1690 //v = o.GetLambda(s, Value.calcHash(s));
|
|
1691 v = o.Get(s, Value.calcHash(s));
|
|
1692 if (!v)
|
|
1693 goto Lcallerror;
|
|
1694 //writef("calling... '%s'\n", v.toString());
|
|
1695 o = v.toObject();
|
|
1696 if (!o)
|
|
1697 {
|
|
1698 ErrInfo errinfo;
|
|
1699 a = Dobject.RuntimeError(&errinfo,
|
|
1700 errmsgtbl[ERR_CANNOT_ASSIGN_TO2],
|
|
1701 b.getType(), s);
|
|
1702 goto Lthrow;
|
|
1703 }
|
|
1704 a = cast(Value*)o.put_Value(a, GETe(code)[0 .. (code + 4).index] );
|
|
1705 if (a)
|
|
1706 goto Lthrow;
|
|
1707 code += 6;
|
|
1708 goto Lnext;
|
|
1709
|
|
1710 case IRputcallscope: // a = s(argc, argv)
|
|
1711 id = (code + 2).id;
|
|
1712 s = id.value.string;
|
|
1713 v = scope_get_lambda(scopex, id, &o);
|
|
1714 if (!v)
|
|
1715 {
|
|
1716 ErrInfo errinfo;
|
|
1717 a = Dobject.RuntimeError(&errinfo,
|
|
1718 errmsgtbl[ERR_UNDEFINED_NO_CALL2],
|
|
1719 "property", s);
|
|
1720 goto Lthrow;
|
|
1721 }
|
|
1722 o = v.toObject();
|
|
1723 if (!o)
|
|
1724 {
|
|
1725 ErrInfo errinfo;
|
|
1726 a = Dobject.RuntimeError(&errinfo,
|
|
1727 errmsgtbl[ERR_CANNOT_ASSIGN_TO],
|
|
1728 s);
|
|
1729 goto Lthrow;
|
|
1730 }
|
|
1731 a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] );
|
|
1732 if (a)
|
|
1733 goto Lthrow;
|
|
1734 code += 5;
|
|
1735 goto Lnext;
|
|
1736
|
|
1737 case IRputcallv: // v(argc, argv) = a
|
|
1738 b = GETb(code);
|
|
1739 o = b.toObject();
|
|
1740 if (!o)
|
|
1741 {
|
|
1742 //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
|
|
1743 ErrInfo errinfo;
|
|
1744 a = Dobject.RuntimeError(&errinfo,
|
|
1745 errmsgtbl[ERR_UNDEFINED_NO_CALL2],
|
|
1746 b.getType(), b.toString());
|
|
1747 goto Lthrow;
|
|
1748 }
|
|
1749 a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] );
|
|
1750 if (a)
|
|
1751 goto Lthrow;
|
|
1752 code += 5;
|
|
1753 goto Lnext;
|
|
1754
|
|
1755 case IRnew: // a = new b(argc, argv)
|
|
1756 a = GETa(code);
|
|
1757 b = GETb(code);
|
|
1758 a.putVundefined();
|
|
1759 a = cast(Value*)b.Construct(cc, a, GETd(code)[0 .. (code + 3).index] );
|
|
1760 debug (VERIFY)
|
|
1761 assert(checksum == IR.verify(__LINE__, codestart));
|
|
1762 if (a)
|
|
1763 goto Lthrow;
|
|
1764 code += 5;
|
|
1765 goto Lnext;
|
|
1766
|
|
1767 case IRpush:
|
|
1768 SCOPECACHE_CLEAR();
|
|
1769 a = GETa(code);
|
|
1770 o = a.toObject();
|
|
1771 if (!o)
|
|
1772 {
|
|
1773 a = cannotConvert(a, GETlinnum(code));
|
|
1774 goto Lthrow;
|
|
1775 }
|
|
1776 scopex ~= o; // push entry onto scope chain
|
|
1777 cc.scopex = scopex;
|
|
1778 code += 2;
|
|
1779 break;
|
|
1780
|
|
1781 case IRpop:
|
|
1782 SCOPECACHE_CLEAR();
|
|
1783 o = scopex[length - 1];
|
|
1784 scopex = scopex[0 .. length - 1]; // pop entry off scope chain
|
|
1785 // If it's a Finally, we need to execute
|
|
1786 // the finally block
|
|
1787 code += 1;
|
|
1788 if (o.isFinally()) // test could be eliminated with virtual func
|
|
1789 {
|
|
1790 f = cast(Finally)o;
|
|
1791 cc.finallyret = 0;
|
|
1792 a = cast(Value*)call(cc, othis, f.finallyblock, ret, locals);
|
|
1793 debug (VERIFY)
|
|
1794 assert(checksum == IR.verify(__LINE__, codestart));
|
|
1795 if (a)
|
|
1796 goto Lthrow;
|
|
1797 if (cc.finallyret)
|
|
1798 cc.finallyret = 0;
|
|
1799 else
|
|
1800 { // The rest of any unwinding is already done
|
|
1801 return null;
|
|
1802 }
|
|
1803 }
|
|
1804 goto Lnext;
|
|
1805
|
|
1806 case IRfinallyret:
|
|
1807 cc.finallyret = 1;
|
|
1808 case IRret:
|
|
1809 version (SCOPECACHE_LOG)
|
|
1810 printf("scopecache_cnt = %d\n", scopecache_cnt);
|
|
1811 return null;
|
|
1812
|
|
1813 case IRretexp:
|
|
1814 a = GETa(code);
|
|
1815 Value.copy(ret, a);
|
|
1816 //writef("returns: %s\n", ret.toString());
|
|
1817 return null;
|
|
1818
|
|
1819 case IRimpret:
|
|
1820 a = GETa(code);
|
|
1821 Value.copy(ret, a);
|
|
1822 //writef("implicit return: %s\n", ret.toString());
|
|
1823 code += 2;
|
|
1824 goto Lnext;
|
|
1825
|
|
1826 case IRthrow:
|
|
1827 a = GETa(code);
|
|
1828 cc.linnum = GETlinnum(code);
|
|
1829 Lthrow:
|
|
1830 //writef("Lthrow: linnum = %d\n", GETlinnum(code));
|
|
1831 a.getErrInfo(null, GETlinnum(code));
|
|
1832 SCOPECACHE_CLEAR();
|
|
1833 for (;;)
|
|
1834 {
|
|
1835 if (scopex.length <= dimsave)
|
|
1836 {
|
|
1837 ret.putVundefined();
|
|
1838 // 'a' may be pointing into the stack, which means
|
|
1839 // it gets scrambled on return. Therefore, we copy
|
|
1840 // its contents into a safe area in CallContext.
|
|
1841 assert(cc.value.sizeof == Value.sizeof);
|
|
1842 Value.copy(cast(Value*)cc.value, a);
|
|
1843 return cast(Value*)cc.value;
|
|
1844 }
|
|
1845 o = scopex[length - 1];
|
|
1846 scopex = scopex[0 .. length - 1]; // pop entry off scope chain
|
|
1847 if (o.isCatch())
|
|
1848 { ca = cast(Catch)o;
|
|
1849 //writef("catch('%s')\n", ca.name);
|
|
1850 o = new Dobject(Dobject.getPrototype());
|
|
1851 version (JSCRIPT_CATCH_BUG)
|
|
1852 {
|
|
1853 PutValue(cc, ca.name, a);
|
|
1854 }
|
|
1855 else
|
|
1856 {
|
|
1857 o.Put(ca.name, a, DontDelete);
|
|
1858 }
|
|
1859 scopex ~= o;
|
|
1860 cc.scopex = scopex;
|
|
1861 code = codestart + ca.offset;
|
|
1862 break;
|
|
1863 }
|
|
1864 else
|
|
1865 {
|
|
1866 if (o.isFinally())
|
|
1867 {
|
|
1868 f = cast(Finally)o;
|
|
1869 v = cast(Value*)call(cc, othis, f.finallyblock, ret, locals);
|
|
1870 if (v)
|
|
1871 { a = v;
|
|
1872 //writef("changing a\n");
|
|
1873 }
|
|
1874 }
|
|
1875 }
|
|
1876 }
|
|
1877 goto Lnext;
|
|
1878
|
|
1879 case IRtrycatch:
|
|
1880 SCOPECACHE_CLEAR();
|
|
1881 offset = (code - codestart) + (code + 1).offset;
|
|
1882 s = (code + 2).id.value.string;
|
|
1883 ca = new Catch(offset, s);
|
|
1884 scopex ~= ca;
|
|
1885 cc.scopex = scopex;
|
|
1886 code += 3;
|
|
1887 break;
|
|
1888
|
|
1889 case IRtryfinally:
|
|
1890 SCOPECACHE_CLEAR();
|
|
1891 f = new Finally(code + (code + 1).offset);
|
|
1892 scopex ~= f;
|
|
1893 cc.scopex = scopex;
|
|
1894 code += 2;
|
|
1895 break;
|
|
1896
|
|
1897 case IRassert:
|
|
1898 {
|
|
1899 ErrInfo errinfo;
|
|
1900 errinfo.linnum = (code + 1).index;
|
|
1901 version (all) // Not supported under some com servers
|
|
1902 {
|
|
1903 a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_ASSERT], (code + 1).index);
|
|
1904 goto Lthrow;
|
|
1905 }
|
|
1906 else
|
|
1907 {
|
|
1908 RuntimeErrorx(ERR_ASSERT, (code + 1).index);
|
|
1909 }
|
|
1910 code += 2;
|
|
1911 break;
|
|
1912 }
|
|
1913
|
|
1914 default:
|
|
1915 //writef("1: Unrecognized IR instruction %d\n", code.opcode);
|
|
1916 assert(0); // unrecognized IR instruction
|
|
1917 }
|
|
1918 }
|
|
1919
|
|
1920 Linterrupt:
|
|
1921 ret.putVundefined();
|
|
1922 return null;
|
|
1923 }
|
|
1924
|
|
1925 /*******************************************
|
|
1926 * This is a 'disassembler' for our interpreted code.
|
|
1927 * Useful for debugging.
|
|
1928 */
|
|
1929
|
|
1930 static void print(uint address, IR *code)
|
|
1931 {
|
|
1932 switch (code.opcode)
|
|
1933 {
|
|
1934 case IRerror:
|
|
1935 writef("\tIRerror\n");
|
|
1936 break;
|
|
1937
|
|
1938 case IRnop:
|
|
1939 writef("\tIRnop\n");
|
|
1940 break;
|
|
1941
|
|
1942 case IRend:
|
|
1943 writef("\tIRend\n");
|
|
1944 break;
|
|
1945
|
|
1946 case IRget: // a = b.c
|
|
1947 writef("\tIRget %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
1948 break;
|
|
1949
|
|
1950 case IRput: // b.c = a
|
|
1951 writef("\tIRput %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
1952 break;
|
|
1953
|
|
1954 case IRgets: // a = b.s
|
|
1955 writef("\tIRgets %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
1956 break;
|
|
1957
|
|
1958 case IRgetscope: // a = othis.ident
|
|
1959 writef("\tIRgetscope %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 2).id.value.hash);
|
|
1960 break;
|
|
1961
|
|
1962 case IRaddass: // b.c += a
|
|
1963 writef("\tIRaddass %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
1964 break;
|
|
1965
|
|
1966 case IRaddasss: // b.s += a
|
|
1967 writef("\tIRaddasss %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
1968 break;
|
|
1969
|
|
1970 case IRaddassscope: // othis.ident += a
|
|
1971 writef("\tIRaddassscope %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 3).index);
|
|
1972 break;
|
|
1973
|
|
1974 case IRputs: // b.s = a
|
|
1975 writef("\tIRputs %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
1976 break;
|
|
1977
|
|
1978 case IRputscope: // s = a
|
|
1979 writef("\tIRputscope %d, '%s'\n",(code + 1).index, (code + 2).id.value.string);
|
|
1980 break;
|
|
1981
|
|
1982 case IRputdefault: // b = a
|
|
1983 writef("\tIRputdefault %d, %d\n",(code + 1).index, (code + 2).index);
|
|
1984 break;
|
|
1985
|
|
1986 case IRputthis: // b = s
|
|
1987 writef("\tIRputthis '%s', %d\n",(code + 2).id.value.string,(code + 1).index);
|
|
1988 break;
|
|
1989
|
|
1990 case IRmov: // a = b
|
|
1991 writef("\tIRmov %d, %d\n", (code + 1).index, (code + 2).index);
|
|
1992 break;
|
|
1993
|
|
1994 case IRstring: // a = "string"
|
|
1995 writef("\tIRstring %d, '%s'\n",(code + 1).index,(code + 2).id.value.string);
|
|
1996 break;
|
|
1997
|
|
1998 case IRobject: // a = object
|
|
1999 writef("\tIRobject %d, %x\n",(code + 1).index,cast(void*)(code + 2).object);
|
|
2000 break;
|
|
2001
|
|
2002 case IRthis: // a = this
|
|
2003 writef("\tIRthis %d\n",(code + 1).index);
|
|
2004 break;
|
|
2005
|
|
2006 case IRnumber: // a = number
|
|
2007 writef("\tIRnumber %d, %g\n",(code + 1).index,*cast(d_number *)(code + 2));
|
|
2008 break;
|
|
2009
|
|
2010 case IRboolean: // a = boolean
|
|
2011 writef("\tIRboolean %d, %d\n",(code + 1).index, (code + 2).boolean);
|
|
2012 break;
|
|
2013
|
|
2014 case IRnull: // a = null
|
|
2015 writef("\tIRnull %d\n",(code + 1).index);
|
|
2016 break;
|
|
2017
|
|
2018 case IRundefined: // a = undefined
|
|
2019 writef("\tIRundefined %d\n",(code + 1).index);
|
|
2020 break;
|
|
2021
|
|
2022 case IRthisget: // a = othis.ident
|
|
2023 writef("\tIRthisget %d, '%s'\n",(code + 1).index,(code + 2).id.value.string);
|
|
2024 break;
|
|
2025
|
|
2026 case IRneg: // a = -a
|
|
2027 writef("\tIRneg %d\n",(code + 1).index);
|
|
2028 break;
|
|
2029
|
|
2030 case IRpos: // a = a
|
|
2031 writef("\tIRpos %d\n",(code + 1).index);
|
|
2032 break;
|
|
2033
|
|
2034 case IRcom: // a = ~a
|
|
2035 writef("\tIRcom %d\n",(code + 1).index);
|
|
2036 break;
|
|
2037
|
|
2038 case IRnot: // a = !a
|
|
2039 writef("\tIRnot %d\n",(code + 1).index);
|
|
2040 break;
|
|
2041
|
|
2042 case IRtypeof: // a = typeof a
|
|
2043 writef("\tIRtypeof %d\n", (code + 1).index);
|
|
2044 break;
|
|
2045
|
|
2046 case IRinstance: // a = b instanceof c
|
|
2047 writef("\tIRinstance %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
|
|
2048 break;
|
|
2049
|
|
2050 case IRadd: // a = b + c
|
|
2051 writef("\tIRadd %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2052 break;
|
|
2053
|
|
2054 case IRsub: // a = b - c
|
|
2055 writef("\tIRsub %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2056 break;
|
|
2057
|
|
2058 case IRmul: // a = b * c
|
|
2059 writef("\tIRmul %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2060 break;
|
|
2061
|
|
2062 case IRdiv: // a = b / c
|
|
2063 writef("\tIRdiv %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2064 break;
|
|
2065
|
|
2066 case IRmod: // a = b % c
|
|
2067 writef("\tIRmod %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2068 break;
|
|
2069
|
|
2070 case IRshl: // a = b << c
|
|
2071 writef("\tIRshl %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2072 break;
|
|
2073
|
|
2074 case IRshr: // a = b >> c
|
|
2075 writef("\tIRshr %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2076 break;
|
|
2077
|
|
2078 case IRushr: // a = b >>> c
|
|
2079 writef("\tIRushr %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2080 break;
|
|
2081
|
|
2082 case IRand: // a = b & c
|
|
2083 writef("\tIRand %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2084 break;
|
|
2085
|
|
2086 case IRor: // a = b | c
|
|
2087 writef("\tIRor %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2088 break;
|
|
2089
|
|
2090 case IRxor: // a = b ^ c
|
|
2091 writef("\tIRxor %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2092 break;
|
|
2093
|
|
2094 case IRpreinc: // a = ++b.c
|
|
2095 writef("\tIRpreinc %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2096 break;
|
|
2097
|
|
2098 case IRpreincs: // a = ++b.s
|
|
2099 writef("\tIRpreincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
2100 break;
|
|
2101
|
|
2102 case IRpreincscope: // a = ++s
|
|
2103 writef("\tIRpreincscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash);
|
|
2104 break;
|
|
2105
|
|
2106 case IRpredec: // a = --b.c
|
|
2107 writef("\tIRpredec %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2108 break;
|
|
2109
|
|
2110 case IRpredecs: // a = --b.s
|
|
2111 writef("\tIRpredecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
2112 break;
|
|
2113
|
|
2114 case IRpredecscope: // a = --s
|
|
2115 writef("\tIRpredecscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash);
|
|
2116 break;
|
|
2117
|
|
2118 case IRpostinc: // a = b.c++
|
|
2119 writef("\tIRpostinc %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2120 break;
|
|
2121
|
|
2122 case IRpostincs: // a = b.s++
|
|
2123 writef("\tIRpostincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
2124 break;
|
|
2125
|
|
2126 case IRpostincscope: // a = s++
|
|
2127 writef("\tIRpostincscope %d, %s\n",(code + 1).index, (code + 2).id.value.string);
|
|
2128 break;
|
|
2129
|
|
2130 case IRpostdec: // a = b.c--
|
|
2131 writef("\tIRpostdec %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2132 break;
|
|
2133
|
|
2134 case IRpostdecs: // a = b.s--
|
|
2135 writef("\tIRpostdecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
2136 break;
|
|
2137
|
|
2138 case IRpostdecscope: // a = s--
|
|
2139 writef("\tIRpostdecscope %d, %s\n",(code + 1).index, (code + 2).id.value.string);
|
|
2140 break;
|
|
2141
|
|
2142 case IRdel: // a = delete b.c
|
|
2143 writef("\tIRdel %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2144 break;
|
|
2145
|
|
2146 case IRdels: // a = delete b.s
|
|
2147 writef("\tIRdels %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
|
|
2148 break;
|
|
2149
|
|
2150 case IRdelscope: // a = delete s
|
|
2151 writef("\tIRdelscope %d, '%s'\n",(code + 1).index, (code + 2).id.value.string);
|
|
2152 break;
|
|
2153
|
|
2154 case IRclt: // a = (b < c)
|
|
2155 writef("\tIRclt %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2156 break;
|
|
2157
|
|
2158 case IRcle: // a = (b <= c)
|
|
2159 writef("\tIRcle %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2160 break;
|
|
2161
|
|
2162 case IRcgt: // a = (b > c)
|
|
2163 writef("\tIRcgt %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2164 break;
|
|
2165
|
|
2166 case IRcge: // a = (b >= c)
|
|
2167 writef("\tIRcge %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2168 break;
|
|
2169
|
|
2170 case IRceq: // a = (b == c)
|
|
2171 writef("\tIRceq %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2172 break;
|
|
2173
|
|
2174 case IRcne: // a = (b != c)
|
|
2175 writef("\tIRcne %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2176 break;
|
|
2177
|
|
2178 case IRcid: // a = (b === c)
|
|
2179 writef("\tIRcid %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2180 break;
|
|
2181
|
|
2182 case IRcnid: // a = (b !== c)
|
|
2183 writef("\tIRcnid %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
|
|
2184 break;
|
|
2185
|
|
2186 case IRjt: // if (b) goto t
|
|
2187 writef("\tIRjt %d, %d\n", (code + 1).index + address, (code + 2).index);
|
|
2188 break;
|
|
2189
|
|
2190 case IRjf: // if (!b) goto t
|
|
2191 writef("\tIRjf %d, %d\n", (code + 1).index + address, (code + 2).index);
|
|
2192 break;
|
|
2193
|
|
2194 case IRjtb: // if (b) goto t
|
|
2195 writef("\tIRjtb %d, %d\n", (code + 1).index + address, (code + 2).index);
|
|
2196 break;
|
|
2197
|
|
2198 case IRjfb: // if (!b) goto t
|
|
2199 writef("\tIRjfb %d, %d\n", (code + 1).index + address, (code + 2).index);
|
|
2200 break;
|
|
2201
|
|
2202 case IRjmp:
|
|
2203 writef("\tIRjmp %d\n", (code + 1).offset + address);
|
|
2204 break;
|
|
2205
|
|
2206 case IRjlt: // if (b < c) goto t
|
|
2207 writef("\tIRjlt %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index);
|
|
2208 break;
|
|
2209
|
|
2210 case IRjle: // if (b <= c) goto t
|
|
2211 writef("\tIRjle %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index);
|
|
2212 break;
|
|
2213
|
|
2214 case IRjltc: // if (b < constant) goto t
|
|
2215 writef("\tIRjltc %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
|
|
2216 break;
|
|
2217
|
|
2218 case IRjlec: // if (b <= constant) goto t
|
|
2219 writef("\tIRjlec %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
|
|
2220 break;
|
|
2221
|
|
2222 case IRiter: // a = iter(b)
|
|
2223 writef("\tIRiter %d, %d\n",(code + 1).index, (code + 2).index);
|
|
2224 break;
|
|
2225
|
|
2226 case IRnext: // a, b.c, iter
|
|
2227 writef("\tIRnext %d, %d, %d, %d\n",
|
|
2228 (code + 1).index,
|
|
2229 (code + 2).index,
|
|
2230 (code + 3).index,
|
|
2231 (code + 4).index);
|
|
2232 break;
|
|
2233
|
|
2234 case IRnexts: // a, b.s, iter
|
|
2235 writef("\tIRnexts %d, %d, '%s', %d\n",
|
|
2236 (code + 1).index,
|
|
2237 (code + 2).index,
|
|
2238 (code + 3).id.value.string,
|
|
2239 (code + 4).index);
|
|
2240 break;
|
|
2241
|
|
2242 case IRnextscope: // a, s, iter
|
|
2243 writef
|
|
2244 ("\tIRnextscope %d, '%s', %d\n",
|
|
2245 (code + 1).index,
|
|
2246 (code + 2).id.value.string,
|
|
2247 (code + 3).index);
|
|
2248 break;
|
|
2249
|
|
2250 case IRcall: // a = b.c(argc, argv)
|
|
2251 writef("\tIRcall %d,%d,%d, argc=%d, argv=%d \n",
|
|
2252 (code + 1).index,
|
|
2253 (code + 2).index,
|
|
2254 (code + 3).index,
|
|
2255 (code + 4).index,
|
|
2256 (code + 5).index);
|
|
2257 break;
|
|
2258
|
|
2259 case IRcalls: // a = b.s(argc, argv)
|
|
2260 writef
|
|
2261 ("\tIRcalls %d,%d,'%s', argc=%d, argv=%d \n",
|
|
2262 (code + 1).index,
|
|
2263 (code + 2).index,
|
|
2264 (code + 3).id.value.string,
|
|
2265 (code + 4).index,
|
|
2266 (code + 5).index);
|
|
2267 break;
|
|
2268
|
|
2269 case IRcallscope: // a = s(argc, argv)
|
|
2270 writef
|
|
2271 ("\tIRcallscope %d,'%s', argc=%d, argv=%d \n",
|
|
2272 (code + 1).index,
|
|
2273 (code + 2).id.value.string,
|
|
2274 (code + 3).index,
|
|
2275 (code + 4).index);
|
|
2276 break;
|
|
2277
|
|
2278 case IRputcall: // a = b.c(argc, argv)
|
|
2279 writef("\tIRputcall %d,%d,%d, argc=%d, argv=%d \n",
|
|
2280 (code + 1).index,
|
|
2281 (code + 2).index,
|
|
2282 (code + 3).index,
|
|
2283 (code + 4).index,
|
|
2284 (code + 5).index);
|
|
2285 break;
|
|
2286
|
|
2287 case IRputcalls: // a = b.s(argc, argv)
|
|
2288 writef
|
|
2289 ("\tIRputcalls %d,%d,'%s', argc=%d, argv=%d \n",
|
|
2290 (code + 1).index,
|
|
2291 (code + 2).index,
|
|
2292 (code + 3).id.value.string,
|
|
2293 (code + 4).index,
|
|
2294 (code + 5).index);
|
|
2295 break;
|
|
2296
|
|
2297 case IRputcallscope: // a = s(argc, argv)
|
|
2298 writef
|
|
2299 ("\tIRputcallscope %d,'%s', argc=%d, argv=%d \n",
|
|
2300 (code + 1).index,
|
|
2301 (code + 2).id.value.string,
|
|
2302 (code + 3).index,
|
|
2303 (code + 4).index);
|
|
2304 break;
|
|
2305
|
|
2306 case IRcallv: // a = v(argc, argv)
|
|
2307 writef("\tIRcallv %d, %d(argc=%d, argv=%d)\n",
|
|
2308 (code + 1).index,
|
|
2309 (code + 2).index,
|
|
2310 (code + 3).index,
|
|
2311 (code + 4).index);
|
|
2312 break;
|
|
2313
|
|
2314 case IRputcallv: // a = v(argc, argv)
|
|
2315 writef("\tIRputcallv %d, %d(argc=%d, argv=%d)\n",
|
|
2316 (code + 1).index,
|
|
2317 (code + 2).index,
|
|
2318 (code + 3).index,
|
|
2319 (code + 4).index);
|
|
2320 break;
|
|
2321
|
|
2322 case IRnew: // a = new b(argc, argv)
|
|
2323 writef("\tIRnew %d,%d, argc=%d, argv=%d \n",
|
|
2324 (code + 1).index,
|
|
2325 (code + 2).index,
|
|
2326 (code + 3).index,
|
|
2327 (code + 4).index);
|
|
2328 break;
|
|
2329
|
|
2330 case IRpush:
|
|
2331 writef("\tIRpush %d\n",(code + 1).index);
|
|
2332 break;
|
|
2333
|
|
2334 case IRpop:
|
|
2335 writef("\tIRpop\n");
|
|
2336 break;
|
|
2337
|
|
2338 case IRret:
|
|
2339 writef("\tIRret\n");
|
|
2340 return;
|
|
2341
|
|
2342 case IRretexp:
|
|
2343 writef("\tIRretexp %d\n",(code + 1).index);
|
|
2344 return;
|
|
2345
|
|
2346 case IRimpret:
|
|
2347 writef("\tIRimpret %d\n",(code + 1).index);
|
|
2348 return;
|
|
2349
|
|
2350 case IRthrow:
|
|
2351 writef("\tIRthrow %d\n",(code + 1).index);
|
|
2352 break;
|
|
2353
|
|
2354 case IRassert:
|
|
2355 writef("\tIRassert %d\n",(code + 1).index);
|
|
2356 break;
|
|
2357
|
|
2358 case IRtrycatch:
|
|
2359 writef("\tIRtrycatch %d, '%s'\n", (code + 1).offset + address, (code + 2).id.value.string);
|
|
2360 break;
|
|
2361
|
|
2362 case IRtryfinally:
|
|
2363 writef("\tIRtryfinally %d\n", (code + 1).offset + address);
|
|
2364 break;
|
|
2365
|
|
2366 case IRfinallyret:
|
|
2367 writef("\tIRfinallyret\n");
|
|
2368 break;
|
|
2369
|
|
2370 default:
|
|
2371 writef("2: Unrecognized IR instruction %d\n", code.opcode);
|
|
2372 assert(0); // unrecognized IR instruction
|
|
2373 }
|
|
2374 }
|
|
2375
|
|
2376 /*********************************
|
|
2377 * Give size of opcode.
|
|
2378 */
|
|
2379
|
|
2380 static uint size(uint opcode)
|
|
2381 { uint sz = 9999;
|
|
2382
|
|
2383 switch (opcode)
|
|
2384 {
|
|
2385 case IRerror:
|
|
2386 case IRnop:
|
|
2387 case IRend:
|
|
2388 sz = 1;
|
|
2389 break;
|
|
2390
|
|
2391 case IRget: // a = b.c
|
|
2392 case IRaddass:
|
|
2393 sz = 4;
|
|
2394 break;
|
|
2395
|
|
2396 case IRput: // b.c = a
|
|
2397 sz = 4;
|
|
2398 break;
|
|
2399
|
|
2400 case IRgets: // a = b.s
|
|
2401 case IRaddasss:
|
|
2402 sz = 4;
|
|
2403 break;
|
|
2404
|
|
2405 case IRgetscope: // a = s
|
|
2406 sz = 3;
|
|
2407 break;
|
|
2408
|
|
2409 case IRaddassscope:
|
|
2410 sz = 4;
|
|
2411 break;
|
|
2412
|
|
2413 case IRputs: // b.s = a
|
|
2414 sz = 4;
|
|
2415 break;
|
|
2416
|
|
2417 case IRputscope: // s = a
|
|
2418 case IRputdefault: // b = a
|
|
2419 sz = 3;
|
|
2420 break;
|
|
2421
|
|
2422 case IRputthis: // a = s
|
|
2423 sz = 3;
|
|
2424 break;
|
|
2425
|
|
2426 case IRmov: // a = b
|
|
2427 sz = 3;
|
|
2428 break;
|
|
2429
|
|
2430 case IRstring: // a = "string"
|
|
2431 sz = 3;
|
|
2432 break;
|
|
2433
|
|
2434 case IRobject: // a = object
|
|
2435 sz = 3;
|
|
2436 break;
|
|
2437
|
|
2438 case IRthis: // a = this
|
|
2439 sz = 2;
|
|
2440 break;
|
|
2441
|
|
2442 case IRnumber: // a = number
|
|
2443 sz = 4;
|
|
2444 break;
|
|
2445
|
|
2446 case IRboolean: // a = boolean
|
|
2447 sz = 3;
|
|
2448 break;
|
|
2449
|
|
2450 case IRnull: // a = null
|
|
2451 sz = 2;
|
|
2452 break;
|
|
2453
|
|
2454 case IRundefined: // a = undefined
|
|
2455 sz = 2;
|
|
2456 break;
|
|
2457
|
|
2458 case IRthisget: // a = othis.ident
|
|
2459 sz = 3;
|
|
2460 break;
|
|
2461
|
|
2462 case IRneg: // a = -a
|
|
2463 case IRpos: // a = a
|
|
2464 case IRcom: // a = ~a
|
|
2465 case IRnot: // a = !a
|
|
2466 case IRtypeof: // a = typeof a
|
|
2467 sz = 2;
|
|
2468 break;
|
|
2469
|
|
2470 case IRinstance: // a = b instanceof c
|
|
2471 case IRadd: // a = b + c
|
|
2472 case IRsub: // a = b - c
|
|
2473 case IRmul: // a = b * c
|
|
2474 case IRdiv: // a = b / c
|
|
2475 case IRmod: // a = b % c
|
|
2476 case IRshl: // a = b << c
|
|
2477 case IRshr: // a = b >> c
|
|
2478 case IRushr: // a = b >>> c
|
|
2479 case IRand: // a = b & c
|
|
2480 case IRor: // a = b | c
|
|
2481 case IRxor: // a = b ^ c
|
|
2482 sz = 4;
|
|
2483 break;
|
|
2484
|
|
2485 case IRpreinc: // a = ++b.c
|
|
2486 case IRpreincs: // a = ++b.s
|
|
2487 case IRpredec: // a = --b.c
|
|
2488 case IRpredecs: // a = --b.s
|
|
2489 case IRpostinc: // a = b.c++
|
|
2490 case IRpostincs: // a = b.s++
|
|
2491 case IRpostdec: // a = b.c--
|
|
2492 case IRpostdecs: // a = b.s--
|
|
2493 sz = 4;
|
|
2494 break;
|
|
2495
|
|
2496 case IRpostincscope: // a = s++
|
|
2497 case IRpostdecscope: // a = s--
|
|
2498 sz = 3;
|
|
2499 break;
|
|
2500
|
|
2501 case IRpreincscope: // a = ++s
|
|
2502 case IRpredecscope: // a = --s
|
|
2503 sz = 4;
|
|
2504 break;
|
|
2505
|
|
2506 case IRdel: // a = delete b.c
|
|
2507 case IRdels: // a = delete b.s
|
|
2508 sz = 4;
|
|
2509 break;
|
|
2510
|
|
2511 case IRdelscope: // a = delete s
|
|
2512 sz = 3;
|
|
2513 break;
|
|
2514
|
|
2515 case IRclt: // a = (b < c)
|
|
2516 case IRcle: // a = (b <= c)
|
|
2517 case IRcgt: // a = (b > c)
|
|
2518 case IRcge: // a = (b >= c)
|
|
2519 case IRceq: // a = (b == c)
|
|
2520 case IRcne: // a = (b != c)
|
|
2521 case IRcid: // a = (b === c)
|
|
2522 case IRcnid: // a = (b !== c)
|
|
2523 case IRjlt: // if (b < c) goto t
|
|
2524 case IRjle: // if (b <= c) goto t
|
|
2525 sz = 4;
|
|
2526 break;
|
|
2527
|
|
2528 case IRjltc: // if (b < constant) goto t
|
|
2529 case IRjlec: // if (b <= constant) goto t
|
|
2530 sz = 5;
|
|
2531 break;
|
|
2532
|
|
2533 case IRjt: // if (b) goto t
|
|
2534 case IRjf: // if (!b) goto t
|
|
2535 case IRjtb: // if (b) goto t
|
|
2536 case IRjfb: // if (!b) goto t
|
|
2537 sz = 3;
|
|
2538 break;
|
|
2539
|
|
2540 case IRjmp:
|
|
2541 sz = 2;
|
|
2542 break;
|
|
2543
|
|
2544 case IRiter: // a = iter(b)
|
|
2545 sz = 3;
|
|
2546 break;
|
|
2547
|
|
2548 case IRnext: // a, b.c, iter
|
|
2549 case IRnexts: // a, b.s, iter
|
|
2550 sz = 5;
|
|
2551 break;
|
|
2552
|
|
2553 case IRnextscope: // a, s, iter
|
|
2554 sz = 4;
|
|
2555 break;
|
|
2556
|
|
2557 case IRcall: // a = b.c(argc, argv)
|
|
2558 case IRcalls: // a = b.s(argc, argv)
|
|
2559 case IRputcall: // b.c(argc, argv) = a
|
|
2560 case IRputcalls: // b.s(argc, argv) = a
|
|
2561 sz = 6;
|
|
2562 break;
|
|
2563
|
|
2564 case IRcallscope: // a = s(argc, argv)
|
|
2565 case IRputcallscope: // s(argc, argv) = a
|
|
2566 case IRcallv:
|
|
2567 case IRputcallv:
|
|
2568 sz = 5;
|
|
2569 break;
|
|
2570
|
|
2571 case IRnew: // a = new b(argc, argv)
|
|
2572 sz = 5;
|
|
2573 break;
|
|
2574
|
|
2575 case IRpush:
|
|
2576 sz = 2;
|
|
2577 break;
|
|
2578
|
|
2579 case IRpop:
|
|
2580 sz = 1;
|
|
2581 break;
|
|
2582
|
|
2583 case IRfinallyret:
|
|
2584 case IRret:
|
|
2585 sz = 1;
|
|
2586 break;
|
|
2587
|
|
2588 case IRretexp:
|
|
2589 case IRimpret:
|
|
2590 case IRthrow:
|
|
2591 sz = 2;
|
|
2592 break;
|
|
2593
|
|
2594 case IRtrycatch:
|
|
2595 sz = 3;
|
|
2596 break;
|
|
2597
|
|
2598 case IRtryfinally:
|
|
2599 sz = 2;
|
|
2600 break;
|
|
2601
|
|
2602 case IRassert:
|
|
2603 sz = 2;
|
|
2604 break;
|
|
2605
|
|
2606 default:
|
|
2607 writef("3: Unrecognized IR instruction %d, IRMAX = %d\n", opcode, IRMAX);
|
|
2608 assert(0); // unrecognized IR instruction
|
|
2609 }
|
|
2610 assert(sz <= 6);
|
|
2611 return sz;
|
|
2612 }
|
|
2613
|
|
2614 static void printfunc(IR *code)
|
|
2615 {
|
|
2616 IR *codestart = code;
|
|
2617
|
|
2618 for (;;)
|
|
2619 {
|
|
2620 writef("%2d(%d):", code - codestart, code.linnum);
|
|
2621 print(code - codestart, code);
|
|
2622 if (code.opcode == IRend)
|
|
2623 return;
|
|
2624 code += size(code.opcode);
|
|
2625 }
|
|
2626 }
|
|
2627
|
|
2628 /***************************************
|
|
2629 * Verify that it is a correct sequence of code.
|
|
2630 * Useful for isolating memory corruption bugs.
|
|
2631 */
|
|
2632
|
|
2633 static uint verify(uint linnum, IR *codestart)
|
|
2634 {
|
|
2635 debug (VERIFY)
|
|
2636 {
|
|
2637 uint checksum = 0;
|
|
2638 uint sz;
|
|
2639 uint i;
|
|
2640 IR *code;
|
|
2641
|
|
2642 // Verify code
|
|
2643 for (code = codestart;;)
|
|
2644 {
|
|
2645 switch (code.opcode)
|
|
2646 {
|
|
2647 case IRend:
|
|
2648 return checksum;
|
|
2649
|
|
2650 case IRerror:
|
|
2651 writef("verify failure line %u\n", linnum);
|
|
2652 assert(0);
|
|
2653 break;
|
|
2654
|
|
2655 default:
|
|
2656 if (code.opcode >= IRMAX)
|
|
2657 { writef("undefined opcode %d in code %p\n", code.opcode, codestart);
|
|
2658 assert(0);
|
|
2659 }
|
|
2660 sz = IR.size(code.opcode);
|
|
2661 for (i = 0; i < sz; i++)
|
|
2662 { checksum += code.opcode;
|
|
2663 code++;
|
|
2664 }
|
|
2665 break;
|
|
2666 }
|
|
2667 }
|
|
2668 }
|
|
2669 else
|
|
2670 return 0;
|
|
2671 }
|
|
2672 }
|