Bug Summary

File:platform/mac/avmshell/../../../core/Interpreter.cpp
Location:line 1089, column 17
Description:Value stored to 'u1' is never read

Annotated Source Code

1/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3/* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is [Open Source Virtual Machine.].
17 *
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Adobe AS3 Team
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40
41#include "avmplus.h"
42#include "Interpreter.h"
43
44#ifdef FEATURE_NANOJIT
45# include "exec-osr.h"
46#endif
47
48#ifdef AVMPLUS_MAC
49#ifndef __GNUC__4
50// inline_max_total_size() defaults to 10000.
51// This module includes so many inline functions that we
52// exceed this limit and we start getting compile warnings,
53// so bump up the limit for this file.
54#pragma inline_max_total_size(26576)
55#endif
56#endif
57
58// The macro VMCFG_WORDCODE is true if the representation of ABC code is as an array of words and
59// not an array of bytes.
60
61namespace avmplus
62{
63 // an auto-ptr for managing MethodFrame calls.
64 class EnterMethodEnv
65 {
66 public:
67 inline explicit EnterMethodEnv(AvmCore* core, MethodEnv* env, MethodFrame& frame) : m_core(core), m_frame(frame)
68 {
69 m_frame.enter(m_core, env);
70 }
71
72 inline ~EnterMethodEnv()
73 {
74 m_frame.exit(m_core);
75 }
76
77 void setCurrent()
78 {
79 m_core->currentMethodFrame = &m_frame;
80 }
81
82 private:
83 AvmCore* m_core;
84 MethodFrame& m_frame;
85 };
86
87#ifdef _DEBUG
88 REALLY_INLINEinline __attribute__((always_inline)) Atom CHECK_INT_ATOM(Atom a)(Atom a)
89 {
90 AvmAssert(atomKind(a) == kIntptrType && atomIsValidIntptrValue(atomGetIntptr(a)))do { } while (0);
91 return a;
92 }
93 REALLY_INLINEinline __attribute__((always_inline)) Atom MAKE_INTEGER(intptr_t i)((intptr_t(intptr_t i) << 3) | kIntptrType)
94 {
95 AvmAssert(atomIsValidIntptrValue(i))do { } while (0);
96 return (intptr_t(i) << 3) | kIntptrType;
97 }
98#else
99 #define CHECK_INT_ATOM(a)(a) (a)
100 #define MAKE_INTEGER(v)((intptr_t(v) << 3) | kIntptrType) ((intptr_t(v) << 3) | kIntptrType)
101#endif
102
103
104#define IS_INTEGER(v)(((v) & 7) == kIntptrType) (((v) & 7) == kIntptrType)
105#define IS_DOUBLE(v)(((v) & 7) == kDoubleType) (((v) & 7) == kDoubleType)
106#define IS_BOOLEAN(v)(((v) & 7) == kBooleanType) (((v) & 7) == kBooleanType)
107#define IS_STRING(v)(((v) & 7) == kStringType) (((v) & 7) == kStringType)
108
109// note that the argument to SIGN_EXTEND is expected to be upshifted 3 bits (not a "raw" intptr),
110// but it doesn't expect or require the tag bits to be set properly.
111#ifdef AVMPLUS_64BIT
112// since 64-bit int atoms expect exactly 53 bits of precision, we want to shift bit 53+3 up into the sign bit and back down
113# define SIGN_EXTEND(v)(intptr_t(v)) ((intptr_t(v) << 8) >> 8)
114#else
115# define SIGN_EXTEND(v)(intptr_t(v)) (intptr_t(v))
116#endif
117
118// CLAMP_32 is equivalent to running an int atom thru AvmCore::integer (ie, truncate to int32_t using the right rules),
119// but, like SIGN_EXTEND, it expects the argument to be upshifted 3 bit.
120#ifdef AVMPLUS_64BIT
121# define CLAMP_32(v)(intptr_t(v)) ((intptr_t(v) << 29) >> 29)
122#else
123# define CLAMP_32(v)(intptr_t(v)) (intptr_t(v))
124#endif
125
126#define INT32_VALUE(v)int32_t(atomGetIntptr(v)) int32_t(atomGetIntptr(v))
127#define UINT32_VALUE(v)uint32_t(atomGetIntptr(v)) uint32_t(atomGetIntptr(v))
128#define DOUBLE_VALUE(v)(*(double*)((v) ^ kDoubleType)) (*(double*)((v) ^ kDoubleType))
129#define IS_BOTH_INTEGER(a,b)((((a ^ kIntptrType) | (b ^ kIntptrType)) & 7) == 0) ((((a ^ kIntptrType) | (b ^ kIntptrType)) & 7) == 0) // less control flow but more registers -- which is better?
130#define IS_BOTH_DOUBLE(a,b)((((a ^ kDoubleType) | (b ^ kDoubleType)) & 7) == 0) ((((a ^ kDoubleType) | (b ^ kDoubleType)) & 7) == 0)
131
132#ifdef VMCFG_WORDCODE
133# define WORD_CODE_ONLY(x) x
134# define ABC_CODE_ONLY(x)x
135#else
136# define WORD_CODE_ONLY(x)
137# define ABC_CODE_ONLY(x)x x
138#endif
139
140#ifdef VMCFG_WORDCODE_PEEPHOLE
141# define PEEPHOLE_ONLY(x) x
142#else
143# define PEEPHOLE_ONLY(x)
144#endif
145
146#ifdef DEBUGGER
147# define DEBUGGER_ONLY(x) x
148# define NONDEBUGGER_ONLY(x)x
149#else
150# define DEBUGGER_ONLY(x)
151# define NONDEBUGGER_ONLY(x)x x
152#endif
153#ifdef DEBUG
154# define DEBUG_ONLY(x) x
155#else
156# define DEBUG_ONLY(x)
157#endif
158
159#ifdef VMCFG_WORDCODE
160 typedef uintptr_t bytecode_t;
161#else
162 typedef uint8_t bytecode_t;
163#endif
164
165#ifndef VMCFG_WORDCODE
166 inline intptr_t readS24(const uint8_t* pc) {
167 return AvmCore::readS24(pc);
168 }
169
170 inline uintptr_t readU30(const uint8_t*& pc) {
171 return AvmCore::readU32(pc);
172 }
173#endif
174
175// Direct threading in the interpreter.
176//
177// If you have gcc, direct threading should work out of the box and
178// should provide a nice speedup with many platforms and compiler versions.
179//
180// If you are using Microsoft Visual C/C++ then you may turn on direct
181// threading, and you must select one of the two threading implementations
182// below. MSVC_X86_ASM_THREADING should "just work" but is likely
183// to be slower than switch dispatch, unless you're using a compiler
184// version with little or no optimization. MSVC_X86_REWRITE_THREADING
185// usually improves the performance over switch dispatch, but requires
186// a fair amount of manual work if core/Interpreter.cpp has been modified
187// since core/FastInterpreter.asm was generated. The specific work
188// needed to regenerate core/FastInterpreter.cpp is described in a comment
189// at the head of utils/x86rewrite.as, which you will need to run.
190
191#ifdef VMCFG_DIRECT_THREADED
192# ifndef VMCFG_WORDCODE
193# error "Need word code enabled for this"
194# endif
195# if defined __GNUC__4
196# define GNUC_THREADING
197# define DIRECT_DISPATCH
198# elif defined AVMPLUS_WIN32
199 // Pick one of the two following options
200//# define MSVC_X86_ASM_THREADING
201# define MSVC_X86_REWRITE_THREADING
202# ifdef MSVC_X86_ASM_THREADING
203# define DIRECT_DISPATCH
204# endif
205# ifdef MSVC_X86_REWRITE_THREADING
206# define SWITCH_DISPATCH
207# endif
208# else
209# error "Threaded code not supported for this platform/compiler"
210# endif
211#else
212# define SWITCH_DISPATCH
213#endif // compiler/platform vipers' nest
214
215 static Atom* initMultiname(MethodEnv* env, Multiname &name, Atom* sp);
216 static Atom* initMultinameNoXMLList(MethodEnv* env, Multiname &name, Atom* sp);
217 static Traits* getTraits(const Multiname* name, PoolObject* pool, Toplevel* toplevel, AvmCore* core);
218#ifdef AVMPLUS_VERBOSE
219 // display contents of current stack frame only
220 static void showState(MethodInfo* info, const bytecode_t *code_start, const bytecode_t *pc,
221 Atom* framep, Atom *spp, int scopeDepth, Atom *scopebasep, int max_scope);
222#endif
223
224 /**
225 * on a backwards branch, check if the interrupt flag is enabled.
226 * used by interpreter only. A copy of this is inline-generated
227 * by CodegenLIR at loop headers.
228 */
229 REALLY_INLINEinline __attribute__((always_inline)) void branchCheck(AvmCore* core, MethodEnv *env, boolbool interruptable)
230 {
231 #ifdef DEBUGGER
232 core->sampleCheck();
233 #endif
234 if (core->interruptCheck(interruptable))
235 core->handleInterruptMethodEnv(env);
236 }
237
238#ifdef _MSC_VER
239# ifdef MSVC_X86_ASM_THREADING
240# pragma warning(disable:4740) // "inline assembler suppresses global optimization"
241# endif
242#endif // _MSC_VER
243
244#ifdef VMCFG_DIRECT_THREADED
245
246 void** interpGetOpcodeLabels() {
247 // *** NOTE ON THREAD SAFETY ***
248 //
249 // If we ever enable direct threading for a platform where the thread jump targets
250 // cannot be constants in a vector but must be written into a vector the first time
251 // interpGetOpcodeLabels() is called, then the following call must be within a
252 // critical section (or some startup code must make an initial call to make sure
253 // the vector is initialized in a thread safe way). At this time, Visual C++
254 // requires this, but we're not using direct threading with Visual C++, so there
255 // is no critical section here.
256 //
257 // The startup code to make the initial call can simply call this function and
258 // assign the result to a dummy static global variable; that trick is not portable
259 // but it can be used for many platforms (and is used elsewhere).
260
261 #if defined MSVC_X86_ASM_THREADING || defined MSVC_X86_REWRITE_THREADING
262 #error "interpGetOpcodeLabels needs a critical section or eager initialization for this compiler / platform combination"
263 #endif
264
265 return (void**)interpBoxed(NULL__null, 0, NULL__null);
266 }
267
268#endif // VMCFG_DIRECT_THREADED
269
270#if defined FEATURE_NANOJIT && defined VMCFG_OSR
271# define OSR(offset) \
272 if (OSR::countEdge(env, info, ms) && \
273 OSR::execute(env, framep, ms, pc + (offset), &a1l)) { \
274 methodFrame.setCurrent(); \
275 a1 = a1l; \
276 goto return_value_from_interpreter; \
277 }
278#else
279# define OSR(i1)
280#endif
281
282 Atom interpBoxed(register MethodEnv* env, register int _argc, register Atom* _atomv)
283 {
284#ifdef VMCFG_DIRECT_THREADED
285
286 // If env is NULL return the jump table. Optionally initialize it here on those
287 // platforms where compile-time initialization is not possible or practical.
288
289 if (env == NULL__null) {
290# if defined GNUC_THREADING
291# define III(idx, lbl) &&lbl,
292# define XXX(idx) &&L_illegal_op,
293 static void* opcode_labels[] = {
294# elif defined MSVC_X86_ASM_THREADING || defined MSVC_X86_REWRITE_THREADING
295 static void* opcode_labels[WOP_LAST+1];
296 if (opcode_labels[0] == 0) {
297# define XXX(idx) III(idx, L_illegal_op)
298# ifdef MSVC_X86_ASM_THREADING
299# define III(idx, lbl) __asm { \
300 __asm mov eax, offset opcode_labels \
301 __asm mov ebx, offset lbl \
302 __asm mov [eax+4*idx], ebx \
303 }
304# else
305 extern boolbool LLLLABEL(int);
306# define III(a,b) extern void LLLLABEL ## _ ## a ## _ ## b(); LLLLABEL ## _ ## a ## _ ## b();
307# endif
308# endif // threading discipline
309# define IIM(a,b) III(a,b)
310# if defined VMCFG_WORDCODE_PEEPHOLE
311# define IIP(a,b) III(a,b)
312# else
313# define IIP(a,b) XXX(a)
314# endif
315# if defined DEBUGGER || !defined VMCFG_WORDCODE
316# define IID(a,b) III(a,b)
317# else
318# define IID(a,b) XXX(a)
319# endif
320 XXX(0x00)
321 XXX(0x01) /* OP_bkpt */
322 III(0x02, L_nop)
323 III(0x03, L_throw)
324 III(0x04, L_getsuper)
325 III(0x05, L_setsuper)
326 III(0x06, L_dxns)
327 III(0x07, L_dxnslate)
328 III(0x08, L_kill)
329 XXX(0x09) /* OP_label */
330 XXX(0x0A)
331 XXX(0x0B)
332 III(0x0C, L_ifnlt)
333 III(0x0D, L_ifnle)
334 III(0x0E, L_ifngt)
335 III(0x0F, L_ifnge)
336 III(0x10, L_jump)
337 III(0x11, L_iftrue)
338 III(0x12, L_iffalse)
339 III(0x13, L_ifeq)
340 III(0x14, L_ifne)
341 III(0x15, L_iflt)
342 III(0x16, L_ifle)
343 III(0x17, L_ifgt)
344 III(0x18, L_ifge)
345 III(0x19, L_ifstricteq)
346 III(0x1A, L_ifstrictne)
347 III(0x1B, L_lookupswitch)
348 III(0x1C, L_pushwith)
349 III(0x1D, L_popscope)
350 III(0x1E, L_nextname)
351 III(0x1F, L_hasnext)
352 III(0x20, L_pushnull)
353 III(0x21, L_pushundefined)
354 XXX(0x22)
355 III(0x23, L_nextvalue)
356 XXX(0x24) /* OP_pushbyte */
357 XXX(0x25) /* OP_pushshort */
358 III(0x26, L_pushtrue)
359 III(0x27, L_pushfalse)
360 III(0x28, L_pushnan)
361 III(0x29, L_pop)
362 III(0x2A, L_dup)
363 III(0x2B, L_swap)
364 III(0x2C, L_pushstring)
365 XXX(0x2D) /* OP_pushint */
366 XXX(0x2E) /* OP_pushuint */
367 III(0x2F, L_pushdouble)
368 III(0x30, L_pushscope)
369 III(0x31, L_pushnamespace)
370 III(0x32, L_hasnext2)
371 XXX(0x33)
372 XXX(0x34)
373 IIM(0x35, L_li8)
374 IIM(0x36, L_li16)
375 IIM(0x37, L_li32)
376 IIM(0x38, L_lf32)
377 IIM(0x39, L_lf64)
378 IIM(0x3A, L_si8)
379 IIM(0x3B, L_si16)
380 IIM(0x3C, L_si32)
381 IIM(0x3D, L_sf32)
382 IIM(0x3E, L_sf64)
383 XXX(0x3F)
384 III(0x40, L_newfunction)
385 III(0x41, L_call)
386 III(0x42, L_construct)
387 III(0x43, L_callmethod)
388 III(0x44, L_callstatic)
389 III(0x45, L_callsuper)
390 III(0x46, L_callproperty)
391 III(0x47, L_returnvoid)
392 III(0x48, L_returnvalue)
393 III(0x49, L_constructsuper)
394 III(0x4A, L_constructprop)
395 XXX(0x4B) /* OP_callsuperid */
396 III(0x4C, L_callproplex)
397 XXX(0x4D) /* OP_callinterface */
398 III(0x4E, L_callsupervoid)
399 III(0x4F, L_callpropvoid)
400 IIM(0x50, L_sxi1)
401 IIM(0x51, L_sxi8)
402 IIM(0x52, L_sxi16)
403 III(0x53, L_applytype)
404 XXX(0x54)
405 III(0x55, L_newobject)
406 III(0x56, L_newarray)
407 III(0x57, L_newactivation)
408 III(0x58, L_newclass)
409 III(0x59, L_getdescendants)
410 III(0x5A, L_newcatch)
411 XXX(0x5B)
412 XXX(0x5C)
413 III(0x5D, L_findpropstrict)
414 III(0x5E, L_findproperty)
415 III(0x5F, L_finddef)
416 III(0x60, L_getlex)
417 III(0x61, L_setproperty)
418 III(0x62, L_getlocal)
419 III(0x63, L_setlocal)
420 III(0x64, L_getglobalscope)
421 III(0x65, L_getscopeobject)
422 III(0x66, L_getproperty)
423 III(0x67, L_getouterscope)
424 III(0x68, L_initproperty)
425 XXX(0x69)
426 III(0x6A, L_deleteproperty)
427 XXX(0x6B)
428 III(0x6C, L_getslot)
429 III(0x6D, L_setslot)
430 III(0x6E, L_getglobalslot)
431 III(0x6F, L_setglobalslot)
432 III(0x70, L_convert_s)
433 III(0x71, L_esc_xelem)
434 III(0x72, L_esc_xattr)
435 III(0x73, L_convert_i)
436 III(0x74, L_convert_u)
437 III(0x75, L_convert_d)
438 III(0x76, L_convert_b)
439 III(0x77, L_convert_o)
440 III(0x78, L_checkfilter)
441 XXX(0x79)
442 XXX(0x7A)
443 XXX(0x7B)
444 XXX(0x7C)
445 XXX(0x7D)
446 XXX(0x7E)
447 XXX(0x7F)
448 III(0x80, L_coerce)
449 III(0x81, L_convert_b) // coerce_b -> convert_b, they are the same
450 XXX(0x82) /* OP_coerce_a */
451 III(0x83, L_convert_i) // coerce_i -> convert_i, they are the same
452 III(0x84, L_convert_d) // coerce_d -> convert_d, they are the same
453 III(0x85, L_coerce_s)
454 III(0x86, L_astype)
455 III(0x87, L_astypelate)
456 III(0x88, L_convert_u) // coerce_u -> convert_u, they are the same
457 III(0x89, L_coerce_o)
458 XXX(0x8A)
459 XXX(0x8B)
460 XXX(0x8C)
461 XXX(0x8D)
462 XXX(0x8E)
463 XXX(0x8F)
464 III(0x90, L_negate)
465 III(0x91, L_increment)
466 III(0x92, L_inclocal)
467 III(0x93, L_decrement)
468 III(0x94, L_declocal)
469 III(0x95, L_typeof)
470 III(0x96, L_not)
471 III(0x97, L_bitnot)
472 XXX(0x98)
473 XXX(0x99)
474 XXX(0x9A)
475 XXX(0x9B)
476 XXX(0x9C)
477 XXX(0x9D)
478 XXX(0x9E)
479 XXX(0x9F)
480 III(0xA0, L_add)
481 III(0xA1, L_subtract)
482 III(0xA2, L_multiply)
483 III(0xA3, L_divide)
484 III(0xA4, L_modulo)
485 III(0xA5, L_lshift)
486 III(0xA6, L_rshift)
487 III(0xA7, L_urshift)
488 III(0xA8, L_bitand)
489 III(0xA9, L_bitor)
490 III(0xAA, L_bitxor)
491 III(0xAB, L_equals)
492 III(0xAC, L_strictequals)
493 III(0xAD, L_lessthan)
494 III(0xAE, L_lessequals)
495 III(0xAF, L_greaterthan)
496 III(0xB0, L_greaterequals)
497 III(0xB1, L_instanceof)
498 III(0xB2, L_istype)
499 III(0xB3, L_istypelate)
500 III(0xB4, L_in)
501 XXX(0xB5)
502 XXX(0xB6)
503 XXX(0xB7)
504 XXX(0xB8)
505 XXX(0xB9)
506 XXX(0xBA)
507 XXX(0xBB)
508 XXX(0xBC)
509 XXX(0xBD)
510 XXX(0xBE)
511 XXX(0xBF)
512 III(0xC0, L_increment_i)
513 III(0xC1, L_decrement_i)
514 III(0xC2, L_inclocal_i)
515 III(0xC3, L_declocal_i)
516 III(0xC4, L_negate_i)
517 III(0xC5, L_add_i)
518 III(0xC6, L_subtract_i)
519 III(0xC7, L_multiply_i)
520 XXX(0xC8)
521 XXX(0xC9)
522 XXX(0xCA)
523 XXX(0xCB)
524 XXX(0xCC)
525 XXX(0xCD)
526 XXX(0xCE)
527 XXX(0xCF)
528 III(0xD0, L_getlocal0)
529 III(0xD1, L_getlocal1)
530 III(0xD2, L_getlocal2)
531 III(0xD3, L_getlocal3)
532 III(0xD4, L_setlocal0)
533 III(0xD5, L_setlocal1)
534 III(0xD6, L_setlocal2)
535 III(0xD7, L_setlocal3)
536 XXX(0xD8)
537 XXX(0xD9)
538 XXX(0xDA)
539 XXX(0xDB)
540 XXX(0xDC)
541 XXX(0xDD)
542 XXX(0xDE)
543 XXX(0xDF)
544 XXX(0xE0)
545 XXX(0xE1)
546 XXX(0xE2)
547 XXX(0xE3)
548 XXX(0xE4)
549 XXX(0xE5)
550 XXX(0xE6)
551 XXX(0xE7)
552 XXX(0xE8)
553 XXX(0xE9)
554 XXX(0xEA)
555 XXX(0xEB)
556 XXX(0xEC)
557 XXX(0xED)
558 XXX(0xEE)
559 IID(0xEF, L_debug)
560 IID(0xF0, L_debugline)
561 IID(0xF1, L_debugfile)
562 XXX(0xF2) /* OP_bkptline */
563 XXX(0xF3) /* OP_timestamp */
564 XXX(0xF4)
565 XXX(0xF5)
566 XXX(0xF6)
567 XXX(0xF7)
568 XXX(0xF8)
569 XXX(0xF9)
570 XXX(0xFA)
571 XXX(0xFB)
572 XXX(0xFC)
573 XXX(0xFD)
574 XXX(0xFE)
575 XXX(0xFF) /* OP_ext */
576 XXX(0x100)
577 III(0x101, L_pushbits)
578 III(0x102, L_push_doublebits)
579 IIP(0x103, L_get2locals)
580 IIP(0x104, L_get3locals)
581 IIP(0x105, L_get4locals)
582 IIP(0x106, L_get5locals)
583 IIP(0x107, L_storelocal)
584 IIP(0x108, L_add_ll)
585 IIP(0x109, L_add_set_lll)
586 IIP(0x10A, L_subtract_ll)
587 IIP(0x10B, L_multiply_ll)
588 IIP(0x10C, L_divide_ll)
589 IIP(0x10D, L_modulo_ll)
590 IIP(0x10E, L_bitand_ll)
591 IIP(0x10F, L_bitor_ll)
592 IIP(0x110, L_bitxor_ll)
593 IIP(0x111, L_add_lb)
594 IIP(0x112, L_subtract_lb)
595 IIP(0x113, L_multiply_lb)
596 IIP(0x114, L_divide_lb)
597 IIP(0x115, L_bitand_lb)
598 IIP(0x116, L_bitor_lb)
599 IIP(0x117, L_bitxor_lb)
600 IIP(0x118, L_iflt_ll)
601 IIP(0x119, L_ifnlt_ll)
602 IIP(0x11A, L_ifle_ll)
603 IIP(0x11B, L_ifnle_ll)
604 IIP(0x11C, L_ifgt_ll)
605 IIP(0x11D, L_ifngt_ll)
606 IIP(0x11E, L_ifge_ll)
607 IIP(0x11F, L_ifnge_ll)
608 IIP(0x120, L_ifeq_ll)
609 IIP(0x121, L_ifne_ll)
610 IIP(0x122, L_ifstricteq_ll)
611 IIP(0x123, L_ifstrictne_ll)
612 IIP(0x124, L_iflt_lb)
613 IIP(0x125, L_ifnlt_lb)
614 IIP(0x126, L_ifle_lb)
615 IIP(0x127, L_ifnle_lb)
616 IIP(0x128, L_ifgt_lb)
617 IIP(0x129, L_ifngt_lb)
618 IIP(0x12A, L_ifge_lb)
619 IIP(0x12B, L_ifnge_lb)
620 IIP(0x12C, L_ifeq_lb)
621 IIP(0x12D, L_ifne_lb)
622 IIP(0x12E, L_ifstricteq_lb)
623 IIP(0x12F, L_ifstrictne_lb)
624 IIP(0x130, L_swap_pop)
625 III(0x131, L_findpropglobal)
626 III(0x132, L_findpropglobalstrict)
627#if defined DEBUGGER && defined VMCFG_WORDCODE
628 IID(0x133, L_debugenter)
629 IID(0x134, L_debugexit)
630#else
631 XXX(0x133)
632 XXX(0x134)
633#endif
634 III(0x135, L_lix8)
635 III(0x136, L_lix16)
636# if defined GNUC_THREADING
637 };
638 AvmAssert(opcode_labels[0x18] == &&L_ifge)do { } while (0);
639 AvmAssert(opcode_labels[0x97] == &&L_bitnot)do { } while (0);
640 AvmAssert(opcode_labels[257] == &&L_pushbits)do { } while (0);
641# ifdef VMCFG_WORDCODE_PEEPHOLE
642 AvmAssert(opcode_labels[48 + 256] == &&L_swap_pop)do { } while (0);
643# endif
644# elif defined MSVC_X86_ASM_THREADING || defined MSVC_X86_REWRITE_THREADING
645 } // conditional run-time initialization of jump table
646# endif // threading discipline
647 return (Atom)opcode_labels;
648 } // env == 0?
649
650#endif // !VMCFG_DIRECT_THREADED
651
652 // These are local variables that are allocated to alloca'd memory;
653 // if alloca() is the real alloca() then that makes no difference, but
654 // when alloca() is redirected to the heap it makes stack frames smaller,
655 // which matters on systems with short stacks.
656 //
657 // Storage that is conditionally initialized or rarely used may be moved
658 // into this structure, to balance the benefit (smaller stack frames)
659 // with the costs (more expensive access, slightly larger code).
660 //
661 // Be careful: if a member has a destructor then an auto_ptr like mechanism is
662 // required to invoke the destructor. The ExceptionFrame gets such a mechanism
663 // when the TRY_UNLESS_HEAPMEM macro is used to initialize it.
664
665 struct InterpreterAuxiliaryFrame
666 {
667 MethodFrame methodFrame;
668 ExceptionFrame ef;
669 Multiname multiname2;
670 };
671
672#ifdef DEBUGGER
673 struct InterpreterAuxiliaryFrameWithCSN : public InterpreterAuxiliaryFrame
674 {
675 inline InterpreterAuxiliaryFrameWithCSN() : cs(CallStackNode::kEmpty) {}
676
677 CallStackNode cs;
678 };
679#endif
680
681 // OPTIMIZEME - opportunity to compute some information only when needed.
682 //
683 // Some of these, notably cpool_double and envDomain, are cached because
684 // programs that use them tend to be quite a bit slower if they're not cached. (In the
685 // ABC interpreter we should also cache cpool_int and cpool_uint.) But
686 // the caching slows down function-heavy programs that don't use them. It may
687 // be fruitful to have a bit in the info that tells the interpreter whether to
688 // set these up or not.
689
690 register AvmCore* const core = env->core();
691 register Toplevel* const toplevel = env->toplevel();
692 register MethodInfo* const info = env->method;
693 register PoolObject* const pool = info->pool();
694
695#ifdef DEBUGGER
696 const size_t kAuxFrameSize = core->debugger() ? sizeof(InterpreterAuxiliaryFrameWithCSN) : sizeof(InterpreterAuxiliaryFrame);
697#else
698 const size_t kAuxFrameSize = sizeof(InterpreterAuxiliaryFrame);
699#endif
700
701#ifdef AVMPLUS_VERBOSE
702 if (pool->isVerbose(VB_interp, info))
703 core->console << "interp " << info << '\n';
704#endif
705
706#ifdef VMCFG_WORDCODE
707 // OPTIMIZEME - code does not belong here, should be moved off the fast path.
708 //
709 // Should not have to do this on every entry, but the logic that tries to do
710 // it elsewhere is not currently working - at least the verifier installs a trampoline
711 // bypasses delegateInvoke, so the structure is not created on all paths.
712 //
713 // this block is not #ifdef VMCFG_LOOKUP_CACHE because we only want
714 // to do this when the lookup cache is being used by wordcode. we do not
715 // want to run this in the abc interpreter when combined with the JIT.
716
717 if (info->lookup_cache_size() > 0 && env->lookup_cache == NULL__null)
718 env->createLookupCache();
719#endif
720
721 // always do a stack check; this not only checks true stack overflows
722 // but also the stack limit is used to gain control for host interrupts.
723 // so this stack check doubles as an interrupt check.
724 // see also: AvmCore::handleStackOverflow().
725 core->stackCheck(env);
726
727 register GCList<GCDouble> const & cpool_double = pool->cpool_double;
728 register const boolbool interruptable = !info->isNonInterruptible();
729 register const DomainEnv* envDomain = env->domainEnv();
730 // I do *not* like making pc 'volatile'; a smart compiler may handle it well
731 // and only spill to memory across a call, but a dumb compiler may not ever
732 // keep the value in a register at all.
733 MethodSignaturep volatile ms = env->method->getMethodSignature();
734#if !defined VMCFG_WORDCODE || defined AVMPLUS_VERBOSE
735 #ifdef VMCFG_WORDCODE
736 register const bytecode_t* volatile codeStart = info->word_code_start();
737 #else
738 register const bytecode_t* volatile codeStart = ms->abc_code_start();
739 #endif
740#endif
741#ifdef VMCFG_WORDCODE
742 register const bytecode_t* /* NOT VOLATILE */ pc = info->word_code_start();
743#else
744 register const bytecode_t* /* NOT VOLATILE */ pc = ms->abc_code_start();
745#endif
746 intptr_t volatile expc=0;
747 MMgc::GC::AllocaAutoPtr _framep;
748#ifdef AVMPLUS_64BIT
749 // Allocation is guaranteed on an 8-byte boundary, but we need 16 for _setjmpex.
750 // So allocate 8 bytes extra, then round up to a 16-byte boundary.
751 register Atom* const framep =
752 (Atom*)VMPI_alloca(core, _framep,(sizeof(Atom)*(ms->frame_size()) + 8 + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + 8 + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom
)*(ms->frame_size()) + 8 + kAuxFrameSize))
753 sizeof(Atom)*(ms->frame_size())(sizeof(Atom)*(ms->frame_size()) + 8 + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + 8 + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom
)*(ms->frame_size()) + 8 + kAuxFrameSize))
754 + 8(sizeof(Atom)*(ms->frame_size()) + 8 + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + 8 + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom
)*(ms->frame_size()) + 8 + kAuxFrameSize))
755 + kAuxFrameSize)(sizeof(Atom)*(ms->frame_size()) + 8 + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + 8 + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom
)*(ms->frame_size()) + 8 + kAuxFrameSize))
;
756 register InterpreterAuxiliaryFrame* const aux_memory = (InterpreterAuxiliaryFrame*)(((uintptr_t)(framep + ms->frame_size()) + 15) & ~15);
757#else
758 register Atom* const framep =
759 (Atom*)VMPI_alloca(core, _framep,(sizeof(Atom)*(ms->frame_size()) + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom)
*(ms->frame_size()) + kAuxFrameSize))
760 sizeof(Atom)*(ms->frame_size())(sizeof(Atom)*(ms->frame_size()) + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom)
*(ms->frame_size()) + kAuxFrameSize))
761 + kAuxFrameSize)(sizeof(Atom)*(ms->frame_size()) + kAuxFrameSize > 4000
? core->gc->allocaPush(sizeof(Atom)*(ms->frame_size
()) + kAuxFrameSize, _framep) : __builtin_alloca(sizeof(Atom)
*(ms->frame_size()) + kAuxFrameSize))
;
762 union {
763 Atom* fa;
764 InterpreterAuxiliaryFrame* fi;
765 };
766 fa = framep + ms->frame_size();
767 register InterpreterAuxiliaryFrame* const aux_memory = (InterpreterAuxiliaryFrame*)fi;
768#endif
769
770 // It's essential that the MethodFrame is cleaned up upon normal exit,
771 // to keep core->currentMethodFrame in order. A throw past the frame
772 // will not perform cleanup. A manual call just before returning
773 // is *not* adequate, as we need to be able to call
774 // aux_memory->methodFrame->exit() *after* our TRY/CATCH code has
775 // completed (otherwise, it may attempt to "restore" currentStack
776 // to a bogus value). Using a real dtor here ensures we are called
777 // after any endTry().
778 EnterMethodEnv methodFrame(core, env, aux_memory->methodFrame);
779
780 register Atom* const scopeBase = framep + ms->local_count();
781 register Atom* volatile withBase = NULL__null;
782 NONDEBUGGER_ONLY( register )register int volatile scopeDepth = 0;
783 register ScopeChain* const scope = env->scope();
784
785 // Compute base of operand stack.
786 register Atom* /* NOT VOLATILE */ sp = scopeBase + ms->max_scope() - 1;
787
788 // Note: scopes can be anything but null or undefined... but scope 0
789 // (the global scope) will always be a ScriptObject*. Code that uses
790 // lots of global variables accesses this frequently, so it's worth
791 // caching.
792 ScriptObject* /* NOT VOLATILE */ globalScope = (scope->getSize() > 0)
793 ? AvmCore::atomToScriptObject(scope->getScope(0))
794 : NULL__null;
795
796 // OPTIMIZEME - opportunities for streamlining the function entry code.
797 //
798 // * With unbox/box optimization introduced and alloca removed so
799 // that the parameter are as on the heap, we could overlap the
800 // outgoing parameter area with the incoming locals. This avoids
801 // copying, and will be a win if we don't have to work hard to
802 // figure out when it's applicable.
803 //
804 // * A minor point is that rest / arguments could possibly be
805 // created by a special opcode so that those flags don't have to be
806 // checked here. Unlikely to be a time sink.
807 //
808 // Edwin has suggested that the interp() function should simply take
809 // a boxed argument array always and that the call code should always
810 // pass a boxed argument array. We'd end up with two entry points,
811 // one for boxed entry and one for unboxed entry. For interpreted
812 // code the boxed entry would jump straight into this function, and
813 // the unboxed entry would go through reboxing. For compiled code it
814 // would be the other way around, probably.
815
816 {
817 // Copy instance and args to local frame
818 const int param_count = ms->param_count();
819 for (int i=0, n = _argc < param_count ? _argc : param_count; i <= n; i++)
820 framep[i] = _atomv[i];
821
822 // Store original value of argc for createRest and createArguments.
823 // argc may be changed by the optional parameter check below.
824 int arguments_argc = _argc;
825
826 // Set optional param values. these not aliased to arguments[] since arguments[]
827 // only present with traditional prototype functions (no optional args)
828 if (info->hasOptional())
829 {
830 if (_argc < param_count)
831 {
832 // initialize default values
833 for (int i=_argc+1, o=_argc + ms->optional_count() - param_count, n=param_count; i <= n; i++, o++)
834 framep[i] = ms->getDefaultValue(o);
835 _argc = param_count;
836 }
837 }
838
839 // Set remaining locals to undefined. Don't have to init scope or stack because
840 // our conservative GC scan knows how to ignore garbage.
841 for (Atom *p = framep + 1 + param_count; p < scopeBase; p++)
842 *p = undefinedAtom;
843
844 // Capture arguments or rest array.
845 if (info->needRest())
846 {
847 framep[param_count+1] = env->createRest(_atomv, arguments_argc)->atom();
848 }
849 else if (info->needArguments())
850 {
851 // create arguments using atomv[1..argc].
852 // Even tho E3 says create an Object, E4 says create an Array so thats what we will do.
853 framep[param_count+1] = env->createArguments(_atomv, arguments_argc)->atom();
854 }
855
856#ifdef DEBUGGER
857 // in debugger builds, ensure that non-active scope entries are nulled out
858 // (really only need to do so if there's a debugger active, but not really worth checking for)
859 for (int i = 0; i < ms->max_scope(); ++i)
860 scopeBase[i] = nullObjectAtom;
861#endif
862 }
863
864#ifdef DEBUGGER
865 CallStackNode* volatile callStackNode = NULL__null;
866#ifndef VMCFG_WORDCODE
867 if (core->debugger())
868 {
869 callStackNode = new ((char*)aux_memory + offsetof(InterpreterAuxiliaryFrameWithCSN, cs)__builtin_offsetof(InterpreterAuxiliaryFrameWithCSN, cs)) CallStackNode(env, (FramePtr)framep, /*frameTraits*/0, &expc);
870 env->debugEnterInner();
871 }
872#endif
873#endif
874
875// NEXT dispatches the next instruction.
876//
877// U30ARG picks up a variable-length unsigned integer argument from the instruction
878// stream and advances the PC.
879//
880// U8ARG picks up a fixed-length unsigned byte argument from the instruction stream
881// and advances the PC.
882//
883// S24ARG picks up a fixed-length signed integer argument from the instruction stream
884// and advances the PC.
885//
886// SAVE_EXPC and variants saves the address of the current opcode in the local 'expc'.
887// Used in the case of exceptions.
888
889#ifdef AVMPLUS_VERBOSE
890# define VERBOSE if (pool->isVerbose(VB_interp, info)) showState(info, codeStart, pc-1, framep, sp, scopeDepth, scopeBase, ms->max_scope())
891#else
892# define VERBOSE
893#endif
894
895#ifdef VMCFG_WORDCODE
896
897# if defined VMCFG_DIRECT_THREADED
898# if defined GNUC_THREADING
899# define INSTR(op)case OP_op: ; L_##op: VERBOSE;
900# define NEXTcontinue goto *(*pc++)
901# elif defined MSVC_X86_REWRITE_THREADING
902# define INSTR(op)case OP_op: ; case WOP_##op: L_ ## op: VERBOSE;
903# define NEXTcontinue continue
904# elif defined MSVC_X86_ASM_THREADING
905# define INSTR(op)case OP_op: ; L_ ## op: VERBOSE;
906# define NEXTcontinue __asm { \
907 __asm mov ebx, pc \
908 __asm mov eax, [ebx] \
909 __asm add ebx, 4 \
910 __asm mov pc, ebx \
911 __asm jmp eax \
912 }
913# endif // threading discipline
914# else // VMCFG_DIRECT_THREADED
915# define INSTR(op)case OP_op: ; case WOP_##op: VERBOSE;
916# define NEXTcontinue continue
917# endif
918
919# define U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
(*pc++)
920# define U8ARG(*pc++) (*pc++)
921# define S24ARG(pc+=3, readS24(pc-3)) (intptr_t)(*pc++)
922# ifdef DEBUGGER
923 // expc is visible outside this function, so make sure it's correct.
924 // It's probably possible to adjust it on demand outside the function too,
925 // because code that accesses it will have access to "info" and can
926 // perform the adjustment.
927# define SAVE_EXPCexpc = pc-1 -codeStart expc = pc-1-info->word_code_start()
928# define SAVE_EXPC_TARGET(off)expc = pc + (off) - codeStart expc = pc + (off) - info->word_code_start()
929# else
930 // Adjusted on demand in the CATCH clause. Reduces size of interpreter function
931 // by 2.5KB of object code (x86 / gcc4.0 / -O3).
932# define SAVE_EXPCexpc = pc-1 -codeStart expc = (intptr_t)pc
933# define SAVE_EXPC_TARGET(off)expc = pc + (off) - codeStart expc = (intptr_t)(pc + (off) + 1)
934# endif
935
936#else // !VMCFG_WORDCODE
937
938# define INSTR(op)case OP_op: ; case OP_##op: VERBOSE;
939
940# define NEXTcontinue continue
941# define U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30)
942# define U8ARG(*pc++) (*pc++)
943# define S24ARG(pc+=3, readS24(pc-3)) (pc+=3, readS24(pc-3))
944# define SAVE_EXPCexpc = pc-1 -codeStart expc = pc-1-codeStart
945# define SAVE_EXPC_TARGET(off)expc = pc + (off) - codeStart expc = pc + (off) - codeStart
946
947#endif // VMCFG_WORDCODE
948
949 // The following variables are here for the following purposes:
950 //
951 // - parameter passing between shared bytecode bodies
952 //
953 // - reducing the size of the stack frame on compilers that allocate
954 // individual frame slots to individual block-scoped variables.
955 // Visual C++ is particularly bad.
956 //
957 // Please do not initialize these variables.
958 //
959 // Please do not remove the 'register' qualifier. The variables are so
960 // qualified so that their addresses can't be taken.
961 //
962 // Please do not try to put any of these in a union together.
963
964 register Atom a1, a2, a3;
965 register Atom* a2p;
966 register intptr_t i1, i2;
967 register uintptr_t u1, u2;
968 register uintptr_t u1t, u2t, u3t; // private to the generic arithmetic macros
969 register double d1, d2;
970 register boolbool b1;
971 register uint8_t ub2;
972 register ScriptObject *o1;
973 register const Multiname* multiname;
974 register MethodEnv* f;
975 register Traits* t1;
976 uint16_t uh2l; // not register - its address /can/ be taken
977 int32_t i32l; // ditto
978 float f2l; // ditto
979 double d2l; // ditto
980 Atom a1l; // ditto
981#ifndef VMCFG_WORDCODE
982 register uint32_t tmp_u30;
983 const bytecode_t* tmp_pc;
984#endif
985
986 MainLoop:
987#ifdef VMCFG_WORDCODE
988 TRY_UNLESS_HEAPMEM((char*)aux_memory + offsetof(InterpreterAuxiliaryFrame, ef), core, !info->word_code_exceptions(), kCatchAction_SearchForActionScriptExceptionHandler){ avmplus::ExceptionFrame& _ef = *(new ((char*)aux_memory
+ __builtin_offsetof(InterpreterAuxiliaryFrame, ef)) ExceptionFrame
); avmplus::ExceptionFrameAutoPtr _ef_ap(_ef); avmplus::Exception
* _ee; int _setjmpVal = 0; if ((!info->word_code_exceptions
()) || (_ef.beginTry(core), _ef.catchAction=(kCatchAction_SearchForActionScriptExceptionHandler
), _setjmpVal = ::_setjmp(_ef.jmpbuf), _ee=core->exceptionAddr
, (_setjmpVal == 0)))
{
989#else
990 TRY_UNLESS_HEAPMEM((char*)aux_memory + offsetof(InterpreterAuxiliaryFrame, ef), core, !info->abc_exceptions(), kCatchAction_SearchForActionScriptExceptionHandler){ avmplus::ExceptionFrame& _ef = *(new ((char*)aux_memory
+ __builtin_offsetof(InterpreterAuxiliaryFrame, ef)) ExceptionFrame
); avmplus::ExceptionFrameAutoPtr _ef_ap(_ef); avmplus::Exception
* _ee; int _setjmpVal = 0; if ((!info->abc_exceptions()) ||
(_ef.beginTry(core), _ef.catchAction=(kCatchAction_SearchForActionScriptExceptionHandler
), _setjmpVal = ::_setjmp(_ef.jmpbuf), _ee=core->exceptionAddr
, (_setjmpVal == 0)))
{
991#endif
992
993#ifdef DIRECT_DISPATCH
994 NEXTcontinue;
995#else
996 for (;;)
997 {
998# ifdef SUPERWORD_PROFILING
999 WordcodeTranslator::swprofPC(pc);
1000# endif
1001# ifdef VMCFG_WORDCODE
1002 AvmAssert((*pc & 65535) == ((*pc >> 16) & 65535))do { } while (0);
1003 switch ((*pc++) & 65535)
1004# else
1005 switch (*pc++)
1006# endif
1007 {
1008#endif // dispatch
1009
1010 INSTR(returnvoid)case OP_returnvoid: ; {
1011 a1 = undefinedAtom;
1012 goto return_value_from_interpreter;
1013 }
1014
1015 INSTR(returnvalue)case OP_returnvalue: ; {
1016 a1 = *sp;
1017 return_value_from_interpreter:
1018#if defined DEBUGGER && !defined VMCFG_WORDCODE
1019 if (callStackNode)
1020 {
1021 env->debugExit(callStackNode);
1022 callStackNode->reset();
1023 }
1024#endif
1025 SAVE_EXPCexpc = pc-1 -codeStart;
1026 a1 = toplevel->coerce(a1, ms->returnTraits());
1027#ifdef AVMPLUS_VERBOSE
1028 if (pool->isVerbose(VB_interp, info))
1029 core->console << "exit " << info << '\n';
1030#endif
1031 return a1;
1032 }
1033
1034 INSTR(nop)case OP_nop: ; {
1035 NEXTcontinue;
1036 }
1037
1038#ifndef VMCFG_WORDCODE
1039 INSTR(label)case OP_label: ; {
1040 NEXTcontinue;
1041 }
1042#endif
1043
1044#ifndef VMCFG_WORDCODE
1045 INSTR(timestamp)case OP_timestamp: ; {
1046 NEXTcontinue;
1047 }
1048#endif
1049
1050#ifndef VMCFG_WORDCODE
1051 INSTR(bkpt)case OP_bkpt: ; {
1052 NEXTcontinue;
1053 }
1054#endif
1055
1056#ifndef VMCFG_WORDCODE
1057 INSTR(bkptline)case OP_bkptline: ; {
1058 U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1059 NEXTcontinue;
1060 }
1061#endif
1062
1063#ifndef VMCFG_WORDCODE
1064 INSTR(coerce_a)case OP_coerce_a: ; { // no-op since interpreter only uses atoms
1065 NEXTcontinue;
1066 }
1067#endif
1068
1069#if defined DEBUGGER || !defined VMCFG_WORDCODE
1070 INSTR(debugline)case OP_debugline: ; {
1071 SAVE_EXPCexpc = pc-1 -codeStart;
1072 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1073 DEBUGGER_ONLY( if (core->debugger()) core->debugger()->debugLine((int32_t)u1); )
1074 NEXTcontinue;
1075 }
1076#endif
1077
1078#if defined DEBUGGER || !defined VMCFG_WORDCODE
1079 INSTR(debug)case OP_debug: ; {
1080 WORD_CODE_ONLY( pc += 4 );
1081 ABC_CODE_ONLY( pc += AvmCore::calculateInstructionWidth(pc-1) - 1 )pc += AvmCore::calculateInstructionWidth(pc-1) - 1;
1082 NEXTcontinue;
1083 }
1084#endif
1085
1086#if defined DEBUGGER || !defined VMCFG_WORDCODE
1087 INSTR(debugfile)case OP_debugfile: ; {
1088 SAVE_EXPCexpc = pc-1 -codeStart;
1089 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
Value stored to 'u1' is never read
1090 DEBUGGER_ONLY( if (core->debugger()) core->debugger()->debugFile(pool->getString((int32_t)u1)); )
1091 NEXTcontinue;
1092 }
1093#endif
1094
1095#if defined DEBUGGER && defined VMCFG_WORDCODE
1096 INSTR(debugenter)case OP_debugenter: ; {
1097 AvmAssert(core->debugger() != NULL)do { } while (0);
1098 AvmAssert(callStackNode == NULL)do { } while (0);
1099 callStackNode = new ((char*)aux_memory + offsetof(InterpreterAuxiliaryFrameWithCSN, cs)__builtin_offsetof(InterpreterAuxiliaryFrameWithCSN, cs)) CallStackNode(env, (FramePtr)framep, /*frameTraits*/0, &expc);
1100 env->debugEnterInner();
1101 NEXTcontinue;
1102 }
1103#endif
1104
1105#if defined DEBUGGER && defined VMCFG_WORDCODE
1106 INSTR(debugexit)case OP_debugexit: ; {
1107 AvmAssert(core->debugger() != NULL)do { } while (0);
1108 AvmAssert(callStackNode != NULL)do { } while (0);
1109 env->debugExit(callStackNode);
1110 callStackNode->reset();
1111 NEXTcontinue;
1112 }
1113#endif
1114
1115 INSTR(jump)case OP_jump: ; {
1116 i1 = S24ARG(pc+=3, readS24(pc-3));
1117 if (i1 < 0) {
1118 SAVE_EXPC_TARGET(i1)expc = pc + (i1) - codeStart;
1119 branchCheck(core, env, interruptable);
1120 OSR(i1);
1121 }
1122 pc += i1;
1123 NEXTcontinue;
1124 }
1125
1126 INSTR(pushnull)case OP_pushnull: ; {
1127 *(++sp) = nullObjectAtom;
1128 NEXTcontinue;
1129 }
1130
1131 INSTR(pushundefined)case OP_pushundefined: ; {
1132 *(++sp) = undefinedAtom;
1133 NEXTcontinue;
1134 }
1135
1136 INSTR(pushstring)case OP_pushstring: ; {
1137 *(++sp) = pool->getString((uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
)->atom();
1138 NEXTcontinue;
1139 }
1140
1141#ifndef VMCFG_WORDCODE
1142 INSTR(pushint)case OP_pushint: ; {
1143 *(++sp) = core->intToAtom(pool->cpool_int[(uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
]);
1144 NEXTcontinue;
1145 }
1146#endif
1147
1148#ifndef VMCFG_WORDCODE
1149 INSTR(pushuint)case OP_pushuint: ; {
1150 *(++sp) = core->uintToAtom(pool->cpool_uint[(uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
]);
1151 NEXTcontinue;
1152 }
1153#endif
1154
1155 INSTR(pushdouble)case OP_pushdouble: ; {
1156 *(++sp) = kDoubleType|(uintptr_t)cpool_double[(uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
];
1157 NEXTcontinue;
1158 }
1159
1160 INSTR(pushnamespace)case OP_pushnamespace: ; {
1161 *(++sp) = pool->cpool_ns[(uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
]->atom();
1162 NEXTcontinue;
1163 }
1164
1165 INSTR(getlocal)case OP_getlocal: ; {
1166 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1167 *(++sp) = framep[u1];
1168 NEXTcontinue;
1169 }
1170
1171 INSTR(getlocal0)case OP_getlocal0: ; {
1172 *(++sp) = framep[0];
1173 NEXTcontinue;
1174 }
1175
1176 INSTR(getlocal1)case OP_getlocal1: ; {
1177 *(++sp) = framep[1];
1178 NEXTcontinue;
1179 }
1180
1181 INSTR(getlocal2)case OP_getlocal2: ; {
1182 *(++sp) = framep[2];
1183 NEXTcontinue;
1184 }
1185
1186 INSTR(getlocal3)case OP_getlocal3: ; {
1187 *(++sp) = framep[3];
1188 NEXTcontinue;
1189 }
1190
1191 INSTR(pushtrue)case OP_pushtrue: ; {
1192 *(++sp) = trueAtom;
1193 NEXTcontinue;
1194 }
1195
1196 INSTR(pushfalse)case OP_pushfalse: ; {
1197 *(++sp) = falseAtom;
1198 NEXTcontinue;
1199 }
1200
1201 INSTR(pushnan)case OP_pushnan: ; {
1202 *(++sp) = core->kNaN;
1203 NEXTcontinue;
1204 }
1205
1206 INSTR(pop)case OP_pop: ; {
1207 sp--;
1208 NEXTcontinue;
1209 }
1210
1211 INSTR(dup)case OP_dup: ; {
1212 sp++;
1213 sp[0] = sp[-1];
1214 NEXTcontinue;
1215 }
1216
1217 INSTR(swap)case OP_swap: ; {
1218 a1 = sp[0];
1219 sp[0] = sp[-1];
1220 sp[-1] = a1;
1221 NEXTcontinue;
1222 }
1223
1224 INSTR(convert_s)case OP_convert_s: ; {
1225 SAVE_EXPCexpc = pc-1 -codeStart;
1226 sp[0] = core->string(sp[0])->atom();
1227 NEXTcontinue;
1228 }
1229
1230 INSTR(esc_xelem)case OP_esc_xelem: ; { // ToXMLString will call EscapeElementValue
1231 SAVE_EXPCexpc = pc-1 -codeStart;
1232 sp[0] = core->ToXMLString(sp[0])->atom();
1233 NEXTcontinue;
1234 }
1235
1236 INSTR(esc_xattr)case OP_esc_xattr: ; {
1237 SAVE_EXPCexpc = pc-1 -codeStart;
1238 sp[0] = core->EscapeAttributeValue(sp[0])->atom();
1239 NEXTcontinue;
1240 }
1241
1242 INSTR(convert_d)case OP_convert_d: ; {
1243 ABC_CODE_ONLY( convert_d_impl: )convert_d_impl:
1244 if (!IS_DOUBLE(sp[0])(((sp[0]) & 7) == kDoubleType)) {
1245 SAVE_EXPCexpc = pc-1 -codeStart;
1246 sp[0] = core->numberAtom(sp[0]);
1247 }
1248 NEXTcontinue;
1249 }
1250
1251#ifndef VMCFG_WORDCODE /* Jump table forwards to convert_d */
1252 INSTR(coerce_d)case OP_coerce_d: ; {
1253 goto convert_d_impl;
1254 }
1255#endif
1256
1257 INSTR(convert_b)case OP_convert_b: ; {
1258 ABC_CODE_ONLY( convert_b_impl: )convert_b_impl:
1259 a1 = sp[0]; // boolean value
1260 if (IS_BOOLEAN(a1)(((a1) & 7) == kBooleanType))
1261 ;
1262 else if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType))
1263 sp[0] = a1 == zeroIntAtom ? falseAtom : trueAtom;
1264 else
1265 sp[0] = AvmCore::booleanAtom(a1);
1266 NEXTcontinue;
1267 }
1268
1269#ifndef VMCFG_WORDCODE /* Jump table forwards to convert_b */
1270 INSTR(coerce_b)case OP_coerce_b: ; {
1271 goto convert_b_impl;
1272 }
1273#endif
1274
1275 INSTR(convert_o)case OP_convert_o: ; {
1276 if (AvmCore::isNullOrUndefined(sp[0])) {
1277 SAVE_EXPCexpc = pc-1 -codeStart;
1278 env->nullcheck(sp[0]);
1279 }
1280 NEXTcontinue;
1281 }
1282
1283 INSTR(negate)case OP_negate: ; {
1284 a1 = sp[0];
1285 if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType) && a1 != zeroIntAtom) {
1286 i1 = -atomGetIntptr(a1); // *not* INT32_VALUE
1287 if (atomIsValidIntptrValue(i1)) {
1288 sp[0] = MAKE_INTEGER(i1)((intptr_t(i1) << 3) | kIntptrType);
1289 NEXTcontinue;
1290 }
1291 }
1292 SAVE_EXPCexpc = pc-1 -codeStart;
1293 sp[0] = core->doubleToAtom(-AvmCore::number(a1));
1294 NEXTcontinue;
1295 }
1296
1297 INSTR(negate_i)case OP_negate_i: ; {
1298 // OPTIMIZEME - negate_i
1299 SAVE_EXPCexpc = pc-1 -codeStart;
1300 sp[0] = core->intToAtom(-AvmCore::integer(sp[0]));
1301 NEXTcontinue;
1302 }
1303
1304 INSTR(kill)case OP_kill: ; {
1305 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1306 framep[u1] = undefinedAtom;
1307 NEXTcontinue;
1308 }
1309
1310 INSTR(typeof)case OP_typeof: ; {
1311 *sp = core->_typeof(*sp)->atom();
1312 NEXTcontinue;
1313 }
1314
1315 INSTR(not)case OP_not: ; {
1316 a1 = sp[0]; // boolean value
1317 if (IS_BOOLEAN(a1)(((a1) & 7) == kBooleanType))
1318 ;
1319 else if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType))
1320 a1 = a1 == zeroIntAtom ? falseAtom : trueAtom;
1321 else
1322 a1 = AvmCore::booleanAtom(a1);
1323 sp[0] = a1 ^ (trueAtom ^ falseAtom);
1324 NEXTcontinue;
1325 }
1326
1327 INSTR(bitnot)case OP_bitnot: ; {
1328 a1 = sp[0];
1329 if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType)) {
1330 sp[0] = MAKE_INTEGER(~int32_t(atomGetIntptr(a1)))((intptr_t(~int32_t(atomGetIntptr(a1))) << 3) | kIntptrType
)
;
1331 NEXTcontinue;
1332 }
1333 SAVE_EXPCexpc = pc-1 -codeStart;
1334 *sp = core->intToAtom(~AvmCore::integer(a1));
1335 NEXTcontinue;
1336 }
1337
1338 INSTR(setlocal)case OP_setlocal: ; {
1339 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1340 framep[u1] = *(sp--);
1341 NEXTcontinue;
1342 }
1343
1344 INSTR(setlocal0)case OP_setlocal0: ; {
1345 framep[0] = *(sp--);
1346 NEXTcontinue;
1347 }
1348
1349 INSTR(setlocal1)case OP_setlocal1: ; {
1350 framep[1] = *(sp--);
1351 NEXTcontinue;
1352 }
1353
1354 INSTR(setlocal2)case OP_setlocal2: ; {
1355 framep[2] = *(sp--);
1356 NEXTcontinue;
1357 }
1358
1359 INSTR(setlocal3)case OP_setlocal3: ; {
1360 framep[3] = *(sp--);
1361 NEXTcontinue;
1362 }
1363
1364
1365
1366// Add 1 to a1 if it is a fixnum and computation does not overflow, or
1367// if a1 is a flonum. On success, store the result in dest, and NEXT.
1368
1369#define FAST_INC_MAYBE(a1,dest)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t + (1 << 3))); if ((intptr_t)u1t <
0 || (intptr_t)(u3t ^ u1t) >= 0) { dest = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { dest
= core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) + 1.0
); continue; }
\
1370 if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType)) { \
1371 u1t = a1 ^ kIntptrType; \
1372 u3t = SIGN_EXTEND(u1t + (1 << 3))(intptr_t(u1t + (1 << 3))); \
1373 if ((intptr_t)u1t < 0 || (intptr_t)(u3t ^ u1t) >= 0) { \
1374 dest = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType); \
1375 NEXTcontinue; \
1376 } \
1377 } \
1378 else if (IS_DOUBLE(a1)(((a1) & 7) == kDoubleType)) { \
1379 dest = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) + 1.0); \
1380 NEXTcontinue; \
1381 }
1382
1383#define ADD_TWO_VALUES_AND_NEXT(a1, a2, dest)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { u1t = a1 ^ kIntptrType; u2t = a2 ^ kIntptrType; u3t = (intptr_t
(u1t + u2t)); if ((intptr_t)(u1t ^ u2t) < 0 || (intptr_t)(
u1t ^ u3t) >= 0) { dest = (u3t | kIntptrType); continue; }
} else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) &
7) == 0)) { dest = core->doubleToAtom((*(double*)((a1) ^ kDoubleType
)) + (*(double*)((a2) ^ kDoubleType))); continue; } expc = pc
-1 -codeStart; dest = toplevel->add2(a1, a2); continue
\
1384 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) { \
1385 u1t = a1 ^ kIntptrType; \
1386 u2t = a2 ^ kIntptrType; \
1387 u3t = SIGN_EXTEND(u1t + u2t)(intptr_t(u1t + u2t)); \
1388 if ((intptr_t)(u1t ^ u2t) < 0 || (intptr_t)(u1t ^ u3t) >= 0) { \
1389 dest = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType); \
1390 NEXTcontinue; \
1391 } \
1392 } \
1393 else if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) { \
1394 dest = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) + DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType))); \
1395 NEXTcontinue; \
1396 } \
1397 SAVE_EXPCexpc = pc-1 -codeStart; \
1398 dest = toplevel->add2(a1, a2); \
1399 NEXTcontinue
1400
1401// Subtract 1 from a1 if a1 is a fixnum and computation does not overflow.
1402// On success, store the result in dest, and NEXT.
1403#define FAST_DEC_MAYBE(a1,dest)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t - (1 << 3))); if ((intptr_t)u1t >=
0 || (intptr_t)(u1t ^ u3t) >= 0) { dest = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { dest
= core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) - 1.0
); continue; }
\
1404 if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType)) { \
1405 u1t = a1 ^ kIntptrType; \
1406 u3t = SIGN_EXTEND(u1t - (1 << 3))(intptr_t(u1t - (1 << 3))); \
1407 if ((intptr_t)u1t >= 0 || (intptr_t)(u1t ^ u3t) >= 0) { \
1408 dest = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType); \
1409 NEXTcontinue; \
1410 } \
1411 } \
1412 else if (IS_DOUBLE(a1)(((a1) & 7) == kDoubleType)) { \
1413 dest = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) - 1.0); \
1414 NEXTcontinue; \
1415 }
1416
1417 INSTR(increment)case OP_increment: ; {
1418 SAVE_EXPCexpc = pc-1 -codeStart;
1419 a2p = sp;
1420 increment_impl:
1421 a1 = *a2p;
1422 FAST_INC_MAYBE(a1,*a2p)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t + (1 << 3))); if ((intptr_t)u1t <
0 || (intptr_t)(u3t ^ u1t) >= 0) { *a2p = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { *
a2p = core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) +
1.0); continue; }
; // note, *a2p is lvalue here
1423 *a2p = core->numberAtom(a1);
1424 core->increment_d(a2p, 1);
1425 NEXTcontinue;
1426 }
1427
1428 INSTR(inclocal)case OP_inclocal: ; {
1429 SAVE_EXPCexpc = pc-1 -codeStart;
1430 a2p = framep+U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1431 goto increment_impl;
1432 }
1433
1434 INSTR(increment_i)case OP_increment_i: ; {
1435 SAVE_EXPCexpc = pc-1 -codeStart;
1436 a2p = sp;
1437 increment_i_impl:
1438 a1 = *a2p;
1439 if (!IS_INTEGER(a1)(((a1) & 7) == kIntptrType)) {
1440 a1 = core->intAtom(a1);
1441 }
1442 FAST_INC_MAYBE(a1,*a2p)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t + (1 << 3))); if ((intptr_t)u1t <
0 || (intptr_t)(u3t ^ u1t) >= 0) { *a2p = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { *
a2p = core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) +
1.0); continue; }
; // note, *a2p is lvalue here
1443 core->increment_i(a2p, 1);
1444 NEXTcontinue;
1445 }
1446
1447 INSTR(inclocal_i)case OP_inclocal_i: ; {
1448 SAVE_EXPCexpc = pc-1 -codeStart;
1449 a2p = framep+U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1450 goto increment_i_impl;
1451 }
1452
1453 INSTR(decrement)case OP_decrement: ; {
1454 SAVE_EXPCexpc = pc-1 -codeStart;
1455 a2p = sp;
1456 decrement_impl:
1457 a1 = *a2p;
1458 FAST_DEC_MAYBE(a1,*a2p)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t - (1 << 3))); if ((intptr_t)u1t >=
0 || (intptr_t)(u1t ^ u3t) >= 0) { *a2p = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { *
a2p = core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) -
1.0); continue; }
; // note, *a2p is lvalue here
1459 *a2p = core->numberAtom(a1);
1460 core->increment_d(a2p, -1);
1461 NEXTcontinue;
1462 }
1463
1464 INSTR(declocal)case OP_declocal: ; {
1465 SAVE_EXPCexpc = pc-1 -codeStart;
1466 a2p = framep+U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1467 goto decrement_impl;
1468 }
1469
1470 INSTR(decrement_i)case OP_decrement_i: ; {
1471 SAVE_EXPCexpc = pc-1 -codeStart;
1472 a2p = sp;
1473 decrement_i_impl:
1474 a1 = *a2p;
1475 FAST_DEC_MAYBE(a1,*a2p)if ((((a1) & 7) == kIntptrType)) { u1t = a1 ^ kIntptrType
; u3t = (intptr_t(u1t - (1 << 3))); if ((intptr_t)u1t >=
0 || (intptr_t)(u1t ^ u3t) >= 0) { *a2p = (u3t | kIntptrType
); continue; } } else if ((((a1) & 7) == kDoubleType)) { *
a2p = core->doubleToAtom((*(double*)((a1) ^ kDoubleType)) -
1.0); continue; }
; // note, *a2p is lvalue here
1476 core->increment_i(a2p, -1);
1477 NEXTcontinue;
1478 }
1479
1480 INSTR(declocal_i)case OP_declocal_i: ; {
1481 SAVE_EXPCexpc = pc-1 -codeStart;
1482 a2p = framep+U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1483 goto decrement_i_impl;
1484 }
1485
1486 INSTR(add)case OP_add: ; {
1487 a1 = sp[-1];
1488 a2 = sp[0];
1489 sp--;
1490 PEEPHOLE_ONLY( add_two_values_into_tos_impl: )
1491 ADD_TWO_VALUES_AND_NEXT(a1, a2, sp[0])if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { u1t = a1 ^ kIntptrType; u2t = a2 ^ kIntptrType; u3t = (intptr_t
(u1t + u2t)); if ((intptr_t)(u1t ^ u2t) < 0 || (intptr_t)(
u1t ^ u3t) >= 0) { sp[0] = (u3t | kIntptrType); continue; }
} else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) &
7) == 0)) { sp[0] = core->doubleToAtom((*(double*)((a1) ^
kDoubleType)) + (*(double*)((a2) ^ kDoubleType))); continue;
} expc = pc-1 -codeStart; sp[0] = toplevel->add2(a1, a2);
continue
;
1492 }
1493
1494 INSTR(add_i)case OP_add_i: ; {
1495 a1 = sp[-1];
1496 a2 = sp[0];
1497 sp--;
1498 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1499 u1t = a1 ^ kIntptrType;
1500 u2t = a2 ^ kIntptrType;
1501 u3t = CLAMP_32(u1t + u2t)(intptr_t(u1t + u2t));
1502 sp[0] = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType);
1503 NEXTcontinue;
1504 }
1505 if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1506 i1 = (int32_t)AvmCore::integer_d(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)));
1507 i2 = (int32_t)AvmCore::integer_d(DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)));
1508 goto finish_add_i;
1509 }
1510 SAVE_EXPCexpc = pc-1 -codeStart;
1511 i1 = AvmCore::integer(a1);
1512 i2 = AvmCore::integer(a2);
1513 finish_add_i:
1514 sp[0] = core->intToAtom((int32_t)(i1 + i2));
1515 NEXTcontinue;
1516 }
1517
1518 INSTR(subtract)case OP_subtract: ; {
1519 a1 = sp[-1];
1520 a2 = sp[0];
1521 sp--;
1522#ifdef VMCFG_WORDCODE_PEEPHOLE
1523 sub_two_values_and_next:
1524#endif
1525 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1526 u1t = a1 ^ kIntptrType;
1527 u2t = a2 ^ kIntptrType;
1528 u3t = SIGN_EXTEND(u1t - u2t)(intptr_t(u1t - u2t));
1529 if ((intptr_t)(u1t ^ u2t) >= 0 || (intptr_t)(u1t ^ u3t) >= 0) {
1530 sp[0] = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType);
1531 NEXTcontinue;
1532 }
1533 }
1534 if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1535 sp[0] = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) - DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)));
1536 NEXTcontinue;
1537 }
1538 SAVE_EXPCexpc = pc-1 -codeStart;
1539 d1 = AvmCore::number(a1);
1540 d2 = AvmCore::number(a2);
1541 sp[0] = core->doubleToAtom(d1 - d2);
1542 NEXTcontinue;
1543 }
1544
1545 INSTR(subtract_i)case OP_subtract_i: ; {
1546 a1 = sp[-1];
1547 a2 = sp[0];
1548 sp--;
1549 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1550 u1t = a1 ^ kIntptrType;
1551 u2t = a2 ^ kIntptrType;
1552 u3t = CLAMP_32(u1t - u2t)(intptr_t(u1t - u2t));
1553 sp[0] = CHECK_INT_ATOM(u3t | kIntptrType)(u3t | kIntptrType);
1554 NEXTcontinue;
1555 }
1556 if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1557 i1 = (int32_t)AvmCore::integer_d(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)));
1558 i2 = (int32_t)AvmCore::integer_d(DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)));
1559 goto finish_subtract_i;
1560 }
1561 SAVE_EXPCexpc = pc-1 -codeStart;
1562 i1 = AvmCore::integer(a1);
1563 i2 = AvmCore::integer(a2);
1564 finish_subtract_i:
1565 sp[0] = core->intToAtom((int32_t)(i1 - i2));
1566 NEXTcontinue;
1567 }
1568
1569 INSTR(multiply)case OP_multiply: ; {
1570 a1 = sp[-1];
1571 a2 = sp[0];
1572 sp--;
1573#ifdef VMCFG_WORDCODE_PEEPHOLE
1574 mul_two_values_and_next:
1575#endif
1576 // OPTIMIZEME - multiplication of small integers might be optimized?
1577 if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1578 sp[0] = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) * DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType))); \
1579 NEXTcontinue;
1580 }
1581 SAVE_EXPCexpc = pc-1 -codeStart;
1582 d1 = AvmCore::number(a1);
1583 d2 = AvmCore::number(a2);
1584 sp[0] = core->doubleToAtom(d1 * d2);
1585 NEXTcontinue;
1586 }
1587
1588 INSTR(multiply_i)case OP_multiply_i: ; {
1589 // OPTIMIZEME - multiplication of small integers might be optimized?
1590 SAVE_EXPCexpc = pc-1 -codeStart;
1591 a1 = sp[-1];
1592 a2 = sp[0];
1593 sp--;
1594 i1 = AvmCore::integer(a1);
1595 i2 = AvmCore::integer(a2);
1596 sp[0] = core->intToAtom((int32_t)(i1 * i2));
1597 NEXTcontinue;
1598 }
1599
1600 INSTR(divide)case OP_divide: ; {
1601 // OPTIMIZEME - division of small integers might be optimized?
1602 a1 = sp[-1];
1603 a2 = sp[0];
1604 sp--;
1605#ifdef VMCFG_WORDCODE_PEEPHOLE
1606 div_two_values_and_next:
1607#endif
1608 if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1609 sp[0] = core->doubleToAtom(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) / DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)));
1610 NEXTcontinue;
1611 }
1612 SAVE_EXPCexpc = pc-1 -codeStart;
1613 d1 = AvmCore::number(a1);
1614 d2 = AvmCore::number(a2);
1615 sp[0] = core->doubleToAtom(d1 / d2);
1616 NEXTcontinue;
1617 }
1618
1619 INSTR(modulo)case OP_modulo: ; {
1620 // FIXME - dodgy optimization?
1621 // Can the integer modulo overflow somehow? Is it portable?
1622 a1 = sp[-1];
1623 a2 = sp[0];
1624 sp--;
1625#ifdef VMCFG_WORDCODE_PEEPHOLE
1626 mod_two_values_and_next:
1627#endif
1628 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0) && a2 != zeroIntAtom) {
1629 i1 = INT32_VALUE(a1)int32_t(atomGetIntptr(a1)) % INT32_VALUE(a2)int32_t(atomGetIntptr(a2));
1630 if (atomIsValidIntptrValue(i1)) {
1631 sp[0] = MAKE_INTEGER(i1)((intptr_t(i1) << 3) | kIntptrType);
1632 NEXTcontinue;
1633 }
1634 }
1635 else if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) {
1636 sp[0] = core->doubleToAtom(MathUtils::mod(DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)), DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType))));
1637 NEXTcontinue;
1638 }
1639 SAVE_EXPCexpc = pc-1 -codeStart;
1640 d1 = AvmCore::number(a1);
1641 d2 = AvmCore::number(a2);
1642 sp[0] = core->doubleToAtom(MathUtils::mod(d1, d2));
1643 NEXTcontinue;
1644 }
1645
1646 INSTR(lshift)case OP_lshift: ; {
1647 a1 = sp[-1];
1648 a2 = sp[0];
1649 sp--;
1650 //lshift_two_values_and_next:
1651 if (IS_BOTH_INTEGER(a1,a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1652 i1 = INT32_VALUE(a1)int32_t(atomGetIntptr(a1)) << (INT32_VALUE(a2)int32_t(atomGetIntptr(a2)) & 0x1F);
1653 if (atomIsValidIntptrValue(i1)) {
1654 sp[0] = SIGN_EXTEND(MAKE_INTEGER(i1))(intptr_t(((intptr_t(i1) << 3) | kIntptrType)));
1655 NEXTcontinue;
1656 }
1657 }
1658 SAVE_EXPCexpc = pc-1 -codeStart;
1659 i1 = AvmCore::integer(a1);
1660 u2 = AvmCore::toUInt32(a2);
1661 sp[0] = core->intToAtom( (int32_t)(i1 << (u2 & 0x1F)) );
1662 NEXTcontinue;
1663 }
1664
1665 INSTR(rshift)case OP_rshift: ; {
1666 a1 = sp[-1];
1667 a2 = sp[0];
1668 sp--;
1669 //rshift_two_values_and_next:
1670 if (IS_BOTH_INTEGER(a1,a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1671 sp[0] = MAKE_INTEGER(INT32_VALUE(a1) >> (INT32_VALUE(a2) & 0x1F))((intptr_t(int32_t(atomGetIntptr(a1)) >> (int32_t(atomGetIntptr
(a2)) & 0x1F)) << 3) | kIntptrType)
;
1672 NEXTcontinue;
1673 }
1674 SAVE_EXPCexpc = pc-1 -codeStart;
1675 i1 = AvmCore::integer(a1);
1676 u2 = AvmCore::toUInt32(a2);
1677 sp[0] = core->intToAtom( (int32_t)(i1 >> (u2 & 0x1F)) );
1678 NEXTcontinue;
1679 }
1680
1681 INSTR(urshift)case OP_urshift: ; {
1682 a1 = sp[-1];
1683 a2 = sp[0];
1684 sp--;
1685 //urshift_two_values_and_next:
1686 if (IS_BOTH_INTEGER(a1,a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) {
1687 u1 = (UINT32_VALUE(a1)uint32_t(atomGetIntptr(a1)) >> (INT32_VALUE(a2)int32_t(atomGetIntptr(a2)) & 0x1F));
1688 if (atomIsValidIntptrValue_u(u1)) {
1689 sp[0] = MAKE_INTEGER(u1)((intptr_t(u1) << 3) | kIntptrType);
1690 NEXTcontinue;
1691 }
1692 }
1693 SAVE_EXPCexpc = pc-1 -codeStart;
1694 u1 = AvmCore::toUInt32(a1);
1695 u2 = AvmCore::toUInt32(a2);
1696 sp[0] = core->uintToAtom( (uint32_t)(u1 >> (u2 & 0x1F)) );
1697 NEXTcontinue;
1698 }
1699
1700// The OR with tag is only necessary for xor, which passes kIntptrType. The
1701// others pass 0, and we assume the compiler optimizes the OR away.
1702
1703#define BITOP_TWO_VALUES_AND_NEXT(op, a1, a2, dest, tag)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { dest = ((intptr_t((a1) op (a2))) | tag); continue; } expc
= pc-1 -codeStart; i1 = AvmCore::integer(a1); i2 = AvmCore::
integer(a2); dest = core->intToAtom((int32_t)(i1 op i2)); continue
\
1704 if (IS_BOTH_INTEGER(a1,a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) { \
1705 dest = (CLAMP_32((a1) op (a2))(intptr_t((a1) op (a2))) | tag); \
1706 NEXTcontinue; \
1707 } \
1708 SAVE_EXPCexpc = pc-1 -codeStart; \
1709 i1 = AvmCore::integer(a1); \
1710 i2 = AvmCore::integer(a2); \
1711 dest = core->intToAtom((int32_t)(i1 op i2)); \
1712 NEXTcontinue
1713
1714 INSTR(bitand)case OP_bitand: ; {
1715 a1 = sp[-1];
1716 a2 = sp[0];
1717 sp--;
1718#ifdef VMCFG_WORDCODE_PEEPHOLE
1719 bitand_two_values_and_next:
1720#endif
1721 BITOP_TWO_VALUES_AND_NEXT(&, a1, a2, sp[0], 0)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { sp[0] = ((intptr_t((a1) & (a2))) | 0); continue; } expc
= pc-1 -codeStart; i1 = AvmCore::integer(a1); i2 = AvmCore::
integer(a2); sp[0] = core->intToAtom((int32_t)(i1 & i2
)); continue
;
1722 }
1723
1724 INSTR(bitor)case OP_bitor: ; {
1725 a1 = sp[-1];
1726 a2 = sp[0];
1727 sp--;
1728#ifdef VMCFG_WORDCODE_PEEPHOLE
1729 bitor_two_values_and_next:
1730#endif
1731 BITOP_TWO_VALUES_AND_NEXT(|, a1, a2, sp[0], 0)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { sp[0] = ((intptr_t((a1) | (a2))) | 0); continue; } expc =
pc-1 -codeStart; i1 = AvmCore::integer(a1); i2 = AvmCore::integer
(a2); sp[0] = core->intToAtom((int32_t)(i1 | i2)); continue
;
1732 }
1733
1734 INSTR(bitxor)case OP_bitxor: ; {
1735 a1 = sp[-1];
1736 a2 = sp[0];
1737 sp--;
1738#ifdef VMCFG_WORDCODE_PEEPHOLE
1739 bitxor_two_values_and_next:
1740#endif
1741 BITOP_TWO_VALUES_AND_NEXT(^, a1, a2, sp[0], kIntptrType)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { sp[0] = ((intptr_t((a1) ^ (a2))) | kIntptrType); continue
; } expc = pc-1 -codeStart; i1 = AvmCore::integer(a1); i2 = AvmCore
::integer(a2); sp[0] = core->intToAtom((int32_t)(i1 ^ i2))
; continue
;
1742 }
1743
1744 INSTR(equals)case OP_equals: ; {
1745 // OPTIMIZEME - equals on some classes of values?
1746 SAVE_EXPCexpc = pc-1 -codeStart;
1747 sp[-1] = core->equals(sp[-1], sp[0]);
1748 sp--;
1749 NEXTcontinue;
1750 }
1751
1752 INSTR(strictequals)case OP_strictequals: ; {
1753 // OPTIMIZEME - strictequals on some classes of values?
1754 sp[-1] = core->stricteq(sp[-1], sp[0]);
1755 sp--;
1756 NEXTcontinue;
1757 }
1758
1759 INSTR(lookupswitch)case OP_lookupswitch: ; {
1760#ifdef VMCFG_WORDCODE
1761 const uintptr_t* base = pc-1;
1762 uint32_t index = AvmCore::integer_i(*(sp--));
1763 intptr_t default_offset = S24ARG(pc+=3, readS24(pc-3));
1764 uintptr_t case_count = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1765 if (index <= case_count)
1766 pc = base + pc[index];
1767 else
1768 pc = base + default_offset;
1769#else
1770 const uint8_t* base = pc-1;
1771 // safe to assume int since verifier checks for int
1772 uint32_t index = AvmCore::integer_i(*(sp--));
1773 const uint8_t* switch_pc = pc+3;
1774 uint32_t case_count = uint32_t(readU30(switch_pc)) + 1;
1775 pc = base+readS24( index < case_count ? (switch_pc + 3*index) : pc );
1776#endif
1777 if (pc <= base) {
1778 // if backedge, need an interrupt check
1779 SAVE_EXPCexpc = pc-1 -codeStart; // interrupts should originate from target of backedge
1780 branchCheck(core, env, interruptable);
1781 }
1782 NEXTcontinue;
1783 }
1784
1785 INSTR(iftrue)case OP_iftrue: ; {
1786 a2 = trueAtom;
1787 branch_on_boolean:
1788 a1 = *(sp--);
1789 if (IS_BOOLEAN(a1)(((a1) & 7) == kBooleanType))
1790 ;
1791 else if (IS_INTEGER(a1)(((a1) & 7) == kIntptrType))
1792 a1 = a1 == zeroIntAtom ? falseAtom : trueAtom;
1793 else
1794 a1 = AvmCore::booleanAtom(a1); // does not throw or change the XML namespace
1795 i1 = S24ARG(pc+=3, readS24(pc-3));
1796 if (a1 == a2)
1797 {
1798 if (i1 < 0) {
1799 SAVE_EXPC_TARGET(i1)expc = pc + (i1) - codeStart;
1800 branchCheck(core, env, interruptable);
1801 OSR(i1);
1802 }
1803 pc += i1;
1804 }
1805 NEXTcontinue;
1806 }
1807
1808 INSTR(iffalse)case OP_iffalse: ; {
1809 a2 = falseAtom;
1810 goto branch_on_boolean;
1811 }
1812
1813// The client of IFCMP_TWO_VALUES must save the EXPC before extracting
1814// the operands from the instruction stream because it is used in various
1815// contexts where the instruction sizes and layouts aren't the same.
1816
1817#define GENERATE_FLAG(numeric_cmp, generic_cmp, a1, a2)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 numeric_cmp a2; else if (((((a1 ^ kDoubleType) | (
a2 ^ kDoubleType)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType
)) numeric_cmp (*(double*)((a2) ^ kDoubleType)); else b1 = generic_cmp
\
1818 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) \
1819 b1 = a1 numeric_cmp a2; \
1820 else if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) \
1821 b1 = DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) numeric_cmp DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)); \
1822 else \
1823 b1 = generic_cmp
1824
1825#define IFCMP_TWO_VALUES(numeric_cmp, generic_cmp, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 numeric_cmp a2; else if (((((a1 ^ kDoubleType) | (
a2 ^ kDoubleType)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType
)) numeric_cmp (*(double*)((a2) ^ kDoubleType)); else b1 = generic_cmp
; if (b1) { if (i1 < 0) { expc = pc + (i1) - codeStart; branchCheck
(core, env, interruptable); ; } pc += i1; }
\
1826 GENERATE_FLAG(numeric_cmp, generic_cmp, a1, a2)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 numeric_cmp a2; else if (((((a1 ^ kDoubleType) | (
a2 ^ kDoubleType)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType
)) numeric_cmp (*(double*)((a2) ^ kDoubleType)); else b1 = generic_cmp
; \
1827 if (b1) \
1828 { \
1829 if (i1 < 0) \
1830 { \
1831 SAVE_EXPC_TARGET(i1)expc = pc + (i1) - codeStart; \
1832 branchCheck(core, env, interruptable); \
1833 OSR(i1); \
1834 } \
1835 pc += i1; \
1836 }
1837
1838#define IFNCMP_TWO_VALUES(numeric_cmp, generic_cmp, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 numeric_cmp a2; else if (((((a1 ^ kDoubleType) | (
a2 ^ kDoubleType)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType
)) numeric_cmp (*(double*)((a2) ^ kDoubleType)); else b1 = generic_cmp
; if (!b1) { if (i1 < 0) { expc = pc + (i1) - codeStart; branchCheck
(core, env, interruptable); ; } pc += i1; }
\
1839 GENERATE_FLAG(numeric_cmp, generic_cmp, a1, a2)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 numeric_cmp a2; else if (((((a1 ^ kDoubleType) | (
a2 ^ kDoubleType)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType
)) numeric_cmp (*(double*)((a2) ^ kDoubleType)); else b1 = generic_cmp
; \
1840 if (!b1) \
1841 { \
1842 if (i1 < 0) \
1843 { \
1844 SAVE_EXPC_TARGET(i1)expc = pc + (i1) - codeStart; \
1845 branchCheck(core, env, interruptable); \
1846 OSR(i1); \
1847 } \
1848 pc += i1; \
1849 }
1850
1851#define LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
\
1852 SAVE_EXPCexpc = pc-1 -codeStart; \
1853 a1 = sp[-1]; \
1854 a2 = sp[0]; \
1855 sp -= 2; \
1856 i1 = S24ARG(pc+=3, readS24(pc-3))
1857
1858 INSTR(ifeq)case OP_ifeq: ; {
1859 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1860 PEEPHOLE_ONLY( compare_eq_and_branch_impl: )
1861 IFCMP_TWO_VALUES(==, core->equals(a1,a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 == a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) == (
*(double*)((a2) ^ kDoubleType)); else b1 = core->equals(a1
,a2) == trueAtom; if (b1) { if (i1 < 0) { expc = pc + (i1)
- codeStart; branchCheck(core, env, interruptable); ; } pc +=
i1; }
;
1862 NEXTcontinue;
1863 }
1864
1865 INSTR(ifne)case OP_ifne: ; {
1866 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1867 PEEPHOLE_ONLY( compare_ne_and_branch_impl: )
1868 IFNCMP_TWO_VALUES(==, core->equals(a1,a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 == a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) == (
*(double*)((a2) ^ kDoubleType)); else b1 = core->equals(a1
,a2) == trueAtom; if (!b1) { if (i1 < 0) { expc = pc + (i1
) - codeStart; branchCheck(core, env, interruptable); ; } pc +=
i1; }
;
1869 NEXTcontinue;
1870 }
1871
1872 INSTR(ifstricteq)case OP_ifstricteq: ; {
1873 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1874 PEEPHOLE_ONLY( compare_stricteq_and_branch_impl: )
1875 IFCMP_TWO_VALUES(==, core->stricteq(a1,a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 == a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) == (
*(double*)((a2) ^ kDoubleType)); else b1 = core->stricteq(
a1,a2) == trueAtom; if (b1) { if (i1 < 0) { expc = pc + (i1
) - codeStart; branchCheck(core, env, interruptable); ; } pc +=
i1; }
;
1876 NEXTcontinue;
1877 }
1878
1879 INSTR(ifstrictne)case OP_ifstrictne: ; {
1880 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1881 PEEPHOLE_ONLY( compare_strictne_and_branch_impl: )
1882 IFNCMP_TWO_VALUES(==, core->stricteq(a1,a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 == a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) == (
*(double*)((a2) ^ kDoubleType)); else b1 = core->stricteq(
a1,a2) == trueAtom; if (!b1) { if (i1 < 0) { expc = pc + (
i1) - codeStart; branchCheck(core, env, interruptable); ; } pc
+= i1; }
;
1883 NEXTcontinue;
1884 }
1885
1886 INSTR(iflt)case OP_iflt: ; {
1887 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1888 PEEPHOLE_ONLY( compare_lt_and_branch_impl: )
1889 IFCMP_TWO_VALUES(<, core->compare(a1,a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 < a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) <
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a1,a2) == trueAtom; if (b1) { if (i1 < 0) { expc = pc + (
i1) - codeStart; branchCheck(core, env, interruptable); ; } pc
+= i1; }
;
1890 NEXTcontinue;
1891 }
1892
1893 INSTR(ifnlt)case OP_ifnlt: ; {
1894 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1895 PEEPHOLE_ONLY( compare_nlt_and_branch_impl: )
1896 IFNCMP_TWO_VALUES(<, core->compare(a1, a2) == trueAtom, a1, a2, i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 < a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) <
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a1, a2) == trueAtom; if (!b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1897 NEXTcontinue;
1898 }
1899
1900 INSTR(ifle)case OP_ifle: ; {
1901 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1902 PEEPHOLE_ONLY( compare_le_and_branch_impl: )
1903 IFCMP_TWO_VALUES(<=, core->compare(a2, a1) == falseAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 <= a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) <=
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a2, a1) == falseAtom; if (b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1904 NEXTcontinue;
1905 }
1906
1907 INSTR(ifnle)case OP_ifnle: ; {
1908 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1909 PEEPHOLE_ONLY( compare_nle_and_branch_impl: )
1910 IFNCMP_TWO_VALUES(<=, core->compare(a2, a1) == falseAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 <= a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) <=
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a2, a1) == falseAtom; if (!b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1911 NEXTcontinue;
1912 }
1913
1914 INSTR(ifgt)case OP_ifgt: ; {
1915 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1916 PEEPHOLE_ONLY( compare_gt_and_branch_impl: )
1917 IFCMP_TWO_VALUES(>, core->compare(a2, a1) == trueAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 > a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) >
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a2, a1) == trueAtom; if (b1) { if (i1 < 0) { expc = pc + (
i1) - codeStart; branchCheck(core, env, interruptable); ; } pc
+= i1; }
;
1918 NEXTcontinue;
1919 }
1920
1921 INSTR(ifngt)case OP_ifngt: ; {
1922 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1923 PEEPHOLE_ONLY( compare_ngt_and_branch_impl: )
1924 IFNCMP_TWO_VALUES(>, core->compare(a2, a1) == trueAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 > a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) >
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a2, a1) == trueAtom; if (!b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1925 NEXTcontinue;
1926 }
1927
1928 INSTR(ifge)case OP_ifge: ; {
1929 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1930 PEEPHOLE_ONLY( compare_ge_and_branch_impl: )
1931 IFCMP_TWO_VALUES(>=, core->compare(a1, a2) == falseAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 >= a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) >=
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a1, a2) == falseAtom; if (b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1932 NEXTcontinue;
1933 }
1934
1935 INSTR(ifnge)case OP_ifnge: ; {
1936 LOAD_OFFSET_AND_FETCH_SS(a1,a2,i1)expc = pc-1 -codeStart; a1 = sp[-1]; a2 = sp[0]; sp -= 2; i1 =
(pc+=3, readS24(pc-3))
;
1937 PEEPHOLE_ONLY( compare_nge_and_branch_impl: )
1938 IFNCMP_TWO_VALUES(>=, core->compare(a1, a2) == falseAtom,a1,a2,i1)if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) b1 = a1 >= a2; else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) b1 = (*(double*)((a1) ^ kDoubleType)) >=
(*(double*)((a2) ^ kDoubleType)); else b1 = core->compare
(a1, a2) == falseAtom; if (!b1) { if (i1 < 0) { expc = pc +
(i1) - codeStart; branchCheck(core, env, interruptable); ; }
pc += i1; }
;
1939 NEXTcontinue;
1940 }
1941
1942#define CMP2(numeric_cmp, generic_cmp)a1 = sp[-1]; a2 = sp[0]; sp--; if (((((a1 ^ kIntptrType) | (a2
^ kIntptrType)) & 7) == 0)) b1 = a1 numeric_cmp a2; else
if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0
)) b1 = (*(double*)((a1) ^ kDoubleType)) numeric_cmp (*(double
*)((a2) ^ kDoubleType)); else { expc = pc-1 -codeStart; b1 = generic_cmp
; } sp[0] = b1 ? trueAtom : falseAtom;
\
1943 a1 = sp[-1]; \
1944 a2 = sp[0]; \
1945 sp--; \
1946 if (IS_BOTH_INTEGER(a1, a2)((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0)) \
1947 b1 = a1 numeric_cmp a2; \
1948 else if (IS_BOTH_DOUBLE(a1, a2)((((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) \
1949 b1 = DOUBLE_VALUE(a1)(*(double*)((a1) ^ kDoubleType)) numeric_cmp DOUBLE_VALUE(a2)(*(double*)((a2) ^ kDoubleType)); \
1950 else { \
1951 SAVE_EXPCexpc = pc-1 -codeStart; \
1952 b1 = generic_cmp; \
1953 } \
1954 sp[0] = b1 ? trueAtom : falseAtom;
1955
1956 INSTR(lessthan)case OP_lessthan: ; {
1957 CMP2(<, core->compare(a1,a2) == trueAtom)a1 = sp[-1]; a2 = sp[0]; sp--; if (((((a1 ^ kIntptrType) | (a2
^ kIntptrType)) & 7) == 0)) b1 = a1 < a2; else if (((
((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) b1 =
(*(double*)((a1) ^ kDoubleType)) < (*(double*)((a2) ^ kDoubleType
)); else { expc = pc-1 -codeStart; b1 = core->compare(a1,a2
) == trueAtom; } sp[0] = b1 ? trueAtom : falseAtom;
;
1958 NEXTcontinue;
1959 }
1960
1961 INSTR(lessequals)case OP_lessequals: ; {
1962 CMP2(<=, core->compare(a2, a1) == falseAtom)a1 = sp[-1]; a2 = sp[0]; sp--; if (((((a1 ^ kIntptrType) | (a2
^ kIntptrType)) & 7) == 0)) b1 = a1 <= a2; else if ((
(((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) b1
= (*(double*)((a1) ^ kDoubleType)) <= (*(double*)((a2) ^ kDoubleType
)); else { expc = pc-1 -codeStart; b1 = core->compare(a2, a1
) == falseAtom; } sp[0] = b1 ? trueAtom : falseAtom;
;
1963 NEXTcontinue;
1964 }
1965
1966 INSTR(greaterthan)case OP_greaterthan: ; {
1967 CMP2(>, core->compare(a2, a1) == trueAtom)a1 = sp[-1]; a2 = sp[0]; sp--; if (((((a1 ^ kIntptrType) | (a2
^ kIntptrType)) & 7) == 0)) b1 = a1 > a2; else if (((
((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) b1 =
(*(double*)((a1) ^ kDoubleType)) > (*(double*)((a2) ^ kDoubleType
)); else { expc = pc-1 -codeStart; b1 = core->compare(a2, a1
) == trueAtom; } sp[0] = b1 ? trueAtom : falseAtom;
;
1968 NEXTcontinue;
1969 }
1970
1971 INSTR(greaterequals)case OP_greaterequals: ; {
1972 CMP2(>=, core->compare(a1, a2) == falseAtom)a1 = sp[-1]; a2 = sp[0]; sp--; if (((((a1 ^ kIntptrType) | (a2
^ kIntptrType)) & 7) == 0)) b1 = a1 >= a2; else if ((
(((a1 ^ kDoubleType) | (a2 ^ kDoubleType)) & 7) == 0)) b1
= (*(double*)((a1) ^ kDoubleType)) >= (*(double*)((a2) ^ kDoubleType
)); else { expc = pc-1 -codeStart; b1 = core->compare(a1, a2
) == falseAtom; } sp[0] = b1 ? trueAtom : falseAtom;
;
1973 NEXTcontinue;
1974 }
1975
1976 INSTR(newobject)case OP_newobject: ; {
1977 SAVE_EXPCexpc = pc-1 -codeStart;
1978 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1979 a1 = env->op_newobject(sp, (int)i1)->atom();
1980 *(sp -= 2*i1-1) = a1;
1981 NEXTcontinue;
1982 }
1983
1984 INSTR(newarray)case OP_newarray: ; {
1985 SAVE_EXPCexpc = pc-1 -codeStart;
1986 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
1987 a1 = avmplus::newarray(toplevel, (int)i1, sp-i1+1)->atom();
1988 *(sp -= i1-1) = a1;
1989 NEXTcontinue;
1990 }
1991
1992// OPTIMIZEME - isRuntime and isRtns are known at translation time.
1993// Using type information in the verifier it may be possible to determine
1994// that isDictionaryLookup is false, too. Should specialize instructions to
1995// handle common cases.
1996//
1997// But does it matter? getproperty, findproperty are heavyweight operations, and
1998// opportunities for early binding are resolved during translation. Still, it may
1999// make a small difference in connection with avoiding multiname copying (now implemented),
2000// since most fields of the multiname data structure will not be accessed.
2001
2002// OPTIMIZEME - inline fast case for toVTable?
2003// Presumably it will very often be a non-null object; now we have to make a call and
2004// a test and a switch to get to that. Should we in-line?
2005// How will RTTI caching affect that?
2006
2007#define GET_MULTINAME_PTR(decl, arg)decl = pool->precomputedMultiname(uint32_t(arg)) decl = pool->precomputedMultiname(uint32_t(arg))
2008
2009 INSTR(getlex)case OP_getlex: ; {
2010 SAVE_EXPCexpc = pc-1 -codeStart;
2011 // findpropstrict + getproperty
2012 // stack in: -
2013 // stack out: value
2014 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2015 // only non-runtime names are allowed. but this still includes
2016 // wildcard and attribute names.
2017 a1 = env->findproperty(scope, scopeBase, scopeDepth, multiname, truetrue, withBase);
2018 *(++sp) = toplevel->getproperty(a1, multiname, toplevel->toVTable(a1));
2019 NEXTcontinue;
2020 }
2021
2022#if 0
2023 // Multiname is neither isRuntime or isRtns
2024 INSTR(getproperty_fast)case OP_getproperty_fast: ; {
2025 SAVE_EXPCexpc = pc-1 -codeStart;
2026 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2027 sp[0] = toplevel->getproperty(sp[0], multiname, toplevel->toVTable(sp[0]));
2028 NEXTcontinue;
2029 }
2030#endif
2031
2032 // get a property using a multiname ref
2033 INSTR(getproperty)case OP_getproperty: ; {
2034 SAVE_EXPCexpc = pc-1 -codeStart;
2035 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2036 if (!multiname->isRuntime())
2037 {
2038 *sp = toplevel->getproperty(*sp, multiname, toplevel->toVTable(*sp));
2039 }
2040 else if (!multiname->isRtns() && IS_INTEGER(*sp)(((*sp) & 7) == kIntptrType) && atomCanBeUint32(*sp) && AvmCore::isObject(sp[-1]))
2041 {
2042 a2 = *(sp--); // key
2043 *sp = AvmCore::atomToScriptObject(*sp)->getUintProperty(UINT32_VALUE(a2)uint32_t(atomGetIntptr(a2)));
2044 }
2045 else if(multiname->isRtns() || !AvmCore::isDictionaryLookup(*sp, *(sp-1)))
2046 {
2047 aux_memory->multiname2 = *multiname;
2048 sp = initMultiname(env, aux_memory->multiname2, sp);
2049 *sp = toplevel->getproperty(*sp, &aux_memory->multiname2, toplevel->toVTable(*sp));
2050 }
2051 else
2052 {
2053 a2 = *(sp--); // key
2054 *sp = AvmCore::atomToScriptObject(*sp)->getAtomProperty(a2);
2055 }
2056 NEXTcontinue;
2057 }
2058
2059 // set a property using a multiname ref
2060 INSTR(setproperty)case OP_setproperty: ; {
2061 SAVE_EXPCexpc = pc-1 -codeStart;
2062 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2063 a1 = *(sp--); // value
2064 if (!multiname->isRuntime())
2065 {
2066 a3 = *(sp--); // object
2067 toplevel->setproperty(a3, multiname, a1, toplevel->toVTable(a3));
2068 }
2069 else if (!multiname->isRtns() && IS_INTEGER(*sp)(((*sp) & 7) == kIntptrType) && atomCanBeUint32(*sp) && AvmCore::isObject(sp[-1]))
2070 {
2071 a2 = *(sp--); // key
2072 a3 = *(sp--); // object
2073 AvmCore::atomToScriptObject(a3)->setUintProperty(UINT32_VALUE(a2)uint32_t(atomGetIntptr(a2)), a1);
2074 }
2075 else if(multiname->isRtns() || !AvmCore::isDictionaryLookup(*sp, *(sp-1)))
2076 {
2077 aux_memory->multiname2 = *multiname;
2078 sp = initMultiname(env, aux_memory->multiname2, sp);
2079 a3 = *(sp--); // object
2080 toplevel->setproperty(a3, &aux_memory->multiname2, a1, toplevel->toVTable(a3));
2081 }
2082 else
2083 {
2084 a2 = *(sp--); // key
2085 a3 = *(sp--); // object
2086 AvmCore::atomToScriptObject(a3)->setAtomProperty(a2, a1);
2087 }
2088 NEXTcontinue;
2089 }
2090
2091 INSTR(initproperty)case OP_initproperty: ; {
2092 SAVE_EXPCexpc = pc-1 -codeStart;
2093 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2094 a1 = *(sp--); // value
2095 if (multiname->isRuntime())
2096 {
2097 aux_memory->multiname2 = *multiname;
2098 sp = initMultiname(env, aux_memory->multiname2, sp);
2099 multiname = &aux_memory->multiname2;
2100 }
2101 a2 = *(sp--); // object
2102 env->initproperty(a2, multiname, a1, toplevel->toVTable(a2));
2103 NEXTcontinue;
2104 }
2105
2106 INSTR(getdescendants)case OP_getdescendants: ; {
2107 SAVE_EXPCexpc = pc-1 -codeStart;
2108 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2109 if (multiname->isRuntime())
2110 {
2111 aux_memory->multiname2 = *multiname;
2112 sp = initMultiname(env, aux_memory->multiname2, sp);
2113 multiname = &aux_memory->multiname2;
2114 }
2115 sp[0] = env->getdescendants(sp[0], multiname);
2116 NEXTcontinue;
2117 }
2118
2119 INSTR(checkfilter)case OP_checkfilter: ; {
2120 SAVE_EXPCexpc = pc-1 -codeStart;
2121 env->checkfilter(sp[0]);
2122 NEXTcontinue;
2123 }
2124
2125 INSTR(findpropstrict)case OP_findpropstrict: ; {
2126 b1 = truetrue;
2127 goto findproperty_impl;
2128 }
2129
2130 INSTR(findproperty)case OP_findproperty: ; {
2131 b1 = falsefalse;
2132 findproperty_impl:
2133 SAVE_EXPCexpc = pc-1 -codeStart;
2134 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2135 if (multiname->isRuntime())
2136 {
2137 aux_memory->multiname2 = *multiname;
2138 sp = initMultiname(env, aux_memory->multiname2, sp);
2139 multiname = &aux_memory->multiname2;
2140 }
2141 *(++sp) = env->findproperty(scope, scopeBase, scopeDepth, multiname, b1, withBase);
2142 NEXTcontinue;
2143 }
2144
2145 INSTR(finddef)case OP_finddef: ; {
2146 SAVE_EXPCexpc = pc-1 -codeStart;
2147 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2148 *(++sp) = env->finddef(multiname)->atom();
2149 NEXTcontinue;
2150 }
2151
2152 INSTR(nextname)case OP_nextname: ; {
2153 SAVE_EXPCexpc = pc-1 -codeStart;
2154 a1 = sp[-1];
2155 a2 = sp[0];
2156 sp--;
2157 // verifier checks for int
2158 sp[0] = env->nextname(a1, AvmCore::integer_i(a2));
2159 NEXTcontinue;
2160 }
2161
2162 INSTR(nextvalue)case OP_nextvalue: ; {
2163 SAVE_EXPCexpc = pc-1 -codeStart;
2164 a1 = sp[-1];
2165 a2 = sp[0];
2166 sp--;
2167 // verifier checks for int
2168 sp[0] = env->nextvalue(a1, AvmCore::integer_i(a2));
2169 NEXTcontinue;
2170 }
2171
2172 INSTR(hasnext)case OP_hasnext: ; {
2173 SAVE_EXPCexpc = pc-1 -codeStart;
2174 a1 = sp[-1];
2175 a2 = sp[0];
2176 sp--;
2177 // verifier checks for int
2178 sp[0] = core->intToAtom(env->hasnext(a1, AvmCore::integer_i(a2)));
2179 NEXTcontinue;
2180 }
2181
2182 INSTR(hasnext2)case OP_hasnext2: ; {
2183 SAVE_EXPCexpc = pc-1 -codeStart;
2184 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // objReg
2185 u2 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // indexReg
2186 a1l = framep[u1]; // objAtom
2187 i32l = AvmCore::integer(framep[u2]); // index
2188 *(++sp) = env->hasnextproto(a1l, i32l) ? trueAtom : falseAtom;
2189 framep[u1] = a1l;
2190 framep[u2] = core->intToAtom(i32l);
2191 NEXTcontinue;
2192 }
2193
2194 // sign extends -- results always fit into an atom, no need to call intToAtom
2195 // since we are downshifting anyway, integrate final upshift-by-3 into downshift
2196 // rather than using MAKE_INTEGER macro.
2197 INSTR(sxi1)case OP_sxi1: ; {
2198 i1 = AvmCore::integer(sp[0]);
2199 sp[0] = CHECK_INT_ATOM(Atom(((i1 << (8*sizeof(Atom)-1)) >> ((8*sizeof(Atom)-1)-3)) | kIntptrType))(Atom(((i1 << (8*sizeof(Atom)-1)) >> ((8*sizeof(Atom
)-1)-3)) | kIntptrType))
;
2200 NEXTcontinue;
2201 }
2202
2203 INSTR(sxi8)case OP_sxi8: ; {
2204 i1 = AvmCore::integer(sp[0]);
2205 sp[0] = CHECK_INT_ATOM(Atom(((i1 << (8*(sizeof(Atom)-1))) >> ((8*(sizeof(Atom)-1))-3)) | kIntptrType))(Atom(((i1 << (8*(sizeof(Atom)-1))) >> ((8*(sizeof
(Atom)-1))-3)) | kIntptrType))
;
2206 NEXTcontinue;
2207 }
2208
2209 INSTR(sxi16)case OP_sxi16: ; {
2210 i1 = AvmCore::integer(sp[0]);
2211 sp[0] = CHECK_INT_ATOM(Atom(((i1 << (8*(sizeof(Atom)-2))) >> ((8*(sizeof(Atom)-2))-3)) | kIntptrType))(Atom(((i1 << (8*(sizeof(Atom)-2))) >> ((8*(sizeof
(Atom)-2))-3)) | kIntptrType))
;
2212 NEXTcontinue;
2213 }
2214
2215 // note that the mops "addr" (offset from globalMemoryBase) is in fact a signed int, so we have to check
2216 // for it being < 0 ... but we can get by with a single unsigned compare since all values < 0 will be > size
2217#define MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2218 if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof(type))) { avmplus::mop_rangeCheckFailed(env); }
2219
2220#if defined(VMCFG_UNALIGNED_INT_ACCESS) && defined(VMCFG_LITTLE_ENDIAN)
2221 #define MOPS_LOAD_INT(addr, type, call, result)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const type* p; }; p8 = envDomain->globalMemoryBase
() + (addr); result = *p;
\
2222 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2223 union { const uint8_t* p8; const type* p; }; \
2224 p8 = envDomain->globalMemoryBase() + (addr); \
2225 result = *p;
2226
2227 #define MOPS_STORE_INT(addr, type, call, value)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; type* p; }; p8 = envDomain->globalMemoryBase() + (addr
); *p = (type)(value);
\
2228 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2229 union { uint8_t* p8; type* p; }; \
2230 p8 = envDomain->globalMemoryBase() + (addr); \
2231 *p = (type)(value);
2232#else
2233 #define MOPS_LOAD_INT(addr, type, call, result)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const type* p; }; p8 = envDomain->globalMemoryBase
() + (addr); result = *p;
\
2234 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2235 result = (type)avmplus::mop_##call(envDomain->globalMemoryBase() + (addr));
2236
2237 #define MOPS_STORE_INT(addr, type, call, value)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; type* p; }; p8 = envDomain->globalMemoryBase() + (addr
); *p = (type)(value);
\
2238 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2239 avmplus::mop_##call(envDomain->globalMemoryBase() + (addr), value);
2240#endif
2241
2242#if defined(VMCFG_UNALIGNED_FP_ACCESS) && defined(VMCFG_LITTLE_ENDIAN)
2243 #define MOPS_LOAD_FP(addr, type, call, result)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const type* p; }; p8 = envDomain->globalMemoryBase
() + (addr); result = *p;
\
2244 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2245 union { const uint8_t* p8; const type* p; }; \
2246 p8 = envDomain->globalMemoryBase() + (addr); \
2247 result = *p;
2248
2249 #define MOPS_STORE_FP(addr, type, call, value)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; type* p; }; p8 = envDomain->globalMemoryBase() + (addr
); *p = (type)(value);
\
2250 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2251 union { uint8_t* p8; type* p; }; \
2252 p8 = envDomain->globalMemoryBase() + (addr); \
2253 *p = (type)(value);
2254#else
2255 #define MOPS_LOAD_FP(addr, type, call, result)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const type* p; }; p8 = envDomain->globalMemoryBase
() + (addr); result = *p;
\
2256 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2257 result = (type)avmplus::mop_##call(envDomain->globalMemoryBase() + (addr));
2258
2259 #define MOPS_STORE_FP(addr, type, call, value)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; type* p; }; p8 = envDomain->globalMemoryBase() + (addr
); *p = (type)(value);
\
2260 MOPS_RANGE_CHECK(addr, type)if (uint32_t(addr) > (envDomain->globalMemorySize() - sizeof
(type))) { avmplus::mop_rangeCheckFailed(env); }
\
2261 avmplus::mop_##call(envDomain->globalMemoryBase() + (addr), value);
2262#endif
2263
2264
2265
2266 // loads
2267#ifdef VMCFG_WORDCODE
2268 INSTR(lix8)case OP_lix8: ; {
2269 i1 = AvmCore::integer(sp[0]); // i1 = addr
2270 MOPS_LOAD_INT(i1, int8_t, lix8, i32l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(int8_t))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const int8_t* p; }; p8 = envDomain->globalMemoryBase
() + (i1); i32l = *p;
; // i32l = result
2271 sp[0] = MAKE_INTEGER(i32l)((intptr_t(i32l) << 3) | kIntptrType); // always fits in atom
2272 NEXTcontinue;
2273 }
2274
2275 INSTR(lix16)case OP_lix16: ; {
2276 i1 = AvmCore::integer(sp[0]); // i1 = addr
2277 MOPS_LOAD_INT(i1, int16_t, lix16, i32l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(int16_t))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const int16_t* p; }; p8 = envDomain->globalMemoryBase
() + (i1); i32l = *p;
; // i32l = result
2278 sp[0] = MAKE_INTEGER(i32l)((intptr_t(i32l) << 3) | kIntptrType); // always fits in atom
2279 NEXTcontinue;
2280 }
2281#endif
2282
2283 INSTR(li8)case OP_li8: ; {
2284 i1 = AvmCore::integer(sp[0]); // i1 = addr
2285 MOPS_LOAD_INT(i1, uint8_t, liz8, ub2)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(uint8_t))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const uint8_t* p; }; p8 = envDomain->globalMemoryBase
() + (i1); ub2 = *p;
; // ub2 = result
2286 sp[0] = MAKE_INTEGER(ub2)((intptr_t(ub2) << 3) | kIntptrType); // always fits in atom
2287 NEXTcontinue;
2288 }
2289
2290 INSTR(li16)case OP_li16: ; {
2291 i1 = AvmCore::integer(sp[0]); // i1 = addr
2292 MOPS_LOAD_INT(i1, uint16_t, liz16, uh2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(uint16_t))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const uint16_t* p; }; p8 = envDomain->globalMemoryBase
() + (i1); uh2l = *p;
; // uh2l = result
2293 sp[0] = MAKE_INTEGER(uh2l)((intptr_t(uh2l) << 3) | kIntptrType); // always fits in atom
2294 NEXTcontinue;
2295 }
2296
2297 INSTR(li32)case OP_li32: ; {
2298 i1 = AvmCore::integer(sp[0]); // i1 = addr
2299 MOPS_LOAD_INT(i1, int32_t, li32, i32l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(int32_t))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const int32_t* p; }; p8 = envDomain->globalMemoryBase
() + (i1); i32l = *p;
; // i32l = result
2300 sp[0] = core->intToAtom(i32l);
2301 NEXTcontinue;
2302 }
2303
2304 INSTR(lf32)case OP_lf32: ; {
2305 i1 = AvmCore::integer(sp[0]); // i1 = addr
2306 MOPS_LOAD_FP(i1, float, lf32, f2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(float))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const float* p; }; p8 = envDomain->globalMemoryBase
() + (i1); f2l = *p;
; // f2l = result
2307 sp[0] = core->doubleToAtom(f2l);
2308 NEXTcontinue;
2309 }
2310
2311 INSTR(lf64)case OP_lf64: ; {
2312 i1 = AvmCore::integer(sp[0]); // i1 = addr
2313 MOPS_LOAD_FP(i1, double, lf64, d2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(double))) { avmplus::mop_rangeCheckFailed(env); } union { const
uint8_t* p8; const double* p; }; p8 = envDomain->globalMemoryBase
() + (i1); d2l = *p;
; // d2l = addr
2314 sp[0] = core->doubleToAtom(d2l);
2315 NEXTcontinue;
2316 }
2317
2318 // stores
2319 INSTR(si8)case OP_si8: ; {
2320 i1 = AvmCore::integer(sp[0]); // i1 = addr
2321 ub2 = (uint8_t)AvmCore::integer(sp[-1]); // u2 = value
2322 MOPS_STORE_INT(i1, uint8_t, si8, ub2)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(uint8_t))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; uint8_t* p; }; p8 = envDomain->globalMemoryBase() + (
i1); *p = (uint8_t)(ub2);
;
2323 sp -= 2;
2324 NEXTcontinue;
2325 }
2326
2327 INSTR(si16)case OP_si16: ; {
2328 i1 = AvmCore::integer(sp[0]); // i1 = addr
2329 uh2l = (uint16_t)AvmCore::integer(sp[-1]); // uh2l = value
2330 MOPS_STORE_INT(i1, uint16_t, si16, uh2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(uint16_t))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; uint16_t* p; }; p8 = envDomain->globalMemoryBase() +
(i1); *p = (uint16_t)(uh2l);
;
2331 sp -= 2;
2332 NEXTcontinue;
2333 }
2334
2335 INSTR(si32)case OP_si32: ; {
2336 i1 = AvmCore::integer(sp[0]); // i1 = addr
2337 i32l = AvmCore::integer(sp[-1]); // i32l = value
2338 MOPS_STORE_INT(i1, uint32_t, si32, i32l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(uint32_t))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; uint32_t* p; }; p8 = envDomain->globalMemoryBase() +
(i1); *p = (uint32_t)(i32l);
;
2339 sp -= 2;
2340 NEXTcontinue;
2341 }
2342
2343 INSTR(sf32)case OP_sf32: ; {
2344 i1 = AvmCore::integer(sp[0]); // i1 = addr
2345 f2l = (float)AvmCore::number(sp[-1]); // d2l = value
2346 MOPS_STORE_FP(i1, float, sf32, f2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(float))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; float* p; }; p8 = envDomain->globalMemoryBase() + (i1
); *p = (float)(f2l);
;
2347 sp -= 2;
2348 NEXTcontinue;
2349 }
2350
2351 INSTR(sf64)case OP_sf64: ; {
2352 i1 = AvmCore::integer(sp[0]);
2353 d2l = AvmCore::number(sp[-1]);
2354 MOPS_STORE_FP(i1, double, sf64, d2l)if (uint32_t(i1) > (envDomain->globalMemorySize() - sizeof
(double))) { avmplus::mop_rangeCheckFailed(env); } union { uint8_t
* p8; double* p; }; p8 = envDomain->globalMemoryBase() + (
i1); *p = (double)(d2l);
;
2355 sp -= 2;
2356 NEXTcontinue;
2357 }
2358
2359 // delete property using multiname
2360 INSTR(deleteproperty)case OP_deleteproperty: ; {
2361 SAVE_EXPCexpc = pc-1 -codeStart;
2362 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2363 if (!multiname->isRuntime())
2364 {
2365 sp[0] = env->delproperty(sp[0], multiname);
2366 }
2367 else if (!multiname->isRtns() && IS_INTEGER(*sp)(((*sp) & 7) == kIntptrType) && atomCanBeUint32(*sp) && AvmCore::isObject(sp[-1]))
2368 {
2369 a2 = *(sp--); // key
2370 *sp = AvmCore::atomToScriptObject(*sp)->delUintProperty(UINT32_VALUE(a2)uint32_t(atomGetIntptr(a2))) ? trueAtom : falseAtom;
2371 }
2372 else if(multiname->isRtns() || !AvmCore::isDictionaryLookup(*sp, *(sp-1)))
2373 {
2374 aux_memory->multiname2 = *multiname;
2375 sp = initMultinameNoXMLList(env, aux_memory->multiname2, sp);
2376 sp[0] = env->delproperty(sp[0], &aux_memory->multiname2);
2377 }
2378 else
2379 {
2380 a2 = *(sp--); // key
2381 sp[0] = AvmCore::atomToScriptObject(sp[0])->deleteAtomProperty(a2) ? trueAtom : falseAtom;
2382 }
2383 NEXTcontinue;
2384 }
2385
2386 INSTR(setslot)case OP_setslot: ; {
2387 SAVE_EXPCexpc = pc-1 -codeStart;
2388 a1 = sp[-1];
2389 a2 = sp[0];
2390 sp -= 2;
2391 env->nullcheck(a1);
2392 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
-1; // slot_id
2393 AvmCore::atomToScriptObject(a1)->coerceAndSetSlotAtom((uint32_t)u1, a2);
2394 NEXTcontinue;
2395 }
2396
2397 INSTR(getslot)case OP_getslot: ; {
2398 SAVE_EXPCexpc = pc-1 -codeStart;
2399 env->nullcheck(sp[0]);
2400 // OPTIMIZEME - cleanup after ABC interpreter defenestration.
2401 // Perform the -1 adjustment in the bytecode translator, not here every time.
2402 sp[0] = AvmCore::atomToScriptObject(sp[0])->getSlotAtom((uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
-1);
2403 NEXTcontinue;
2404 }
2405
2406 INSTR(setglobalslot)case OP_setglobalslot: ; {
2407 SAVE_EXPCexpc = pc-1 -codeStart;
2408 // find the global activation scope (object at depth 0 on scope chain)
2409 AvmAssert(globalScope != NULL)do { } while (0);
2410
2411 // OPTIMIZEME - cleanup after ABC interpreter defenestration.
2412 // Perform the -1 adjustment in the bytecode translator, not here every time.
2413 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
-1; // slot_id
2414 a1 = sp[0]; // value
2415 sp--;
2416 globalScope->coerceAndSetSlotAtom((uint32_t)u1, a1);
2417 NEXTcontinue;
2418 }
2419
2420 INSTR(getglobalslot)case OP_getglobalslot: ; {
2421 SAVE_EXPCexpc = pc-1 -codeStart;
2422 // find the global activation scope (object at depth 0 on scope chain)
2423 AvmAssert(globalScope != NULL)do { } while (0);
2424
2425 // OPTIMIZMEME - cleanup after ABC interpreter defenestration.
2426 // Perform the -1 adjustment in the bytecode translator, not here every time.
2427 sp++;
2428 sp[0] = globalScope->getSlotAtom((uint32_t)(U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
-1));
2429 NEXTcontinue;
2430 }
2431
2432 // OPTIMIZEME - presumably there are many ways in which the call opcodes may be specialized
2433 // to avoid the full function prologue?
2434
2435 INSTR(call)case OP_call: ; {
2436 SAVE_EXPCexpc = pc-1 -codeStart;
2437 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2438 // stack in: function, receiver, arg1, ... argN
2439 // stack out: result
2440 a1 = toplevel->op_call(sp[-i1-1]/*function*/, (int32_t)i1, sp-i1);
2441 *(sp = sp-i1-1) = a1;
2442 NEXTcontinue;
2443 }
2444
2445 INSTR(construct)case OP_construct: ; {
2446 SAVE_EXPCexpc = pc-1 -codeStart;
2447 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2448 // stack in: function, arg1, ..., argN
2449 // stack out: new instance
2450 a1 = toplevel->op_construct(sp[-i1]/*function*/, (int32_t)i1, sp-i1);
2451 *(sp = sp-i1) = a1;
2452 NEXTcontinue;
2453 }
2454
2455 INSTR(newfunction)case OP_newfunction: ; {
2456 SAVE_EXPCexpc = pc-1 -codeStart;
2457 sp++;
2458 MethodInfo *body = pool->getMethodInfo((uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
);
2459 sp[0] = env->newfunction(body, scopeBase)->atom();
2460 NEXTcontinue;
2461 }
2462
2463 INSTR(newclass)case OP_newclass: ; {
2464 SAVE_EXPCexpc = pc-1 -codeStart;
2465 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
;
2466 Traits* ctraits = pool->getClassTraits((uint32_t)u1);
2467 o1 = (ScriptObject*)(~7 & toplevel->coerce(sp[0], CLASS_TYPE(core->traits.class_itraits)));
2468 sp[0] = env->newclass(ctraits, (ClassClosure*)o1, scope, scopeBase)->atom();
2469 NEXTcontinue;
2470 }
2471
2472 INSTR(callstatic)case OP_callstatic: ; {
2473 SAVE_EXPCexpc = pc-1 -codeStart;
2474 // stack in: receiver, arg1..N
2475 // stack out: result
2476 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // method_id
2477 i2 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2478 env->nullcheck(sp[-i2]);
2479 // ISSUE if arg types were checked in verifier, this coerces again.
2480 f = env->abcEnv()->getMethod((uint32_t)u1);
2481 a1 = f->coerceEnter((int32_t)i2, sp-i2);
2482 *(sp -= i2) = a1;
2483 NEXTcontinue;
2484 }
2485
2486 INSTR(callmethod)case OP_callmethod: ; {
2487 SAVE_EXPCexpc = pc-1 -codeStart;
2488 // stack in: receiver, arg1..N
2489 // stack out: result
2490 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
-1; // disp_id
2491 i2 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2492 a2p = sp-i2; // atomv
2493
2494 // must be a real class instance for this to be used. primitives that have
2495 // methods will only have final bindings and no dispatch table.
2496 VTable* vtable = toplevel->toVTable(a2p[0]); // includes null check
2497 AvmAssert(u1 < vtable->traits->getTraitsBindings()->methodCount)do { } while (0);
2498 f = vtable->methods[u1];
2499 // ISSUE if arg types were checked in verifier, this coerces again.
2500 a1 = f->coerceEnter((int32_t)i2, a2p);
2501 *(sp -= i2) = a1;
2502 NEXTcontinue;
2503 }
2504
2505 INSTR(callproperty)case OP_callproperty: ; {
2506 u1 = WORD_CODE_ONLY(WOP_callproperty) ABC_CODE_ONLY(OP_callproperty)OP_callproperty;
2507 callproperty_impl:
2508 SAVE_EXPCexpc = pc-1 -codeStart;
2509 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2510 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; /* argc */
2511 a2p = sp - i1; /* atomv */
2512 sp = a2p;
2513 if (multiname->isRuntime())
2514 {
2515 aux_memory->multiname2 = *multiname;
2516 sp = initMultiname(env, aux_memory->multiname2, sp);
2517 multiname = &aux_memory->multiname2;
2518 }
2519 a1 = *sp; /* base */
2520 if (u1 == WORD_CODE_ONLY(WOP_callproplex) ABC_CODE_ONLY(OP_callproplex)OP_callproplex)
2521 a2p[0] = nullObjectAtom;
2522 *sp = toplevel->callproperty(a1, multiname, (int32_t)i1, a2p, toplevel->toVTable(a1));
2523 if (u1 == WORD_CODE_ONLY(WOP_callpropvoid) ABC_CODE_ONLY(OP_callpropvoid)OP_callpropvoid)
2524 sp--;
2525 NEXTcontinue;
2526 }
2527
2528 INSTR(callproplex)case OP_callproplex: ; {
2529 u1 = WORD_CODE_ONLY(WOP_callproplex) ABC_CODE_ONLY(OP_callproplex)OP_callproplex;
2530 goto callproperty_impl;
2531 }
2532
2533 INSTR(callpropvoid)case OP_callpropvoid: ; {
2534 u1 = WORD_CODE_ONLY(WOP_callpropvoid) ABC_CODE_ONLY(OP_callpropvoid)OP_callpropvoid;
2535 goto callproperty_impl;
2536 }
2537
2538 INSTR(constructprop)case OP_constructprop: ; {
2539 SAVE_EXPCexpc = pc-1 -codeStart;
2540 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2541 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2542 sp -= i1;
2543 a2p = sp; // argv
2544 if (multiname->isRuntime())
2545 {
2546 aux_memory->multiname2 = *multiname;
2547 sp = initMultiname(env, aux_memory->multiname2, sp);
2548 multiname = &aux_memory->multiname2;
2549 a2p[0] = *sp;
2550 }
2551 *sp = toplevel->constructprop(multiname, (int32_t)i1, a2p, toplevel->toVTable(a2p[0]));
2552 NEXTcontinue;
2553 }
2554
2555 INSTR(applytype)case OP_applytype: ; {
2556 SAVE_EXPCexpc = pc-1 -codeStart;
2557 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2558 // stack in: factory, arg1, ... argN
2559 // stack out: result
2560 a1 = op_applytype(env, sp[-i1]/*function*/, (int32_t)i1, sp-i1+1);
2561 *(sp = sp-i1) = a1;
2562 NEXTcontinue;
2563 }
2564
2565 INSTR(callsuper)case OP_callsuper: ; {
2566 u1 = WORD_CODE_ONLY(WOP_callsuper) ABC_CODE_ONLY(OP_callsuper)OP_callsuper;
2567 callsuper_impl:
2568 SAVE_EXPCexpc = pc-1 -codeStart;
2569 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2570 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; /* argc */
2571 sp -= i1;
2572 a2p = sp; /* atomv */
2573 if (multiname->isRuntime())
2574 {
2575 aux_memory->multiname2 = *multiname;
2576 sp = initMultiname(env, aux_memory->multiname2, sp);
2577 multiname = &aux_memory->multiname2;
2578 a2p[0] = *sp;
2579 }
2580 env->nullcheck(a2p[0]);
2581 *sp = env->callsuper(multiname, (int32_t)i1, a2p);
2582 if (u1 == WORD_CODE_ONLY(WOP_callsupervoid) ABC_CODE_ONLY(OP_callsupervoid)OP_callsupervoid)
2583 sp--;
2584 NEXTcontinue;
2585 }
2586
2587 INSTR(callsupervoid)case OP_callsupervoid: ; {
2588 u1 = WORD_CODE_ONLY(WOP_callsupervoid) ABC_CODE_ONLY(OP_callsupervoid)OP_callsupervoid;
2589 goto callsuper_impl;
2590 }
2591
2592 // An possible optimization is to split instructions that have a runtime multiname
2593 // into two: one that initializes aux_memory->multiname2, and another that simply picks
2594 // up that value. That way there will be less code in the interpreter, and the
2595 // common case will be faster.
2596
2597 INSTR(getsuper)case OP_getsuper: ; {
2598 a1 = 0; // not a value - instruction is getsuper
2599 getsuper_setsuper_impl:
2600 SAVE_EXPCexpc = pc-1 -codeStart;
2601 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2602 if (multiname->isRuntime())
2603 {
2604 aux_memory->multiname2 = *multiname;
2605 sp = initMultiname(env, aux_memory->multiname2, sp);
2606 multiname = &aux_memory->multiname2;
2607 }
2608 a2 = *(sp--); // object
2609 env->nullcheck(a2);
2610 if (a1 == 0)
2611 *(++sp) = env->getsuper(a2, multiname);
2612 else
2613 env->setsuper(a2, multiname, a1);
2614 NEXTcontinue;
2615 }
2616
2617 INSTR(setsuper)case OP_setsuper: ; {
2618 a1 = *(sp--); // value
2619 goto getsuper_setsuper_impl;
2620 }
2621
2622 // obj arg1 arg2
2623 // sp
2624 INSTR(constructsuper)case OP_constructsuper: ; {
2625 SAVE_EXPCexpc = pc-1 -codeStart;
2626 // stack in: obj arg1..N
2627 // stack out:
2628 i1 = (intptr_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // argc
2629 env->nullcheck(sp[-i1]);
2630 env->super_init()->coerceEnter((int32_t)i1, sp-i1);
2631 sp -= i1+1;
2632 NEXTcontinue;
2633 }
2634
2635#ifndef VMCFG_WORDCODE
2636 INSTR(pushshort)case OP_pushshort: ; {
2637 // this just pushes an integer since we dont have short atoms
2638 *(++sp) = MAKE_INTEGER(((int16_t)U30ARG))((intptr_t(((int16_t)(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc
)), pc = tmp_pc, tmp_u30))) << 3) | kIntptrType)
;
2639 NEXTcontinue;
2640 }
2641#endif
2642
2643 INSTR(astype)case OP_astype: ; {
2644 SAVE_EXPCexpc = pc-1 -codeStart;
2645 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2646 sp[0] = AvmCore::astype(sp[0], getTraits(multiname, pool, toplevel, core));
2647 NEXTcontinue;
2648 }
2649
2650 INSTR(astypelate)case OP_astypelate: ; {
2651 SAVE_EXPCexpc = pc-1 -codeStart;
2652 a1 = sp[-1];
2653 a2 = sp[0];
2654 sp--;
2655 sp[0] = AvmCore::astype(a1, toplevel->toClassITraits(a2));
2656 NEXTcontinue;
2657 }
2658
2659 INSTR(coerce)case OP_coerce: ; {
2660 SAVE_EXPCexpc = pc-1 -codeStart;
2661 // expects a CONSTANT_Multiname cpool index
2662 // this is the ES4 implicit coersion
2663 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2664 sp[0] = toplevel->coerce(sp[0], getTraits(multiname, pool, toplevel, core));
2665 NEXTcontinue;
2666 }
2667
2668 INSTR(coerce_o)case OP_coerce_o: ; {
2669 if (sp[0] == undefinedAtom)
2670 sp[0] = nullObjectAtom;
2671 NEXTcontinue;
2672 }
2673
2674 INSTR(coerce_s)case OP_coerce_s: ; {
2675 a1 = sp[0];
2676 if (!IS_STRING(a1)(((a1) & 7) == kStringType)) {
2677 SAVE_EXPCexpc = pc-1 -codeStart;
2678 sp[0] = AvmCore::isNullOrUndefined(a1) ? nullStringAtom : core->string(a1)->atom();
2679 }
2680 NEXTcontinue;
2681 }
2682
2683 // OPTIMIZEME - early binding for a2 of 'is'?
2684 // (or outright removal in the translator?)
2685
2686 INSTR(istype)case OP_istype: ; {
2687 SAVE_EXPCexpc = pc-1 -codeStart;
2688 // expects a CONSTANT_Multiname cpool index
2689 // used when operator "is" RHS is a compile-time type constant
2690 GET_MULTINAME_PTR(multiname, U30ARG)multiname = pool->precomputedMultiname(uint32_t((tmp_pc=pc
, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc, tmp_u30))
)
;
2691 t1 = getTraits(multiname, pool, toplevel, core); // itraits
2692 sp[0] = AvmCore::istypeAtom(sp[0], t1);
2693 NEXTcontinue;
2694 }
2695
2696 INSTR(istypelate)case OP_istypelate: ; {
2697 SAVE_EXPCexpc = pc-1 -codeStart;
2698 a1 = sp[-1];
2699 a2 = sp[0];
2700 sp--;
2701 sp[0] = AvmCore::istypeAtom(a1, toplevel->toClassITraits(a2));
2702 NEXTcontinue;
2703 }
2704
2705#ifndef VMCFG_WORDCODE
2706 INSTR(pushbyte)case OP_pushbyte: ; {
2707 *(++sp) = MAKE_INTEGER((int8_t)U8ARG)((intptr_t((int8_t)(*pc++)) << 3) | kIntptrType);
2708 NEXTcontinue;
2709 }
2710#endif
2711
2712 INSTR(getscopeobject)case OP_getscopeobject: ; {
2713 u1 = U8ARG(*pc++); // scope_index
2714 *(++sp) = scopeBase[(uint32_t)u1];
2715 NEXTcontinue;
2716 }
2717
2718 INSTR(getouterscope)case OP_getouterscope: ; {
2719 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // scope_index
2720 *(++sp) = scope->getScope((uint32_t)u1);
2721 NEXTcontinue;
2722 }
2723
2724 INSTR(getglobalscope)case OP_getglobalscope: ; {
2725 AvmAssert(globalScope != NULL)do { } while (0);
2726 *(++sp) = globalScope->atom();
2727 NEXTcontinue;
2728 }
2729
2730 INSTR(pushscope)case OP_pushscope: ; {
2731 a1 = sp[0]; // scope
2732 sp--;
2733 if (AvmCore::isNullOrUndefined(a1)) {
2734 SAVE_EXPCexpc = pc-1 -codeStart;
2735 env->nullcheck(a1);
2736 }
2737 if (scopeDepth == 0 && globalScope == NULL__null)
2738 {
2739 AvmAssert(scope->getSize() == 0)do { } while (0);
2740 globalScope = AvmCore::atomToScriptObject(a1);
2741 }
2742 scopeBase[scopeDepth++] = a1;
2743 NEXTcontinue;
2744 }
2745
2746 INSTR(pushwith)case OP_pushwith: ; {
2747 a1 = sp[0]; // scope object
2748 sp--;
2749 if (AvmCore::isNullOrUndefined(a1)) {
2750 SAVE_EXPCexpc = pc-1 -codeStart;
2751 env->nullcheck(a1);
2752 }
2753 if (!withBase)
2754 withBase = scopeBase+scopeDepth;
2755 // is it possible to have pushWith for scope 0? not sure, let's do this just in case
2756 if (scopeDepth == 0 && globalScope == NULL__null)
2757 {
2758 AvmAssert(scope->getSize() == 0)do { } while (0);
2759 globalScope = AvmCore::atomToScriptObject(a1);
2760 }
2761 scopeBase[scopeDepth++] = a1;
2762 NEXTcontinue;
2763 }
2764
2765 INSTR(newactivation)case OP_newactivation: ; {
2766 SAVE_EXPCexpc = pc-1 -codeStart;
2767 *(++sp) = env->newActivation()->atom();
2768 NEXTcontinue;
2769 }
2770
2771 INSTR(newcatch)case OP_newcatch: ; {
2772 SAVE_EXPCexpc = pc-1 -codeStart;
2773 u1 = U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
; // catch_index
2774#ifdef VMCFG_WORDCODE
2775 t1 = info->word_code_exceptions()->exceptions[u1].scopeTraits;
2776#else
2777 t1 = info->abc_exceptions()->exceptions[u1].scopeTraits;
2778#endif
2779 *(++sp) = env->newcatch(t1)->atom();
2780 NEXTcontinue;
2781 }
2782
2783 INSTR(popscope)case OP_popscope: ; {
2784 if (!--scopeDepth)
2785 {
2786 if (scope->getSize() == 0)
2787 globalScope = NULL__null;
2788 }
2789 #ifdef DEBUGGER
2790 // in debugger builds, ensure that non-active scope entries are nulled out
2791 scopeBase[scopeDepth] = nullObjectAtom;
2792 #endif
2793 if (withBase >= scopeBase + scopeDepth)
2794 withBase = NULL__null;
2795 NEXTcontinue;
2796 }
2797
2798 INSTR(convert_i)case OP_convert_i: ; {
2799 ABC_CODE_ONLY( convert_i_impl: )convert_i_impl:
2800 a1 = sp[0];
2801 if (!IS_INTEGER(a1)(((a1) & 7) == kIntptrType)) {
2802 SAVE_EXPCexpc = pc-1 -codeStart;
2803 sp[0] = core->intAtom(a1);
2804 }
2805 else {
2806 sp[0] = CLAMP_32(a1)(intptr_t(a1));
2807 }
2808 NEXTcontinue;
2809 }
2810
2811#ifndef VMCFG_WORDCODE
2812 INSTR(coerce_i)case OP_coerce_i: ; {
2813 goto convert_i_impl;
2814 }
2815#endif
2816
2817 INSTR(convert_u)case OP_convert_u: ; {
2818 ABC_CODE_ONLY( convert_u_impl: )convert_u_impl:
2819 a1 = sp[0];
2820 if (!IS_INTEGER(a1)(((a1) & 7) == kIntptrType) || a1 < 0) {
2821 SAVE_EXPCexpc = pc-1 -codeStart;
2822 sp[0] = core->uintAtom(a1);
2823 }
2824 NEXTcontinue;
2825 }
2826
2827#ifndef VMCFG_WORDCODE
2828 INSTR(coerce_u)case OP_coerce_u: ; {
2829 goto convert_u_impl;
2830 }
2831#endif
2832
2833 INSTR(throw)case OP_throw: ; {
2834 SAVE_EXPCexpc = pc-1 -codeStart;
2835 core->throwAtom(*sp--);
2836 // unreachable
2837 NEXTcontinue;
2838 }
2839
2840 INSTR(instanceof)case OP_instanceof: ; {
2841 SAVE_EXPCexpc = pc-1 -codeStart;
2842 a1 = sp[-1];
2843 a2 = sp[0];
2844 sp--;
2845 sp[0] = toplevel->instanceof(a1, a2);
2846 NEXTcontinue;
2847 }
2848
2849 INSTR(in)case OP_in: ; {
2850 SAVE_EXPCexpc = pc-1 -codeStart;
2851 a1 = sp[-1];
2852 a2 = sp[0];
2853 sp--;
2854 sp[0] = toplevel->in_operator(a1, a2);
2855 NEXTcontinue;
2856 }
2857
2858 INSTR(dxns)case OP_dxns: ; {
2859 AvmAssert(info->setsDxns())do { } while (0);
2860 SAVE_EXPCexpc = pc-1 -codeStart;
2861 core->setDxns(&aux_memory->methodFrame, pool->getString((uint32_t)U30ARG(tmp_pc=pc, tmp_u30 = uint32_t(readU30(tmp_pc)), pc = tmp_pc,
tmp_u30)
));
2862 NEXTcontinue;
2863 }
2864
2865 INSTR(dxnslate)case OP_dxnslate: ; {
2866 AvmAssert(info->setsDxns())do { } while (0);
2867 SAVE_EXPCexpc = pc-1 -codeStart;
2868 core->setDxnsLate(&aux_memory->methodFrame, *sp);
2869 sp--;
2870 NEXTcontinue;
2871 }
2872
2873#if defined(VMCFG_WORDCODE) && !defined(VMCFG_DIRECT_THREADED)
2874 // Fleshes out the dispatch table so that it's 0..255, allows
2875 // some compilers to generate better code for the switch at the
2876 // top, which switches on the low 8 bits. (0 is an illegal
2877 // opcode; 255 is OP_ext, for which there's a case below.)
2878 case 0: {
2879 AvmAssert(false)do { } while (0);
2880 }
2881#endif
2882
2883#ifdef VMCFG_WORDCODE
2884# ifdef MSVC_X86_REWRITE_THREADING
2885 default:
2886 // Keep L_illegal_op and L_push_doublebits alive...
2887 if ((int)pc > 0x100000)
2888 goto L_push_doublebits;
2889 break;
2890# endif
2891
2892 INSTR(pushbits)case OP_pushbits: ; {
2893 *++sp = *pc++;
2894 NEXTcontinue;
2895 }
2896
2897 // OPTIMIZEME - push_doublebits should probably not cons up a new atom every time,
2898 // it would be better to keep it in the constant pool.
2899 //
2900 // OPTIMIZEME - on 64-bit systems we don't need two operand words here
2901 //
2902 // OPTIMIZEME - we can do better if unaligned int64 loads or unaligned fp loads
2903 // are allowed on the platform.
2904
2905 INSTR(push_doublebits)case OP_push_doublebits: ; {
2906 // Native layout in the instruction stream, just copy it over
2907 double_overlay d;
2908 d.bits32[0] = (uint32_t)*pc++;
2909 d.bits32[1] = (uint32_t)*pc++;
2910 *++sp = core->doubleToAtom(d.value);
2911 NEXTcontinue;
2912 }
2913
2914# ifdef VMCFG_WORDCODE_PEEPHOLE
2915
2916# define FETCH_LL(a1, a2) \
2917 u1 = *pc++; \
2918 a1 = framep[u1 & 65535];\
2919 a2 = framep[u1 >> 16]
2920
2921# define LOAD_OFFSET_AND_FETCH_LL(a1, a2, i1) \
2922 SAVE_EXPCexpc = pc-1 -codeStart; \
2923 i1 = (intptr_t)*pc++; \
2924 FETCH_LL(a1, a2)
2925
2926# define FETCH_LB(a1, a2) \
2927 a1 = framep[*pc++]; \
2928 a2 = *pc++
2929
2930# define LOAD_OFFSET_AND_FETCH_LB(a1, a2, i1) \
2931 SAVE_EXPCexpc = pc-1 -codeStart; \
2932 i1 = (intptr_t)*pc++; \
2933 FETCH_LB(a1, a2)
2934
2935 // Superwords not in the instruction set. These are selected by a table
2936 // driven peephole optimizer, see comments and code in core/WordcodeTranslator.cpp.
2937
2938 INSTR(get2locals)case OP_get2locals: ; {
2939 u1 = *pc++;
2940 *(++sp) = framep[u1 & 65535];
2941 *(++sp) = framep[u1 >> 16];
2942 NEXTcontinue;
2943 }
2944
2945 INSTR(get3locals)case OP_get3locals: ; {
2946 u1 = *pc++;
2947 *(++sp) = framep[u1 & 1023];
2948 u1 >>= 10;
2949 *(++sp) = framep[u1 & 1023];
2950 *(++sp) = framep[u1 >> 10];
2951 NEXTcontinue;
2952 }
2953
2954 INSTR(get4locals)case OP_get4locals: ; {
2955 u1 = *pc++;
2956 *(++sp) = framep[u1 & 255];
2957 u1 >>= 8;
2958 *(++sp) = framep[u1 & 255];
2959 u1 >>= 8;
2960 *(++sp) = framep[u1 & 255];
2961 *(++sp) = framep[u1 >> 8];
2962 NEXTcontinue;
2963 }
2964
2965 INSTR(get5locals)case OP_get5locals: ; {
2966 u1 = *pc++;
2967 *(++sp) = framep[u1 & 63];
2968 u1 >>= 6;
2969 *(++sp) = framep[u1 & 63];
2970 u1 >>= 6;
2971 *(++sp) = framep[u1 & 63];
2972 u1 >>= 6;
2973 *(++sp) = framep[u1 & 63];
2974 *(++sp) = framep[u1 >> 6];
2975 NEXTcontinue;
2976 }
2977
2978 INSTR(storelocal)case OP_storelocal: ; {
2979 framep[*pc++] = *sp;
2980 NEXTcontinue;
2981 }
2982
2983 INSTR(add_ll)case OP_add_ll: ; {
2984 FETCH_LL(a1,a2);
2985 ++sp;
2986 goto add_two_values_into_tos_impl;
2987 }
2988
2989 INSTR(add_set_lll)case OP_add_set_lll: ; {
2990 u1 = *pc++;
2991 a1=framep[u1 & 1023];
2992 u1 >>= 10;
2993 a2=framep[u1 & 1023];
2994 ADD_TWO_VALUES_AND_NEXT(a1, a2, framep[u1 >> 10])if (((((a1 ^ kIntptrType) | (a2 ^ kIntptrType)) & 7) == 0
)) { u1t = a1 ^ kIntptrType; u2t = a2 ^ kIntptrType; u3t = (intptr_t
(u1t + u2t)); if ((intptr_t)(u1t ^ u2t) < 0 || (intptr_t)(
u1t ^ u3t) >= 0) { framep[u1 >> 10] = (u3t | kIntptrType
); continue; } } else if (((((a1 ^ kDoubleType) | (a2 ^ kDoubleType
)) & 7) == 0)) { framep[u1 >> 10] = core->doubleToAtom
((*(double*)((a1) ^ kDoubleType)) + (*(double*)((a2) ^ kDoubleType
))); continue; } expc = pc-1 -codeStart; framep[u1 >> 10
] = toplevel->add2(a1, a2); continue
;
2995 }
2996
2997 INSTR(subtract_ll)case OP_subtract_ll: ; {
2998 FETCH_LL(a1,a2);
2999 ++sp;
3000 goto sub_two_values_and_next;
3001 }
3002
3003 INSTR(multiply_ll)case OP_multiply_ll: ; {
3004 FETCH_LL(a1,a2);
3005 ++sp;
3006 goto mul_two_values_and_next;
3007 }
3008
3009 INSTR(divide_ll)case OP_divide_ll: ; {
3010 FETCH_LL(a1,a2);
3011 ++sp;
3012 goto div_two_values_and_next;
3013 }
3014
3015 INSTR(modulo_ll)case OP_modulo_ll: ; {
3016 FETCH_LL(a1,a2);
3017 ++sp;
3018 goto mod_two_values_and_next;
3019 }
3020
3021 INSTR(bitand_ll)case OP_bitand_ll: ; {
3022 FETCH_LL(a1,a2);
3023 ++sp;
3024 goto bitand_two_values_and_next;
3025 }
3026
3027 INSTR(bitor_ll)case OP_bitor_ll: ; {
3028 FETCH_LL(a1,a2);
3029 ++sp;
3030 goto bitor_two_values_and_next;
3031 }
3032
3033 INSTR(bitxor_ll)case OP_bitxor_ll: ; {
3034 FETCH_LL(a1,a2);
3035 ++sp;
3036 goto bitxor_two_values_and_next;
3037 }
3038
3039 // OPTIMIZEME - redundant type check in superword.
3040 // As long as ext_pushbits is only used for integer data we know that
3041 // a2 is an int in the cases below, so the macros need not check.
3042
3043 INSTR(add_lb)case OP_add_lb: ; {
3044 FETCH_LB(a1, a2);
3045 ++sp;
3046 goto add_two_values_into_tos_impl;
3047 }
3048
3049 INSTR(subtract_lb)case OP_subtract_lb: ; {
3050 FETCH_LB(a1, a2);
3051 ++sp;
3052 goto sub_two_values_and_next;
3053 }
3054
3055 INSTR(multiply_lb)case OP_multiply_lb: ; {
3056 FETCH_LB(a1, a2);
3057 ++sp;
3058 goto mul_two_values_and_next;
3059 }
3060
3061 INSTR(divide_lb)case OP_divide_lb: ; {
3062 FETCH_LB(a1, a2);
3063 ++sp;
3064 goto div_two_values_and_next;
3065 }
3066
3067 INSTR(bitand_lb)case OP_bitand_lb: ; {
3068 FETCH_LB(a1, a2);
3069 ++sp;
3070 goto bitand_two_values_and_next;
3071 }
3072
3073 INSTR(bitor_lb)case OP_bitor_lb: ; {
3074 FETCH_LB(a1, a2);
3075 ++sp;
3076 goto bitor_two_values_and_next;
3077 }
3078
3079 INSTR(bitxor_lb)case OP_bitxor_lb: ; {
3080 FETCH_LB(a1, a2);
3081 ++sp;
3082 goto bitxor_two_values_and_next;
3083 }
3084
3085 INSTR(iflt_ll)case OP_iflt_ll: ; {
3086 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3087 goto compare_lt_and_branch_impl;
3088 }
3089
3090 INSTR(ifnlt_ll)case OP_ifnlt_ll: ; {
3091 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3092 goto compare_nlt_and_branch_impl;
3093 }
3094
3095 INSTR(ifle_ll)case OP_ifle_ll: ; {
3096 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3097 goto compare_le_and_branch_impl;
3098 }
3099
3100 INSTR(ifnle_ll)case OP_ifnle_ll: ; {
3101 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3102 goto compare_nle_and_branch_impl;
3103 }
3104
3105 INSTR(ifgt_ll)case OP_ifgt_ll: ; {
3106 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3107 goto compare_gt_and_branch_impl;
3108 }
3109
3110 INSTR(ifngt_ll)case OP_ifngt_ll: ; {
3111 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3112 goto compare_ngt_and_branch_impl;
3113 }
3114
3115 INSTR(ifge_ll)case OP_ifge_ll: ; {
3116 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3117 goto compare_ge_and_branch_impl;
3118 }
3119
3120 INSTR(ifnge_ll)case OP_ifnge_ll: ; {
3121 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3122 goto compare_nge_and_branch_impl;
3123 }
3124
3125 INSTR(ifeq_ll)case OP_ifeq_ll: ; {
3126 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3127 goto compare_eq_and_branch_impl;
3128 }
3129
3130 INSTR(ifne_ll)case OP_ifne_ll: ; {
3131 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3132 goto compare_ne_and_branch_impl;
3133 }
3134
3135 INSTR(ifstricteq_ll)case OP_ifstricteq_ll: ; {
3136 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3137 goto compare_stricteq_and_branch_impl;
3138 }
3139
3140 INSTR(ifstrictne_ll)case OP_ifstrictne_ll: ; {
3141 LOAD_OFFSET_AND_FETCH_LL(a1,a2,i1);
3142 goto compare_strictne_and_branch_impl;
3143 }
3144
3145 INSTR(iflt_lb)case OP_iflt_lb: ; {
3146 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3147 goto compare_lt_and_branch_impl;
3148 }
3149
3150 INSTR(ifnlt_lb)case OP_ifnlt_lb: ; {
3151 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3152 goto compare_nlt_and_branch_impl;
3153 }
3154
3155 INSTR(ifle_lb)case OP_ifle_lb: ; {
3156 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3157 goto compare_le_and_branch_impl;
3158 }
3159
3160 INSTR(ifnle_lb)case OP_ifnle_lb: ; {
3161 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3162 goto compare_nle_and_branch_impl;
3163 }
3164
3165 INSTR(ifgt_lb)case OP_ifgt_lb: ; {
3166 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3167 goto compare_gt_and_branch_impl;
3168 }
3169
3170 INSTR(ifngt_lb)case OP_ifngt_lb: ; {
3171 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3172 goto compare_ngt_and_branch_impl;
3173 }
3174
3175 INSTR(ifge_lb)case OP_ifge_lb: ; {
3176 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3177 goto compare_ge_and_branch_impl;
3178 }
3179
3180 INSTR(ifnge_lb)case OP_ifnge_lb: ; {
3181 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3182 goto compare_nge_and_branch_impl;
3183 }
3184
3185 INSTR(ifeq_lb)case OP_ifeq_lb: ; {
3186 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3187 goto compare_eq_and_branch_impl;
3188 }
3189
3190 INSTR(ifne_lb)case OP_ifne_lb: ; {
3191 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3192 goto compare_ne_and_branch_impl;
3193 }
3194
3195 INSTR(ifstricteq_lb)case OP_ifstricteq_lb: ; {
3196 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3197 goto compare_stricteq_and_branch_impl;
3198 }
3199
3200 INSTR(ifstrictne_lb)case OP_ifstrictne_lb: ; {
3201 LOAD_OFFSET_AND_FETCH_LB(a1,a2,i1);
3202 goto compare_strictne_and_branch_impl;
3203 }
3204
3205 INSTR(swap_pop)case OP_swap_pop: ; {
3206 sp[-1] = sp[0];
3207 --sp;
3208 NEXTcontinue;
3209 }
3210
3211# endif // VMCFG_WORDCODE_PEEPHOLE
3212
3213 INSTR(findpropglobal)case OP_findpropglobal: ; {
3214 b1 = falsefalse; // whether to throw or not
3215 goto findpropglobal_impl;
3216 }
3217
3218 INSTR(findpropglobalstrict)case OP_findpropglobalstrict: ; {
3219 b1 = truetrue;
3220 findpropglobal_impl:
3221 u1 = *pc++; // multiname_index
3222 u2 = *pc++; // cache_slot
3223 if (core->lookupCacheIsValid(env->lookup_cache->get(uint32_t(u2)).timestamp)) {
3224 *(++sp) = env->lookup_cache->get(uint32_t(u2)).object->atom();
3225 NEXTcontinue;
3226 }
3227 SAVE_EXPCexpc = pc-1 -codeStart;
3228 GET_MULTINAME_PTR(multiname, u1)multiname = pool->precomputedMultiname(uint32_t(u1));
3229 AvmAssert(multiname->isBinding())do { } while (0);
3230 AvmAssert(globalScope != NULL)do { } while (0);
3231 a1 = env->findglobalproperty(globalScope->atom(), multiname); // container
3232 if (AvmCore::isNullOrUndefined(a1))
3233 {
3234 if (b1)
3235 toplevel->throwReferenceError(kUndefinedVarError, multiname);
3236 else
3237 *(++sp) = globalScope->atom();
3238 }
3239 else
3240 {
3241 *(++sp) = a1;
3242 env->lookup_cache->get(uint32_t(u2)).timestamp = core->lookupCacheTimestamp();
3243 WBRC(core->GetGC(), env->lookup_cache, &env->lookup_cache->get(uint32_t(u2)).object, AvmCore::atomToScriptObject(sp[0]))core->GetGC()->privateWriteBarrierRC(env->lookup_cache
, &env->lookup_cache->get(uint32_t(u2)).object, (const
void *) (AvmCore::atomToScriptObject(sp[0])))
;
3244 }
3245 NEXTcontinue;
3246 }
3247
3248#endif
3249#if defined SWITCH_DISPATCH
3250 } // switch
3251 // illegal instruction or accidental break
3252 goto L_illegal_op;
3253 } // for
3254#else
3255 goto L_illegal_op;
3256#endif
3257
3258 } // TRY
3259
3260 CATCH (Exception *exception)else { _ef.beginCatch(); Exception *exception = _ee;
3261 {
3262 // find handler; rethrow if no handler.
3263#if defined VMCFG_WORDCODE && !defined DEBUGGER
3264 ExceptionHandler *handler = core->findExceptionHandler(info, (uintptr_t*)expc-1-info->word_code_start(), exception);
3265#else
3266 ExceptionHandler *handler = core->findExceptionHandler(info, expc, exception);
3267#endif
3268 // handler found in current method
3269#ifdef DEBUGGER
3270 // This is a little hokey, see https://bugzilla.mozilla.org/show_bug.cgi?id=470954.
3271 //
3272 // The debugenter instruction sets up core->callStack, we do this lazily to save
3273 // time in builds where the debugger is enabled at compile time but not present
3274 // at run time.
3275 //
3276 // The problem is that CATCH restores core->callStack to its old value, saved by TRY.
3277 // So we force it to the new value here if there is a new value. Then TRY will save the
3278 // value again (the new value this time) which we restore redundantly the next time
3279 // there is an exception, if any. The debugexit instruction will take care of restoring
3280 // the actual old value.
3281 if (callStackNode != NULL__null)
3282 core->callStack = callStackNode;
3283#endif
3284#ifdef VMCFG_WORDCODE
3285 pc = info->word_code_start() + handler->target;
3286#else
3287 pc = codeStart + handler->target;
3288#endif
3289 scopeDepth = 0;
3290#ifdef DEBUGGER
3291 // in debugger builds, ensure that non-active scope entries are nulled out
3292 for (int i = 0, n = ms->max_scope(); i < n; ++i)
3293 scopeBase[i] = nullObjectAtom;
3294#endif
3295 globalScope = (scope->getSize() > 0) ? AvmCore::atomToScriptObject(scope->getScope(0)) : NULL__null;
3296 sp = scopeBase + ms->max_scope() - 1;
3297 *(++sp) = exception->atom;
3298 goto MainLoop;
3299 }
3300 END_CATCH}
3301 END_TRY}
3302
3303 // Target of various error cases
3304
3305 L_illegal_op:
3306 AvmAssert(!"Illegal operation!")do { } while (0);
3307 goto L_illegal_op;
3308 }
3309
3310 // Note, this function is not on the hot path normally, so optimizing it is not urgent.
3311 //
3312 // OPTIMIZEME - statically knowable if name isRtname or isRtns; exploit this somehow?
3313 // OPTIMIZEME - often knowable whether the TOS is an object or something simple; exploit this?
3314
3315 Atom* initMultiname(MethodEnv* env, Multiname &name, Atom* sp)
3316 {
3317 if (name.isRtname())
3318 {
3319 Atom index = *(sp--);
3320 AvmCore* core = env->core();
3321
3322 // is it a qname?
3323 if (AvmCore::isObject(index))
3324 {
3325 ScriptObject* i = AvmCore::atomToScriptObject(index);
3326 if (i->traits() == core->traits.qName_itraits)
3327 {
3328 QNameObject* qname = (QNameObject*) i;
3329 boolbool attr = name.isAttr();
3330 qname->getMultiname(name);
3331 if (attr)
3332 name.setAttr(attr);
3333
3334 // Discard runtime namespace if present
3335 if (name.isRtns())
3336 sp--;
3337
3338 return sp;
3339 }
3340 }
3341
3342 name.setName(core->intern(index));
3343 }
3344
3345 if (name.isRtns())
3346 name.setNamespace(env->internRtns(*(sp--)));
3347
3348 return sp;
3349 }
3350
3351 Atom* initMultinameNoXMLList(MethodEnv* env, Multiname &name, Atom* sp)
3352 {
3353 if (name.isRtname() && AvmCore::isXMLList(sp[0])) {
3354 // Error according to E4X spec, section 11.3.1
3355 env->toplevel()->throwTypeError(kDeleteTypeError, env->core()->toErrorString(env->toplevel()->toTraits(sp[0])));
3356 }
3357 return initMultiname(env, name, sp);
3358 }
3359
3360 Traits* getTraits(const Multiname* name, PoolObject* pool, Toplevel* toplevel, AvmCore* core)
3361 {
3362 // See Verifier::checkTypeName for the canonical code
3363
3364 Traits* t = core->domainMgr()->findTraitsInPoolByMultiname(pool, *name);
3365 // Verifier::checkTypeName has ensured this is a valid, non-ambiguous binding
3366 AvmAssert(t != NULL && t != (Traits*)BIND_AMBIGUOUS)do { } while (0);
3367 if (name->isParameterizedType())
3368 {
3369 const Multiname* param_name;
3370 GET_MULTINAME_PTR(param_name, name->getTypeParameter())param_name = pool->precomputedMultiname(uint32_t(name->
getTypeParameter()))
;
3371 core->stackCheck(toplevel);
3372 Traits* param_traits = name->getTypeParameter() ? getTraits(param_name, pool, toplevel, core) : NULL__null;
3373 t = pool->resolveParameterizedType(toplevel, t, param_traits);
3374 }
3375 return t;
3376 }
3377
3378#ifdef AVMPLUS_VERBOSE
3379 /**
3380 * display contents of current stack frame only.
3381 */
3382 void showState(MethodInfo* info, const bytecode_t *code_start, const bytecode_t *pc, Atom* framep, Atom *spp, int scopeDepth, Atom *scopebasep, int max_scope)
3383 {
3384#ifdef VMCFG_WORDCODE
3385# ifdef VMCFG_DIRECT_THREADED
3386 // 'opcode' is really a code pointer.
3387 void* address = (void*)*pc;
3388 WordOpcode opcode = (WordOpcode)0;
3389 void** jumptable = interpGetOpcodeLabels();
3390 for ( int i=0 ; i <= WOP_LAST ; i++ ) {
3391 if (jumptable[i] == address) {
3392 opcode = (WordOpcode)i;
3393 break;
3394 }
3395 }
3396 // this cannot happen due to the structure of the loop above
3397 // (and triggers a warning in some exceptionally-picky compilers)
3398 //if (opcode < 0 || opcode > WOP_LAST)
3399 // opcode = (WordOpcode)0;
3400# else
3401 WordOpcode opcode = (WordOpcode) *pc;
3402# endif
3403#else
3404 AbcOpcode opcode = (AbcOpcode) *pc;
3405#endif
3406 PoolObject* pool = info->pool();
3407 AvmCore* core = pool->core;
3408 ptrdiff_t off = pc - code_start;
3409 ptrdiff_t sp = spp - framep;
3410 ptrdiff_t scopep = scopebasep + scopeDepth - 1 - framep;
3411 ptrdiff_t scopeBase = scopebasep - framep;
3412 ptrdiff_t stackBase = scopebasep + max_scope - framep;
3413
3414// this is handy for debugging 64-specific interpreter bugs.
3415//#ifdef AVMPLUS_64BIT
3416// core->console << " stack-raw:";
3417// for (ptrdiff_t i=stackBase; i <= sp; i++) {
3418// core->console << " 0x" << MathUtils::convertDoubleToStringRadix(core, framep[i]>>32, 16) <<
3419// MathUtils::convertDoubleToStringRadix(core, framep[i]&0xffffffff, 16);
3420// }
3421// core->console << '\n';
3422//#endif
3423
3424 // locals
3425 core->console << " [";
3426 for (ptrdiff_t i=0, n=scopeBase; i<n; i++) {
3427 core->console << asAtom(framep[i]);
3428 if (i+1<n) core->console << ' ';
3429 }
3430
3431 // scope chain
3432 core->console << "] {";
3433 for (ptrdiff_t i=scopeBase, n=scopep; i<=n; i++) {
3434 core->console << asAtom(framep[i]);
3435 if (i+1<=n) core->console << ' ';
3436 }
3437
3438 // stack
3439 core->console << "} (";
3440 ptrdiff_t stackStart = stackBase;
3441 const size_t stackLimit = 20; // don't display more than this, to reduce verbosity
3442 size_t stackDepth = (stackBase <= sp) ? sp - stackBase : 0;
3443 if (stackDepth > stackLimit) {
3444 stackStart = sp - stackLimit;
3445 core->console << "..." << (stackStart-stackBase) << ": ";
3446 }
3447 for (ptrdiff_t i=stackStart, n=sp; i<=n; i++) {
3448 core->console << asAtom(framep[i]);
3449 if (i+1<=n) core->console << ' ';
3450 }
3451
3452 // opcode
3453 core->console << ")\n ";
3454#ifdef DEBUGGER
3455 if (core->debugger() && core->callStack && core->callStack->filename())
3456 {
3457 core->console << '[' << core->callStack->filename() << ':' << (uint32_t)core->callStack->linenum() << "] ";
3458 }
3459#endif
3460 core->console << (int)off << ':';
3461 // Using largest-possible-pointer here for code_end; this is obviously not correct,
3462 // but extracting the proper code_end requires diving into the method's ABC bytecode
3463 // (and may not be easily accessible at all for wordcode), and more importantly,
3464 // is only used for range-checking of fuzzed opcodes... all of which should have been caught
3465 // by Verifier, thus checking should be unnecessary here.
3466 const bytecode_t* const code_end = (const bytecode_t*)uintptr_t(-1);
3467#ifdef VMCFG_WORDCODE
3468 core->formatOpcode(core->console, pc, code_end, (WordOpcode)((int32_t)opcode&0xffff), off, pool);
3469#else
3470 core->formatOpcode(core->console, pc, code_end, opcode, off, pool);
3471#endif
3472 core->console << '\n';
3473 }
3474#endif // AVMPLUS_VERBOSE
3475}