1 /* -*- mode: java; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is [Open Source Virtual Machine.].
17 * The Initial Developer of the Original Code is
18 * Adobe System Incorporated.
19 * Portions created by the Initial Developer are Copyright (C) 2004-2006
20 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 use default namespace Asm,
42 /*******************************************************************
46 const CONSTANT_Utf8 = 0x01;
47 const CONSTANT_Integer = 0x03;
48 const CONSTANT_UInt = 0x04;
49 const CONSTANT_PrivateNamespace = 0x05;
50 const CONSTANT_Double = 0x06;
51 const CONSTANT_QName = 0x07; // ns::name, const ns, const name
52 const CONSTANT_Namespace = 0x08;
53 const CONSTANT_Multiname = 0x09; // [ns...]::name, const [ns...], const name
54 const CONSTANT_False = 0x0A;
55 const CONSTANT_True = 0x0B;
56 const CONSTANT_Null = 0x0C;
57 const CONSTANT_QNameA = 0x0D; // @ns::name, const ns, const name
58 const CONSTANT_MultinameA = 0x0E; // @[ns...]::name, const [ns...], const name
59 const CONSTANT_RTQName = 0x0F; // ns::name, var ns, const name
60 const CONSTANT_RTQNameA = 0x10; // @ns::name, var ns, const name
61 const CONSTANT_RTQNameL = 0x11; // ns::[name], var ns, var name
62 const CONSTANT_RTQNameLA = 0x12; // @ns::[name], var ns, var name
63 const CONSTANT_NameL = 0x13; // o[name], var name
64 const CONSTANT_NameLA = 0x14; // @[name], var name
65 const CONSTANT_NamespaceSet = 0x15;
66 const CONSTANT_PackageNamespace = 0x16; // namespace for a package
67 const CONSTANT_PackageInternalNS = 0x17;
68 const CONSTANT_ProtectedNamespace = 0x18;
69 const CONSTANT_ExplicitNamespace = 0x19;
70 const CONSTANT_StaticProtectedNS = 0x1A;
71 const CONSTANT_MultinameL = 0x1B;
72 const CONSTANT_MultinameLA = 0x1C;
74 const CONSTANT_ClassSealed = 0x01;
75 const CONSTANT_ClassFinal = 0x02;
76 const CONSTANT_ClassInterface = 0x04;
77 const CONSTANT_ClassProtectedNs = 0x08;
80 const TRAIT_Method = 1;
81 const TRAIT_Getter = 2;
82 const TRAIT_Setter = 3;
83 const TRAIT_Class = 4;
84 const TRAIT_Function = 5;
85 const TRAIT_Const = 6;
87 const ATTR_Final = 0x01;
88 const ATTR_Override = 0x02;
89 const ATTR_Metadata = 0x04;
92 const SLOT_method = 1;
93 const SLOT_getter = 2;
94 const SLOT_setter = 3;
96 const SLOT_function = 6;
98 const METHOD_Arguments = 0x1;
99 const METHOD_Activation = 0x2;
100 const METHOD_Needrest = 0x4;
101 const METHOD_HasOptional = 0x8;
102 const METHOD_IgnoreRest = 0x10;
103 const METHOD_Native = 0x20;
104 const METHOD_Setsdxns = 0x40;
105 const METHOD_HasParamNames = 0x80;
107 const OP_bkpt:int = 0x01;
108 const OP_nop:int = 0x02;
109 const OP_throw:int = 0x03;
110 const OP_getsuper:int = 0x04;
111 const OP_setsuper:int = 0x05;
112 const OP_dxns:int = 0x06;
113 const OP_dxnslate:int = 0x07;
114 const OP_kill:int = 0x08;
115 const OP_label:int = 0x09;
116 const OP_ifnlt:int = 0x0C;
117 const OP_ifnle:int = 0x0D;
118 const OP_ifngt:int = 0x0E;
119 const OP_ifnge:int = 0x0F;
120 const OP_jump:int = 0x10;
121 const OP_iftrue:int = 0x11;
122 const OP_iffalse:int = 0x12;
123 const OP_ifeq:int = 0x13;
124 const OP_ifne:int = 0x14;
125 const OP_iflt:int = 0x15;
126 const OP_ifle:int = 0x16;
127 const OP_ifgt:int = 0x17;
128 const OP_ifge:int = 0x18;
129 const OP_ifstricteq:int = 0x19;
130 const OP_ifstrictne:int = 0x1A;
131 const OP_lookupswitch:int = 0x1B;
132 const OP_pushwith:int = 0x1C;
133 const OP_popscope:int = 0x1D;
134 const OP_nextname:int = 0x1E;
135 const OP_hasnext:int = 0x1F;
136 const OP_pushnull:int = 0x20;
137 const OP_pushundefined:int = 0x21;
138 const OP_pushconstant:int = 0x22;
139 const OP_nextvalue:int = 0x23;
140 const OP_pushbyte:int = 0x24;
141 const OP_pushshort:int = 0x25;
142 const OP_pushtrue:int = 0x26;
143 const OP_pushfalse:int = 0x27;
144 const OP_pushnan:int = 0x28;
145 const OP_pop:int = 0x29;
146 const OP_dup:int = 0x2A;
147 const OP_swap:int = 0x2B;
148 const OP_pushstring:int = 0x2C;
149 const OP_pushint:int = 0x2D;
150 const OP_pushuint:int = 0x2E;
151 const OP_pushdouble:int = 0x2F;
152 const OP_pushscope:int = 0x30;
153 const OP_pushnamespace:int = 0x31;
154 const OP_hasnext2:int = 0x32;
155 const OP_newfunction:int = 0x40;
156 const OP_call:int = 0x41;
157 const OP_construct:int = 0x42;
158 const OP_callmethod:int = 0x43;
159 const OP_callstatic:int = 0x44;
160 const OP_callsuper:int = 0x45;
161 const OP_callproperty:int = 0x46;
162 const OP_returnvoid:int = 0x47;
163 const OP_returnvalue:int = 0x48;
164 const OP_constructsuper:int = 0x49;
165 const OP_constructprop:int = 0x4A;
166 const OP_callsuperid:int = 0x4B;
167 const OP_callproplex:int = 0x4C;
168 const OP_callinterface:int = 0x4D;
169 const OP_callsupervoid:int = 0x4E;
170 const OP_callpropvoid:int = 0x4F;
171 const OP_newobject:int = 0x55;
172 const OP_newarray:int = 0x56;
173 const OP_newactivation:int = 0x57;
174 const OP_newclass:int = 0x58;
175 const OP_getdescendants:int = 0x59;
176 const OP_newcatch:int = 0x5A;
177 const OP_findpropstrict:int = 0x5D;
178 const OP_findproperty:int = 0x5E;
179 const OP_finddef:int = 0x5F;
180 const OP_getlex:int = 0x60;
181 const OP_setproperty:int = 0x61;
182 const OP_getlocal:int = 0x62;
183 const OP_setlocal:int = 0x63;
184 const OP_getglobalscope:int = 0x64;
185 const OP_getscopeobject:int = 0x65;
186 const OP_getproperty:int = 0x66;
187 const OP_getouterscope:int = 0x67;
188 const OP_initproperty:int = 0x68;
189 const OP_setpropertylate:int = 0x69;
190 const OP_deleteproperty:int = 0x6A;
191 const OP_deletepropertylate:int = 0x6B;
192 const OP_getslot:int = 0x6C;
193 const OP_setslot:int = 0x6D;
194 const OP_getglobalslot:int = 0x6E;
195 const OP_setglobalslot:int = 0x6F;
196 const OP_convert_s:int = 0x70;
197 const OP_esc_xelem:int = 0x71;
198 const OP_esc_xattr:int = 0x72;
199 const OP_convert_i:int = 0x73;
200 const OP_convert_u:int = 0x74;
201 const OP_convert_d:int = 0x75;
202 const OP_convert_b:int = 0x76;
203 const OP_convert_o:int = 0x77;
204 const OP_checkfilter:int = 0x78;
205 const OP_coerce:int = 0x80;
206 const OP_coerce_b:int = 0x81;
207 const OP_coerce_a:int = 0x82;
208 const OP_coerce_i:int = 0x83;
209 const OP_coerce_d:int = 0x84;
210 const OP_coerce_s:int = 0x85;
211 const OP_astype:int = 0x86;
212 const OP_astypelate:int = 0x87;
213 const OP_coerce_u:int = 0x88;
214 const OP_coerce_o:int = 0x89;
215 const OP_negate:int = 0x90;
216 const OP_increment:int = 0x91;
217 const OP_inclocal:int = 0x92;
218 const OP_decrement:int = 0x93;
219 const OP_declocal:int = 0x94;
220 const OP_typeof:int = 0x95;
221 const OP_not:int = 0x96;
222 const OP_bitnot:int = 0x97;
223 const OP_concat:int = 0x9A;
224 const OP_add_d:int = 0x9B;
225 const OP_add:int = 0xA0;
226 const OP_subtract:int = 0xA1;
227 const OP_multiply:int = 0xA2;
228 const OP_divide:int = 0xA3;
229 const OP_modulo:int = 0xA4;
230 const OP_lshift:int = 0xA5;
231 const OP_rshift:int = 0xA6;
232 const OP_urshift:int = 0xA7;
233 const OP_bitand:int = 0xA8;
234 const OP_bitor:int = 0xA9;
235 const OP_bitxor:int = 0xAA;
236 const OP_equals:int = 0xAB;
237 const OP_strictequals:int = 0xAC;
238 const OP_lessthan:int = 0xAD;
239 const OP_lessequals:int = 0xAE;
240 const OP_greaterthan:int = 0xAF;
241 const OP_greaterequals:int = 0xB0;
242 const OP_instanceof:int = 0xB1;
243 const OP_istype:int = 0xB2;
244 const OP_istypelate:int = 0xB3;
245 const OP_in:int = 0xB4;
246 const OP_increment_i:int = 0xC0;
247 const OP_decrement_i:int = 0xC1;
248 const OP_inclocal_i:int = 0xC2;
249 const OP_declocal_i:int = 0xC3;
250 const OP_negate_i:int = 0xC4;
251 const OP_add_i:int = 0xC5;
252 const OP_subtract_i:int = 0xC6;
253 const OP_multiply_i:int = 0xC7;
254 const OP_getlocal0:int = 0xD0;
255 const OP_getlocal1:int = 0xD1;
256 const OP_getlocal2:int = 0xD2;
257 const OP_getlocal3:int = 0xD3;
258 const OP_setlocal0:int = 0xD4;
259 const OP_setlocal1:int = 0xD5;
260 const OP_setlocal2:int = 0xD6;
261 const OP_setlocal3:int = 0xD7;
262 const OP_debug:int = 0xEF;
263 const OP_debugline:int = 0xF0;
264 const OP_debugfile:int = 0xF1;
265 const OP_bkptline:int = 0xF2;
266 const OP_timestamp:int = 0xF3;
268 /*********************************************************************************
269 * AVM2 assembler for one code block.
271 * This is a lightweight class that is used to emit bytes for
272 * instructions and data, to maintain stack and scope depths,
273 * count local slots used, and to handle branch targets and
274 * backpatching. It has no code generation logic save for fairly
275 * simple abstractions (eg, I_getlocal() maps to "getlocal_n" or
276 * to the general "getlocal" instruction, depending on its
280 * - There needs to be a way to set the scope stack depth to 0, to be used
281 * when generating code for exception handling
282 * - It would be nice if we could check that every join point has the same
283 * stack depth, this requires that the next linear instruction following
284 * an unconditional nonreturning control flow (return, throw, jump) is
285 * a label always, or is ignored for the purposes of computing the stack
287 * - Ditto for the scope depth, really.
296 private var code = new ABCByteStream;
297 private var nextLabel = 1000;
298 private var backpatches = [];
299 private var current_scope_depth = 0;
300 private var max_scope_depth = 0;
301 private var current_stack_depth = 0;
302 private var max_stack_depth = 0;
303 private var nextTemp;
304 private var freeTemps = [];
305 private var constants;
306 private var set_dxns = false;
307 private var need_activation = false;
308 private var attr = null;
310 function AVM2Assembler(constants, numberOfFormals, attr)
311 : constants = constants
312 , current_scope_depth = 0
314 , nextTemp = numberOfFormals + 1 + (attr.uses_arguments || attr.uses_rest ? 1 : 0) // local 0 is always "this"
318 function get maxStack() { return max_stack_depth }
319 function get maxLocal() { return nextTemp }
320 function get maxScope() { return max_scope_depth }
321 function get flags() {
324 f |= METHOD_Setsdxns;
326 f |= METHOD_Activation;
327 if (attr.uses_arguments)
328 f |= METHOD_Arguments;
330 f |= METHOD_Needrest;
334 private function listL(n) {
339 private function list1(name) {
341 print(indent + name);
344 private function list2(name, v) {
346 print(indent + name + " " + v);
349 private function list3(name, v1, v2) {
351 print(indent + name + " " + v1 + " " + v2);
354 private function list5(name, v1, v2, v3, v4) {
356 print(indent + name + " " + v1 + " " + v2 + " " + v3 + " " + v4);
358 /* function listn(name, ...rest) {
360 print(indent + name + " " + rest.join(" "));
364 // Instructions that push one value, with a single opcode byte
365 private function pushOne(name, opcode) {
371 function I_dup() { pushOne("dup", 0x2A) }
372 function I_getglobalscope() { pushOne("getglobalscope", 0x64) }
373 function I_getlocal_0() { pushOne("getlocal_0", 0xD0) }
374 function I_getlocal_1() { pushOne("getlocal_1", 0xD1) }
375 function I_getlocal_2() { pushOne("getlocal_2", 0xD2) }
376 function I_getlocal_3() { pushOne("getlocal_3", 0xD3) }
377 function I_newactivation() { need_activation=true; pushOne("newactivation", 0x57) }
378 function I_pushfalse() { pushOne("pushfalse", 0x27) }
379 function I_pushnan() { pushOne("pushnan", 0x28) }
380 function I_pushnull() { pushOne("pushnull", 0x20) }
381 function I_pushtrue() { pushOne("pushtrue", 0x26) }
382 function I_pushundefined() { pushOne("pushundefined", 0x21) }
384 // Instructions that push one value, with an opcode byte followed by a u30 argument
385 private function pushOneU30(name, opcode, v) {
392 function I_getglobalslot(index) { pushOneU30("getglobalslot", 0x6E, index) }
393 function I_getlex(index) { pushOneU30("getlex", 0x60, index) }
394 function I_getscopeobject(index) { pushOneU30("getscopeobject", 0x65, index) }
395 function I_getouterscope(index) { pushOneU30("getouterscope", 0x67, index) }
396 function I_newcatch(index) { pushOneU30("newcatch", 0x5A, index) }
397 function I_newfunction(index) { pushOneU30("newfunction", 0x40, index) }
398 function I_pushdouble(index) { pushOneU30("pushdouble", 0x2F, index) }
399 function I_pushint(index) { pushOneU30("pushint", 0x2D, index) }
400 function I_pushnamespace(index) { pushOneU30("pushnamespace", 0x31, index) }
401 function I_pushshort(v) { pushOneU30("pushshort", 0x25, v) }
402 function I_pushstring(index) { pushOneU30("pushstring", 0x2C, index) }
403 function I_pushuint(index) { pushOneU30("pushuint", 0x2E, index) }
405 // start a catch block. increments stack by 1 for the exception object
406 function startCatch() { stack(1) }
408 // Instructions that pop one value, with a single opcode byte
409 private function dropOne(name, opcode) {
415 function I_add() { dropOne("add", 0xA0) }
416 function I_add_i() { dropOne("add_i", 0xC5) }
417 function I_astypelate() { dropOne("astypelate", 0x87) }
418 function I_bitand() { dropOne("bitand", 0xA8) }
419 function I_bitor() { dropOne("bitor", 0xA9) }
420 function I_bitxor() { dropOne("bitxor", 0xAA) }
421 function I_divide() { dropOne("divide", 0xA3) }
422 function I_dxnslate() { set_dxns=true; dropOne("dxnslate", 0x07) }
423 function I_equals() { dropOne("Equals", 0xAB) }
424 function I_greaterequals() { dropOne("greaterequals", 0xB0) }
425 function I_greaterthan() { dropOne("greaterthan", 0xAF) }
426 function I_hasnext() { dropOne("hasnext", 0x1F) }
427 function I_in() { dropOne("in", 0xB4) }
428 function I_instanceof() { dropOne("instanceof", 0xB1) }
429 function I_istypelate() { dropOne("istypelate", 0xB3) }
430 function I_lessequals() { dropOne("lessequals", 0xAE) }
431 function I_lessthan() { dropOne("lessthan", 0xAD) }
432 function I_lshift() { dropOne("lshift", 0xA5) }
433 function I_modulo() { dropOne("modulo", 0xA4) }
434 function I_multiply() { dropOne("multiply", 0xA2) }
435 function I_multiply_i() { dropOne("multiply_i", 0xC7) }
436 function I_nextname() { dropOne("nextname", 0x1E) }
437 function I_nextvalue() { dropOne("nextvalue", 0x23) }
438 function I_pop() { dropOne("pop", 0x29) }
439 function I_pushscope() { scope(1); dropOne("pushscope", 0x30) }
440 function I_pushwith() { scope(1); dropOne("pushwith", 0x1C) }
441 function I_returnvalue() { dropOne("returnvalue", 0x48) }
442 function I_rshift() { dropOne("rshift", 0xA6) }
443 function I_setlocal_0() { dropOne("setlocal_0", 0xD4) }
444 function I_setlocal_1() { dropOne("setlocal_1", 0xD5) }
445 function I_setlocal_2() { dropOne("setlocal_2", 0xD6) }
446 function I_setlocal_3() { dropOne("setlocal_3", 0xD7) }
447 function I_strictequals() { dropOne("strictequals", 0xAC) }
448 function I_subtract() { dropOne("subtract", 0xA1) }
449 function I_subtract_i() { dropOne("subtract_i", 0xC6) }
450 function I_throw() { dropOne("throw", 0x03) }
451 function I_urshift() { dropOne("urshift", 0xA7) }
453 // Instructions that pop one value, with an opcode byte followed by an u30 argument
454 private function dropOneU30(name, opcode, v) {
461 function I_setglobalslot(index) { dropOneU30("setglobalslot", 0x6F, index) }
463 // Instructions that do not change the stack height, with a single opcode byte
464 private function dropNone(name, opcode)
471 function I_bitnot() { dropNone("bitnot", 0x97) }
472 function I_checkfilter() { dropNone("checkfilter", 0x78) }
473 function I_coerce_a() { dropNone("coerce_a", 0x82) }
474 function I_coerce_s() { dropNone("coerce_s", 0x85) }
475 function I_convert_b() { dropNone("convert_b", 0x76) }
476 function I_convert_d() { dropNone("convert_d", 0x75) }
477 function I_convert_i() { dropNone("convert_i", 0x73) }
478 function I_convert_o() { dropNone("convert_o", 0x77) }
479 function I_convert_s() { dropNone("convert_s", 0x70) }
480 function I_convert_u() { dropNone("convert_u", 0x74) }
481 function I_decrement() { dropNone("decrement", 0x93) }
482 function I_decrement_i() { dropNone("decrement_i", 0xC1) }
483 function I_esc_xattr() { dropNone("esc_xattr", 0x72) }
484 function I_esc_xelem() { dropNone("esc_xattr", 0x71) }
485 function I_increment() { dropNone("increment", 0x91) }
486 function I_increment_i() { dropNone("increment_i", 0xC0) }
487 function I_negate() { dropNone("negate", 0x90) }
488 function I_negate_i() { dropNone("negate_i", 0xC4) }
489 function I_nop() { dropNone("nop", 0x02) }
490 function I_not() { dropNone("not", 0x96) }
491 function I_popscope() { scope(-1); dropNone("popscope", 0x1D) }
492 function I_returnvoid() { dropNone("returnvoid", 0x47) }
493 function I_swap() { dropNone("swap", 0x2B) }
494 function I_typeof() { dropNone("typeof", 0x95) }
496 // Instructions that do not change the stack height, with an opcode byte
497 // followed by a u30 argument
498 private function dropNoneU30(name, opcode, x) {
505 function I_astype(index) { dropNoneU30("astype", 0x86, index) }
506 function I_coerce(index) { dropNoneU30("coerce", 0x80, index) }
507 function I_debugfile(index) { dropNoneU30("debugfile", 0xF1, index) }
508 function I_debugline(linenum) { dropNoneU30("debugline", 0xF0, linenum) }
509 function I_declocal(reg) { dropNoneU30("declocal", 0x94, reg) }
510 function I_declocal_i(reg) { dropNoneU30("declocal_i", 0xC3, reg) }
511 function I_dxns(index) { set_dxns=true; dropNoneU30("dxns", 0x06, index) }
512 function I_getslot(index) { dropNoneU30("getslot", 0x6C, index) }
513 function I_inclocal(reg) { dropNoneU30("inclocal", 0x92, reg) }
514 function I_inclocal_i(reg) { dropNoneU30("inclocal_i", 0xC2, reg) }
515 function I_istype(index) { dropNoneU30("istype", 0xB2, index) }
516 function I_kill(index) { dropNoneU30("kill", 0x08, index) }
517 function I_newclass(index) { dropNoneU30("newclass", 0x58, index) }
519 function I_getlocal(index) {
521 case 0: I_getlocal_0(); break;
522 case 1: I_getlocal_1(); break;
523 case 2: I_getlocal_2(); break;
524 case 3: I_getlocal_3(); break;
525 default: pushOneU30("getlocal", 0x62, index);
529 function I_setlocal(index) {
531 case 0: I_setlocal_0(); break;
532 case 1: I_setlocal_1(); break;
533 case 2: I_setlocal_2(); break;
534 case 3: I_setlocal_3(); break;
535 default: dropOneU30("setlocal", 0x63, index);
539 // Local control flow instructions and I_label():
540 // - If called without an argument return a "label" that can later be
541 // passed to I_label() to give the label an actual value.
542 // - If called with an argument, the argument must have been returned
543 // from a control flow instruction or from I_label(). It represents
544 // a transfer target.
546 // A "label" is a data structure with these fields:
547 // - name (uint): a symbolic name for the label, to be used in listings
548 // - address (int): either -1 for "unknown" or the address of the label
549 // - stack (uint): the stack depth at label creation time; this is the
550 // stack depth at the target too [except for exception handling]
551 // - scope (uint): the scope stack depth at label creation time; this is the
552 // scope stack depth at the target too [except for exception handling]
554 // The method newLabel() can be called to return a label that
555 // will later be defined by I_label and referenced by control
556 // flow instructions, without creating a jump instruction at
557 // the point where the label is created. Typically this is
558 // used to create branch targets for "break" and "continue".
560 function newLabel() {
561 return { "name": nextLabel++, "address": -1, "stack": current_stack_depth, "scope": current_scope_depth };
564 private function relativeOffset(base, L) {
566 code.int24(L.address - base);
568 backpatches.push({ "loc": code.length, "base": base, "label": L });
573 private function jmp(stk, name, opcode, L) {
581 relativeOffset(code.length+3, L);
586 function I_label(L) {
587 var here = code.length;
589 if (L === undefined) {
594 Util::assert( L.address == -1 );
595 current_stack_depth = L.stack;
596 current_scope_depth = L.scope;
599 listL(L.name + ": -- " + L.stack + "/" + L.scope);
607 function I_ifeq(L) { return jmp(-2, "ifeq", 0x13, L) }
608 function I_ifge(L) { return jmp(-2, "ifge", 0x18, L) }
609 function I_ifgt(L) { return jmp(-2, "ifgt", 0x17, L) }
610 function I_ifle(L) { return jmp(-2, "ifle", 0x16, L) }
611 function I_iflt(L) { return jmp(-2, "iflt", 0x15, L) }
612 function I_ifne(L) { return jmp(-2, "ifne", 0x14, L) }
613 function I_ifnge(L) { return jmp(-2, "ifnge", 0x0F, L) }
614 function I_ifngt(L) { return jmp(-2, "ifngt", 0x0E, L) }
615 function I_ifnle(L) { return jmp(-2, "ifnle", 0x0D, L) }
616 function I_ifnlt(L) { return jmp(-2, "ifnlt", 0x0C, L) }
617 function I_ifstricteq(L) { return jmp(-2, "ifstricteq", 0x19, L) }
618 function I_ifstrictne(L) { return jmp(-2, "ifstrictne", 0x1A, L) }
620 function I_iffalse(L) { return jmp(-1, "iffalse", 0x12, L) }
621 function I_iftrue(L) { return jmp(-1, "iftrue", 0x11, L) }
623 function I_jump(L) { return jmp(0, "jump", 0x10, L) }
625 // Here, case_labels must be an array with a "length" property
626 // that denotes the number of case labels in the array.
627 // length cannot be 0.
629 // Either default_label is undefined and all the elements of
630 // case_labels are also undefined, or default_label is a label
631 // structure, and all the elements of case_labels between 0
632 // and length-1 are label structures as well.
634 // In the former case, labels are created for the
635 // default_label and for all the case_labels; the array is
636 // updated; and the new default_label is returned.
638 function I_lookupswitch(default_label, case_labels) {
639 Util::assert( case_labels.push ); /*FIXME ES4: really "case_labels is Array" */
640 Util::assert( case_labels.length > 0 );
644 if (default_label === undefined) {
645 default_label = newLabel();
646 for ( var i=0, limit=case_labels.length ; i < limit ; i++ ) {
647 Util::assert( case_labels[i] === undefined );
648 case_labels[i] = newLabel();
652 function map_func(L) { return L.name };
653 list3("lookupswitch", default_label.name, Util::map(map_func, case_labels));
654 var base = code.length;
656 relativeOffset(base, default_label);
657 code.uint30(case_labels.length-1);
658 for ( var i=0, limit=case_labels.length ; i < limit ; i++ )
659 relativeOffset(base, case_labels[i]);
661 return default_label;
664 // Standard function calls
665 private function call(name, opcode, nargs) {
666 stack(1-(nargs+2)); /* pop function/receiver/args; push result */
672 private function construct(name, opcode, nargs) {
673 stack(1-(nargs+1)); /* pop function/receiver/args; push result */
679 function I_call(nargs) { call("call", 0x41, nargs) }
680 function I_construct(nargs) { construct("construct", 0x42, nargs) }
682 function I_constructsuper(nargs) {
683 stack(nargs+1); /* pop receiver/args */
684 list2("constructsuper", nargs);
689 private function callIDX(name, opcode, index, nargs) {
690 stack(1-(nargs+1)); /* pop receiver/args; push result */
691 list3(name, index, nargs);
697 function I_callmethod(index, nargs) { callIDX("callmethod", 0x43, index, nargs) }
698 function I_callstatic(index, nargs) { callIDX("callstatic", 0x44, index, nargs) }
700 private function callMN(name, opcode, index, nargs, isVoid) {
701 /* pop receiver/NS?/Name?/args; push result? */
702 var hasRTNS = constants.hasRTNS(index);
703 var hasRTName = constants.hasRTName(index);
704 stack((isVoid ? 0 : 1) - (1 + (hasRTNS ? 1 : 0) + (hasRTName ? 1 : 0) + nargs));
705 list3(name + (hasRTNS ? "<NS>" : "") + (hasRTName ? "<Name>" : ""), index, nargs);
711 function I_callsuper(index, nargs) { callMN("callsuper", 0x45, index, nargs, false) }
712 function I_callproperty(index, nargs) { callMN("callproperty", 0x46, index, nargs, false) }
713 function I_constructprop(index, nargs) { callMN("constructprop", 0x4A, index, nargs, false) }
714 function I_callproplex(index, nargs) { callMN("callproplex", 0x4C, index, nargs, false) }
715 function I_callsupervoid(index, nargs) { callMN("callsupervoid", 0x4E, index, nargs, true) }
716 function I_callpropvoid(index, nargs) { callMN("callpropvoid", 0x4F, index, nargs, true) }
718 function I_debug(debug_type, index, reg, extra=0) {
720 list5("debug", debug_type, index, reg, extra);
722 code.uint8(debug_type);
728 /* Generic property operation when there may be a namespace or
729 name on the stack. The instruction pops and pushes some
730 fixed amount and may pop one or two more items, depending
731 on the kind of name that index references.
733 private function propU30(name, pops, pushes, opcode, index) {
734 var hasRTNS = constants.hasRTNS(index);
735 var hasRTName = constants.hasRTName(index);
736 stack(pushes - (pops + (hasRTNS ? 1 : 0) + (hasRTName ? 1 : 0)));
737 list2(name + (hasRTNS ? "<NS>" : "") + (hasRTName ? "<Name>" : ""), index);
742 function I_deleteproperty(index) { propU30("deleteproperty", 1, 1, 0x6A, index) }
743 function I_getdescendants(index) { propU30("getdescendants", 1, 1, 0x59, index) }
744 function I_getproperty(index) { propU30("getproperty", 1, 1, 0x66, index); }
745 function I_getsuper(index) { propU30("getsuper", 1, 1, 0x04, index); }
746 function I_findproperty(index) { propU30("findproperty", 0, 1, 0x5E, index) }
747 function I_findpropstrict(index) { propU30("findpropstrict", 0, 1, 0x5D, index) }
748 function I_initproperty(index) { propU30("initproperty", 2, 0, 0x68, index) }
749 function I_setproperty(index) { propU30("setproperty", 2, 0, 0x61, index) }
750 function I_setsuper(index) { propU30("setsuper", 2, 0, 0x05, index) }
752 function I_hasnext2(object_reg, index_reg) {
755 code.uint30(object_reg);
756 code.uint30(index_reg);
759 function I_newarray(nargs) {
761 list2("newarray", nargs);
766 function I_newobject(nargs) {
767 stack(1 - (2 * nargs));
768 list2("newobject", nargs);
773 function I_pushbyte(b) {
775 list2("pushbyte", b);
780 function I_setslot(index) {
782 list2("setslot", index);
788 if (freeTemps.length > 0)
789 return freeTemps.pop();
794 function killTemp(t) {
799 function get length() {
803 function finalize() {
804 resolveBackpatches();
808 private function resolveBackpatches() {
809 for ( var i=0, limit=backpatches.length ; i < limit ; i++ ) {
810 var bp = backpatches[i];
811 if (bp.label.address == -1)
812 Util::internalError("", 0, "Missing definition for label " + bp.label.name); // FIXME: source pos
813 var v = bp.label.address - bp.base;
814 code.setInt24(bp.loc, v);
816 backpatches.length = 0;
819 private function stack(n) {
820 current_stack_depth = current_stack_depth + n;
821 if (current_stack_depth > max_stack_depth) {
822 max_stack_depth = current_stack_depth;
826 private function scope(n) {
827 current_scope_depth = current_scope_depth + n;
828 if (current_scope_depth > max_scope_depth)
829 max_scope_depth = current_scope_depth;