Bug Summary

File:platform/mac/avmshell/../../../core/Verifier.cpp
Location:line 109, column 9
Description:Value stored to 'pos' 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#include "avmplus.h"
41
42//#define DOPROF
43#include "../vprof/vprof.h"
44
45namespace avmplus
46{
47#ifdef VMCFG_WORDCODE
48 inline WordOpcode wordCode(AbcOpcode opcode) {
49 return (WordOpcode)opcodeInfo[opcode].wordCode;
50 }
51#endif
52
53 Verifier::Verifier(MethodInfo* info, MethodSignaturep ms, Toplevel* toplevel, AbcEnv* abc_env
54#ifdef AVMPLUS_VERBOSE
55 , boolbool secondTry
56#endif
57 ) : tryFrom(NULL__null), tryTo(NULL__null)
58 , info(info), ms(ms)
59 , worklist(NULL__null)
60 , blockStates(NULL__null)
61 , handlerIsReachable(falsefalse)
62 {
63#ifdef AVMPLUS_VERBOSE
64 this->secondTry = secondTry;
65#endif
66 this->core = info->pool()->core;
67 this->pool = info->pool();
68 this->toplevel = toplevel;
69 this->abc_env = abc_env;
70
71 state = NULL__null;
72
73 #ifdef VMCFG_RESTARG_OPTIMIZATION
74 restArgAnalyzer.init(core, info, ms->frame_size());
75 #endif
76
77 #ifdef AVMPLUS_VERBOSE
78 verbose = pool->isVerbose(VB_verify, info);
79 #endif
80
81 pool->initPrecomputedMultinames();
82 }
83
84 Verifier::~Verifier()
85 {
86 mmfx_delete( this->state )::MMgcDestructTaggedScalarChecked(this->state);
87 if (blockStates) {
88 for(int i = 0, n=blockStates->map.length(); i < n; i++)
89 mmfx_delete( blockStates->map.at(i) )::MMgcDestructTaggedScalarChecked(blockStates->map.at(i));
90 delete blockStates;
91 }
92 }
93
94 boolbool Verifier::hasReachableExceptions() const
95 {
96 // Valid during code generation only.
97 AvmAssert(emitPass)do { } while (0);
98 return handlerIsReachable;
99 }
100
101 void Verifier::parseBodyHeader()
102 {
103 // note: reading of max_stack, etc (and validating the values)
104 // is handled by MethodInfo::resolveSignature.
105 const uint8_t* pos = info->abc_body_pos();
106 AvmCore::skipU32(pos, 4);
107 code_length = AvmCore::readU32(pos);
108 code_pos = pos;
109 pos += code_length;
Value stored to 'pos' is never read
110 }
111
112 // ScopeWriter implements the scope-type-capturing functionality
113 // for OP_newfunction and OP_newclass, as well as error checking
114 // to handle illegally capturing incompatible scopes for the same
115 // function. All other opcodes are ignored. Expected to be used
116 // in the verifier's phase 2 when each bytecode is only visited once.
117 class ScopeWriter: public NullWriter
118 {
119 MethodInfo* info;
120 Toplevel* toplevel;
121 Verifier *verifier;
122 public:
123 ScopeWriter(CodeWriter* coder, MethodInfo* info,
124 Toplevel* toplevel, Verifier* verifier)
125 : NullWriter(coder), info(info),
126 toplevel(toplevel), verifier(verifier)
127 {}
128
129 void write(const FrameState* state, const uint8_t* pc, AbcOpcode opcode, Traits* type)
130 {
131 if (opcode == OP_newactivation) {
132 // Capture activation scope the first time the method is verified.
133 const ScopeTypeChain *scope = info->activationScope();
134 if (scope == NULL__null) {
135 AvmAssert(type == info->activationTraits())do { } while (0);
136 MMgc::GC* gc = info->pool()->core->GetGC();
137 scope = info->declaringScope()->cloneWithNewTraits(gc, type);
138 type->setDeclaringScopes(scope);
139 info->init_activationScope(scope);
140 }
141 }
142 coder->write(state, pc, opcode, type);
143 }
144
145 void writeOp1(const FrameState* state, const uint8_t* pc, AbcOpcode opcode, uint32_t imm30, Traits* type)
146 {
147 if (opcode == OP_newfunction) {
148 PoolObject* pool = info->pool();
149 AvmCore* core = pool->core;
150 const ScopeTypeChain* scope = info->declaringScope();
151 MethodInfo* f = pool->getMethodInfo(imm30);
152 Traits* ftraits = core->traits.function_itraits;
153 const ScopeTypeChain* fscope = ScopeTypeChain::create(core->GetGC(), ftraits, scope, state, NULL__null, NULL__null);
154 // Duplicate function definitions aren't strictly legal, but can occur
155 // in otherwise "well formed" ABC due to old, buggy versions of ASC.
156 // Specifically, code of the form
157 //
158 // public function simpleTest():void
159 // {
160 // var f:Function = function():void { }
161 // f();
162 // f = function functwo (x):void { }
163 // f(8);
164 // }
165 //
166 // could cause the second interior function ("functwo") to include a bogus, unused OP_newfunction
167 // call to itself inside the body of functwo. This caused the scope to get reinitialized
168 // and generally caused havok. However, we want to allow existing code of this form to continue
169 // to work, so check to see if we already have a declaringScope, and if so, require that
170 // it match this one.
171 const ScopeTypeChain* curScope = f->declaringScope();
172 if (curScope != NULL__null)
173 {
174 if (!curScope->equals(fscope))
175 {
176 // if info->method_id() == imm30, f == info, and therefore
177 // curScope == scope -- don't redefine, don't fail verification,
178 // just accept it. see https://bugzilla.mozilla.org/show_bug.cgi?id=544370
179 if (info->method_id() != int32_t(imm30))
180 toplevel->throwVerifyError(kCorruptABCError);
181
182 AvmAssert(curScope->equals(scope))do { } while (0);
183 }
184 AvmAssert(f->isResolved())do { } while (0);
185 }
186 else
187 {
188 f->makeIntoPrototypeFunction(toplevel, fscope);
189 }
190
191 #ifdef AVMPLUS_VERBOSE
192 if (verifier->verbose)
193 verifier->printScope("function-scope", fscope);
194 #endif
195 } else if (opcode == OP_newclass) {
196 PoolObject* pool = info->pool();
197 AvmCore* core = pool->core;
198 const ScopeTypeChain* scope = info->declaringScope();
199 Traits* ctraits = type;
200 // the actual result type will be the static traits of the new class.
201 // make sure the traits came from this pool. they have to because
202 // the class_index operand is resolved from the current pool.
203 AvmAssert(ctraits->pool == pool)do { } while (0);
204 Traits *itraits = ctraits->itraits;
205
206 // add a type constraint for the "this" scope of static methods
207 const ScopeTypeChain* cscope = ScopeTypeChain::create(core->GetGC(), ctraits, scope, state, NULL__null, ctraits);
208
209 if (state->scopeDepth > 0)
210 {
211 // innermost scope must be the base class object or else createInstance()
212 // will malfunction because it will use the wrong [base] class object to
213 // construct the instance. See ScriptObject::createInstance()
214 Traits* baseCTraits = state->scopeValue(state->scopeDepth-1).traits;
215 if (!baseCTraits || baseCTraits->itraits != itraits->base)
216 verifier->verifyFailed(kCorruptABCError);
217 }
218
219 // add a type constraint for the "this" scope of instance methods
220 const ScopeTypeChain* iscope = ScopeTypeChain::create(core->GetGC(), itraits, cscope, NULL__null, ctraits, itraits);
221
222 ctraits->resolveSignatures(toplevel);
223 itraits->resolveSignatures(toplevel);
224
225 const ScopeTypeChain *cur_cscope = ctraits->declaringScope();
226 const ScopeTypeChain *cur_iscope = itraits->declaringScope();
227 if (!cur_cscope) {
228 // first time we have seen this class, capture scope types
229 ctraits->setDeclaringScopes(cscope);
230 itraits->setDeclaringScopes(iscope);
231 } else {
232 // we have captured a scope already for this class. it better match!
233 if (!cur_cscope->equals(cscope) ||
234 !cur_iscope ||
235 !cur_iscope->equals(iscope)) {
236 toplevel->throwVerifyError(kCorruptABCError);
237 }
238 // use the old ScopeTypeChains, discard the new ones
239 cscope = cur_cscope;
240 iscope = cur_iscope;
241 }
242 #ifdef AVMPLUS_VERBOSE
243 if (verifier->verbose)
244 verifier->printScope("class-scope", cscope);
245 #endif
246 }
247 coder->writeOp1(state, pc, opcode, imm30, type);
248 }
249 };
250
251#ifdef VMCFG_RESTARG_OPTIMIZATION
252
253 // Most interesting things happen in init()
254 RestArgAnalyzer::RestArgAnalyzer()
255 : NullWriter(NULL__null)
256 , optimize(truetrue)
257 , core(NULL__null)
258 , info(NULL__null)
259 , pool(NULL__null)
260 , frameSize(0)
261 , restVar(0)
262 , isRestArray(NULL__null)
263 {
264 }
265
266 void RestArgAnalyzer::init(AvmCore* _core, MethodInfo* _info, uint32_t _frameSize)
267 {
268 core = _core;
269 info = _info;
270 pool = _info->pool();
271 frameSize = _frameSize;
272
273 if (_info->needRest() || (_info->needArguments() && _info->onlyUntypedParameters()))
274 restVar = _info->getMethodSignature()->param_count() + 1;
275 else
276 optimize = falsefalse;
277#ifdef DEBUGGER
278 if (core->debugger() != NULL__null)
279 optimize = falsefalse;
280#endif
281 if (optimize) {
282 isRestArray = mmfx_new_array(bool, frameSize)::MMgcConstructTaggedArray((bool*)__null, frameSize, MMgc::kNone
)
;
283 VMPI_memset::memset(isRestArray, 0, frameSize*sizeof(boolbool));
284 }
285 }
286
287 RestArgAnalyzer::~RestArgAnalyzer()
288 {
289 mmfx_delete_array(isRestArray)::MMgcDestructTaggedArrayChecked(isRestArray);
290 isRestArray = NULL__null;
291 }
292
293 CodeWriter* RestArgAnalyzer::hookup(CodeWriter* next, boolbool pass2)
294 {
295 if (optimize) {
296 if (pass2)
297 info->setLazyRest();
298 coder = next;
299 return this;
300 }
301 return next;
302 }
303
304 // Called when the analysis fails (but not during setup). Factored out to
305 // allow easy breakpointing, etc.
306 inline void RestArgAnalyzer::fail()
307 {
308 optimize = falsefalse;
309 }
310
311 void RestArgAnalyzer::endBlock()
312 {
313 if (!optimize)
314 return;
315 for ( uint32_t i=0 ; i < frameSize ; i++ )
316 if (isRestArray[i])
317 fail();
318 }
319
320 void RestArgAnalyzer::write(const FrameState* state, const uint8_t* pc, AbcOpcode opcode, Traits *type)
321 {
322 if (optimize)
323 operate(state, pc, opcode);
324 coder->write(state, pc, opcode, type);
325 }
326
327 void RestArgAnalyzer::writeOp1(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, uint32_t opd1, Traits* type)
328 {
329 if (optimize)
330 operate(state, pc, opcode);
331 coder->writeOp1(state, pc, opcode, opd1, type);
332 }
333
334 void RestArgAnalyzer::writeOp2(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, uint32_t opd1, uint32_t opd2, Traits* type)
335 {
336 if (optimize)
337 operate(state, pc, opcode);
338 coder->writeOp2(state, pc, opcode, opd1, opd2, type);
339 }
340
341 void RestArgAnalyzer::writeMethodCall(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, MethodInfo* m, uintptr_t disp_id, uint32_t argc, Traits* type)
342 {
343 if (optimize)
344 operate(state, pc, opcode);
345 coder->writeMethodCall(state, pc, opcode, m, disp_id, argc, type);
346 }
347
348 boolbool RestArgAnalyzer::getProperty(const FrameState* state, const Multiname& multiname, int obj_offset)
349 {
350 if (!optimize)
351 return falsefalse;
352
353 uint32_t sp = state->sp();
354
355 // Be sure the arguments to run-time names aren't the rest array.
356 uint32_t numprops = (multiname.isRtname() != 0) + (multiname.isRtns() != 0);
357 if (numprops > 0) {
358 if (isRestArray[sp])
359 fail();
360 }
361 if (numprops > 1) {
362 if (isRestArray[sp-1])
363 fail();
364 }
365 if (!optimize)
366 return falsefalse;
367
368 if (isRestArray[sp-obj_offset+1])
369 {
370 isRestArray[sp-obj_offset+1] = falsefalse;
371
372 if (multiname.isRtname() && multiname.containsAnyPublicNamespace())
373 {
374 // OP_restarg candidate
375 // containsAnyPublicNamespace should imply n==2 - the multiname must have ns or nsset
376 AvmAssert(obj_offset == 2)do { } while (0);
377 }
378 else if (multiname.getName() == core->klength && multiname.containsAnyPublicNamespace())
379 {
380 // OP_restargc candidate
381 AvmAssert(obj_offset == 1)do { } while (0);
382 }
383 else
384 {
385 fail();
386 }
387 return optimize;
388 }
389 else {
390 return falsefalse;
391 }
392 }
393
394 void RestArgAnalyzer::writeOpcodeVerified(const FrameState* state, const uint8_t *pc, AbcOpcode opcode)
395 {
396 if (optimize)
397 {
398 switch (opcode)
399 {
400 case OP_getlocal:
401 {
402 uint32_t imm30=0, imm30b=0;
403 int32_t imm8=0, imm24=0;
404 AvmCore::readOperands(pc, imm30, imm24, imm30b, imm8);
405 if (restVar == imm30)
406 isRestArray[state->sp()] = truetrue;
407 break;
408 }
409 case OP_getlocal0:
410 case OP_getlocal1:
411 case OP_getlocal2:
412 case OP_getlocal3:
413 {
414 if (restVar == uint32_t(opcode-OP_getlocal0))
415 isRestArray[state->sp()] = truetrue;
416 break;
417 }
418
419 case OP_iflt:
420 case OP_ifle:
421 case OP_ifnlt:
422 case OP_ifnle:
423 case OP_ifgt:
424 case OP_ifge:
425 case OP_ifngt:
426 case OP_ifnge:
427 case OP_ifeq:
428 case OP_ifstricteq:
429 case OP_ifne:
430 case OP_ifstrictne:
431 case OP_iftrue:
432 case OP_iffalse:
433 case OP_jump:
434 case OP_lookupswitch:
435 case OP_throw:
436 case OP_returnvalue:
437 case OP_returnvoid:
438 endBlock();
439 break;
440 }
441 }
442
443 coder->writeOpcodeVerified(state, pc, opcode);
444 }
445
446 // This would be less painful if we had a table stating the number of operands read
447 // by most instructions.
448
449 void RestArgAnalyzer::operate(const FrameState* state, const uint8_t *pc, AbcOpcode opcode)
450 {
451 uint32_t imm30=0, imm30b=0;
452 int32_t imm8=0, imm24=0;
453 uint32_t numprops = 0;
454
455 AvmCore::readOperands(pc, imm30, imm24, imm30b, imm8);
456
457 switch (opcode) {
458 // Ignored because they are generated post-analysis when the analysis succeeds.
459 case OP_restarg:
460 case OP_restargc:
461 break;
462
463 // Handled in writeOpcodeVerified
464 case OP_getlocal:
465 case OP_getlocal0:
466 case OP_getlocal1:
467 case OP_getlocal2:
468 case OP_getlocal3:
469 break;
470
471 // Handled in getProperty
472 case OP_getproperty:
473 break;
474
475 // Op0
476 case OP_bkpt:
477 case OP_bkptline:
478 case OP_timestamp:
479 case OP_nop:
480 case OP_pushbyte:
481 case OP_pushshort:
482 case OP_pushtrue:
483 case OP_pushfalse:
484 case OP_pushnan:
485 case OP_pushnull:
486 case OP_pushundefined:
487 case OP_pushstring:
488 case OP_pushint:
489 case OP_pushuint:
490 case OP_pushdouble:
491 case OP_pushnamespace:
492 case OP_dxns:
493 case OP_label:
494 case OP_jump:
495 case OP_pop: // Does not 'read' the value
496 case OP_popscope:
497 case OP_newfunction:
498 case OP_returnvoid:
499 case OP_newactivation:
500 case OP_newcatch:
501 case OP_finddef:
502 case OP_getlex:
503 case OP_getglobalscope:
504 case OP_getscopeobject:
505 case OP_getouterscope:
506 case OP_getglobalslot:
507 case OP_debugline:
508 case OP_debugfile:
509 case OP_debug:
510 case OP_findpropglobalstrict: // Internal, poorly documented
511 case OP_findpropglobal: // Internal, poorly documented
512 break;
513
514 // Op1
515 case OP_throw:
516 case OP_iftrue:
517 case OP_iffalse:
518 case OP_convert_i:
519 case OP_convert_u:
520 case OP_convert_d:
521 case OP_convert_b:
522 case OP_convert_o:
523 case OP_convert_s:
524 case OP_coerce_b:
525 case OP_coerce_a:
526 case OP_coerce_i:
527 case OP_coerce_d:
528 case OP_coerce_s:
529 case OP_coerce_u:
530 case OP_coerce_o:
531 case OP_coerce:
532 case OP_dxnslate:
533 case OP_li8:
534 case OP_li16:
535 case OP_li32:
536 case OP_lf32:
537 case OP_lf64:
538 case OP_sxi1:
539 case OP_sxi8:
540 case OP_sxi16:
541 case OP_pushwith:
542 case OP_lookupswitch:
543 case OP_increment:
544 case OP_decrement:
545 case OP_typeof:
546 case OP_not:
547 case OP_bitnot:
548 case OP_increment_i:
549 case OP_decrement_i:
550 case OP_astype:
551 case OP_pushscope:
552 case OP_negate:
553 case OP_negate_i:
554 case OP_dup:
555 case OP_checkfilter:
556 case OP_esc_xelem:
557 case OP_esc_xattr:
558 case OP_returnvalue:
559 case OP_newclass:
560 case OP_getslot:
561 case OP_setglobalslot:
562 if (isRestArray[state->sp()])
563 fail();
564 break;
565
566 // Op2
567 case OP_add:
568 case OP_subtract:
569 case OP_multiply:
570 case OP_divide:
571 case OP_modulo:
572 case OP_lshift:
573 case OP_rshift:
574 case OP_urshift:
575 case OP_bitand:
576 case OP_bitor:
577 case OP_bitxor:
578 case OP_equals:
579 case OP_strictequals:
580 case OP_lessthan:
581 case OP_lessequals:
582 case OP_greaterthan:
583 case OP_greaterequals:
584 case OP_instanceof:
585 case OP_istype:
586 case OP_istypelate:
587 case OP_in:
588 case OP_ifnlt:
589 case OP_ifnle:
590 case OP_ifngt:
591 case OP_ifnge:
592 case OP_ifeq:
593 case OP_ifne:
594 case OP_iflt:
595 case OP_ifle:
596 case OP_ifgt:
597 case OP_ifge:
598 case OP_ifstricteq:
599 case OP_ifstrictne:
600 case OP_si8:
601 case OP_si16:
602 case OP_si32:
603 case OP_sf32:
604 case OP_sf64:
605 case OP_add_i:
606 case OP_subtract_i:
607 case OP_multiply_i:
608 case OP_astypelate:
609 case OP_swap:
610 case OP_nextname:
611 case OP_nextvalue:
612 case OP_hasnext:
613 case OP_setslot:
614 if (isRestArray[state->sp()] || isRestArray[state->sp()-1])
615 fail();
616 break;
617
618 // Locals
619 case OP_inclocal:
620 case OP_declocal:
621 case OP_inclocal_i:
622 case OP_declocal_i:
623 case OP_setlocal:
624 case OP_kill:
625 update_local:
626 if (imm30 == restVar)
627 fail();
628 break;
629 case OP_setlocal0:
630 case OP_setlocal1:
631 case OP_setlocal2:
632 case OP_setlocal3:
633 imm30 -= OP_setlocal0;
634 goto update_local;
635
636 // Locals
637 case OP_hasnext2:
638 if (imm30 == restVar || imm30b == restVar)
639 fail();
640 break;
641
642 // Workhorses for variable-number-of-operands instructions
643 checkMultiname:
644 {
645 const Multiname* m = pool->precomputedMultiname(imm30);
646 numprops += (m->isRtname() != 0) + (m->isRtns() != 0);
647 }
648 checkVariable:
649 {
650 uint32_t top = state->sp();
651 for ( uint32_t i=0 ; i < numprops ; i++ )
652 if (isRestArray[top-i])
653 fail();
654 break;
655 }
656
657 // 0 + 0/1/2 name components
658 case OP_findpropstrict:
659 case OP_findproperty:
660 numprops = 0;
661 goto checkMultiname;
662
663 // 1 + 0/1/2 name components
664 case OP_getsuper:
665 case OP_getdescendants:
666 case OP_deleteproperty:
667 numprops = 1;
668 goto checkMultiname;
669
670 // 2 + 0/1/2 name components
671 case OP_setsuper:
672 case OP_setproperty:
673 case OP_initproperty:
674 numprops = 2;
675 goto checkMultiname;
676
677 case OP_call:
678 numprops = 2 + imm30;
679 goto checkVariable;
680
681 case OP_construct:
682 case OP_constructsuper:
683 case OP_applytype:
684 numprops = 1 + imm30;
685 goto checkVariable;
686
687 case OP_callmethod:
688 case OP_callstatic:
689 numprops = 1 + imm30b;
690 goto checkVariable;
691
692 case OP_callsuper:
693 case OP_callsupervoid:
694 case OP_callproperty:
695 case OP_callproplex:
696 case OP_callpropvoid:
697 case OP_constructprop:
698 numprops = 1 + imm30b;
699 goto checkMultiname;
700
701 case OP_newobject:
702 numprops = 2 * imm30;
703 goto checkMultiname;
704
705 case OP_newarray:
706 numprops = imm30;
707 goto checkMultiname;
708
709 default:
710 AvmAssert(!"Can't happen")do { } while (0);
711 }
712 }
713#endif // VMCFG_RESTARG_OPTIMIZATION
714
715 /**
716 * (done) branches stay in code block
717 * (done) branches end on even instr boundaries
718 * (done) all local var operands stay inside [0..max_locals-1]
719 * (done) no illegal opcodes
720 * (done) cpool refs are inside [1..cpool_size-1]
721 * (done) converging paths have same stack depth
722 * (done) operand stack stays inside [0..max_stack-1]
723 * (done) locals defined before use
724 * (done) scope stack stays bounded
725 * (done) getScopeObject never exceeds [0..info->maxScopeDepth()-1]
726 * (done) global slots limits obeyed [0..var_count-1]
727 * (done) callstatic method limits obeyed [0..method_count-1]
728 * (done) cpool refs are correct type
729 * (done) make sure we don't fall off end of function
730 * (done) slot based ops are ok (slot must be legal)
731 * (done) propref ops are ok: usage on actual type compatible with ref type.
732 * dynamic lookup ops are ok (type must not have that binding & must be dynamic)
733 * dont access superclass state in ctor until super ctor called.
734 *
735 * pipeline todos:
736 * - early binding
737 * - copy propagation
738 *
739 * @param pool
740 * @param info
741 */
742 void Verifier::verify(CodeWriter *emitter)
743 {
744 SAMPLE_FRAME("[verify]", core);
745 PERFM_NVPROF("abc-bytes", code_length);
746
747 if (!info->abc_body_pos()) {
748 // no body was supplied in abc
749 toplevel->throwVerifyError(kNotImplementedError, core->toErrorString(info));
750 }
751 if (info->declaringTraits() == NULL__null) {
752 // scope hasn't been captured yet.
753 verifyFailed(kCannotVerifyUntilReferencedError);
754 }
755
756 // CodeWriter warning: Verify exceptions are thrown from here
757 // and callees, so any CodeWriters declared with function scope
758 // will not be destructed. Presently, only CodeWriter, VerifyallWriter,
759 // and ScopeWriter are declared this way, and none require cleanup.
760 // if you add a new one, or add allocations in one of these,
761 // a TRY/CATCH will be required.
762
763 #ifdef AVMPLUS_VERBOSE
764 if (verbose)
765 core->console << "\ntypecheck " << info << '\n';
766 secondTry = falsefalse;
767 #endif
768
769 // Verify in two passes. Phase 1 does type modelling and
770 // iterates to a fixed point to determine the types and nullability
771 // of each frame variable at branch targets. Phase 2 includes the
772 // emitter and ScopeWriter, and visits opcodes in linear order.
773 // Errors detected by these additional CodeWriters can be reported
774 // in phase 2. In each phase, the CodeWriter protocol is obeyed:
775 // writePrologue(), visits to explicit and implicit operations using
776 // other writeXXX() methods, then writeEpilogue().
777
778 emitPass = falsefalse;
779 // phase 1 - iterate to a fixed point
780 CodeWriter stubWriter;
781#ifdef VMCFG_RESTARG_OPTIMIZATION
782 coder = restArgAnalyzer.hookup(&stubWriter);
783#else
784 coder = &stubWriter;
785#endif
786 parseBodyHeader(); // set code_pos & code_length
787 parseExceptionHandlers(); // resolve catch block types
788 checkParams();
789 #ifdef AVMPLUS_VERBOSE
790 if (verbose) {
791 printScope("outer-scope", info->declaringScope());
792 StringBuffer buf(core);
793 printState(buf, state);
794 }
795 #endif
796 coder->writePrologue(state, code_pos, this);
797 if (code_length > 0 && code_pos[0] == OP_label) {
798 // a reachable block starts at code_pos; explicitly create it,
799 // which puts it on the worklist.
800 checkTarget(code_pos-1, code_pos);
801 } else {
802 // inital sequence of code is only reachable from procedure
803 // entry, no block will be created, so verify it explicitly
804 verifyBlock(code_pos);
805 }
806 for (FrameState* succ = worklist; succ != NULL__null; succ = worklist) {
807 worklist = succ->wl_next;
808 succ->wl_pending = falsefalse;
809 verifyBlock(loadBlockState(succ));
810 }
811 coder->writeEpilogue(state);
812
813 // phase 2 - traverse code in abc order and emit
814 mmfx_delete(state)::MMgcDestructTaggedScalarChecked(state);
815#ifdef VMCFG_RESTARG_OPTIMIZATION
816 coder = restArgAnalyzer.hookup(emitter, truetrue);
817#else
818 coder = emitter;
819#endif
820
821 // save computed ScopeTypeChain for OP_newfunction and OP_newclass
822 ScopeWriter scopeWriter(coder, info, toplevel, this);
823 coder = &scopeWriter;
824
825 #ifdef AVMPLUS_VERBOSE
826 if (verbose)
827 core->console << "\nverify " << info << '\n';
828 #endif
829
830 emitPass = truetrue;
831 this->coder = coder;
832 parseBodyHeader(); // reset code_pos & code_length
833 checkParams();
834 coder->writePrologue(state, code_pos, this);
835 const uint8_t* end_pos = code_pos;
836 // typically, first block is not in blockStates: verify it explicitly
837 if (!hasFrameState(code_pos))
838 end_pos = verifyBlock(code_pos);
839 // visit blocks in linear order (blockStates is sorted by abc address)
840 for (int i=0, n=getBlockCount(); i < n; i++) {
841 const uint8_t* start_pos = loadBlockState(blockStates->map.at(i));
842 // overlapping blocks indicates a branch to the middle of an instruction
843 if (start_pos < end_pos)
844 verifyFailed(kInvalidBranchTargetError);
845 end_pos = verifyBlock(start_pos);
846 }
847 state->abc_pc = code_pos + code_length;
848 coder->writeEpilogue(state);
849 }
850
851 const uint8_t* Verifier::loadBlockState(FrameState* blk)
852 {
853 // now load the saved state at this block
854 state->init(blk);
855 state->targetOfBackwardsBranch = blk->targetOfBackwardsBranch;
856 state->abc_pc = blk->abc_pc;
857
858#ifdef AVMPLUS_VERBOSE
859 if (verbose) {
860 StringBuffer buf(core);
861 buf << "B" << int(blk->abc_pc - code_pos) << ":";
862 printState(buf, state);
863 }
864#endif
865
866 // found the start of a new basic block
867 coder->writeBlockStart(state);
868 return blk->abc_pc;
869 }
870
871 void Verifier::checkParams()
872 {
873 const int param_count = ms->param_count();
874
875 if (ms->local_count() < param_count+1) {
876 // must have enough locals to hold all parameters including this
877 toplevel->throwVerifyError(kCorruptABCError);
878 }
879
880 // initial scope chain types
881 if (info->declaringTraits()->init != info && info->declaringScope() == NULL__null) {
882 // this can occur when an activation scope inside a class instance method
883 // contains a nested getter, setter, or method. In that case the scope
884 // is not captured when the containing function is verified. This isn't a
885 // bug because such nested functions aren't suppported by AS3. This
886 // verify error is how we don't let those constructs run.
887 verifyFailed(kNoScopeError, core->toErrorString(info));
888 }
889
890 state = mmfx_new( FrameState(ms) )new (MMgc::kUseFixedMalloc) FrameState(ms);
891
892 // initialize method param types.
893 // We already verified param_count is a legal register so
894 // don't checkLocal(i) inside the loop.
895 // MethodInfo::verify takes care of resolving param&return type
896 // names to Traits pointers, and resolving optional param default values.
897 for (int i=0; i <= param_count; i++)
898 state->setType(i, ms->paramTraits(i), i == 0);
899
900 int first_local = param_count+1;
901 if (info->needRestOrArguments()) {
902 // abcMethod_NEED_REST overrides abcMethod_NEED_ARGUMENTS when both are set
903 checkLocal(first_local); // ensure param_count+1 <= max_reg
904 state->setType(first_local, ARRAY_TYPE(core->traits.array_itraits), truetrue);
905 first_local++;
906 } else {
907 checkLocal(param_count); // ensure param_count <= max_reg
908 }
909
910 for (int i=first_local, n = ms->local_count(); i < n; i++)
911 state->setType(i, NULL__null); // void would be more precise.
912 }
913
914 // verify one superblock, return at the end. The end of the block is when
915 // we reach a terminal opcode (jump, lookupswitch, returnvalue, returnvoid,
916 // or throw), or when we fall into the beginning of another block.
917 // returns the address of the next instruction after the block end.
918 const uint8_t* Verifier::verifyBlock(const uint8_t* start_pos)
919 {
920 _nvprof("verify-block", 1);
921 CodeWriter *coder = this->coder; // Load into local var for expediency.
922 ExceptionHandlerTable* exTable = info->abc_exceptions();
923 boolbool isLoopHeader = state->targetOfBackwardsBranch;
924 state->targetOfBackwardsBranch = falsefalse;
925 const uint8_t* code_end = code_pos + code_length;
926 for (const uint8_t *pc = start_pos, *nextpc = pc; pc < code_end; pc = nextpc)
927 {
928 // should we make a new sample frame in this method?
929 // SAMPLE_CHECK();
930 PERFM_NVPROF("abc-verify", 1);
931
932 coder->writeFixExceptionsAndLabels(state, pc);
933
934 AbcOpcode opcode = (AbcOpcode) *pc;
935 if (opcodeInfo[opcode].operandCount == -1)
936 verifyFailed(kIllegalOpcodeError, core->toErrorString(info), core->toErrorString(opcode), core->toErrorString((int)(pc-code_pos)));
937
938 state->abc_pc = pc;
939
940 // test for the start of a new block
941 if (pc != start_pos && (opcode == OP_label || hasFrameState(pc))) {
942 checkTarget(pc-1, pc);
943 return pc;
944 }
945
946 int sp = state->sp();
947
948 if (pc < tryTo && pc >= tryFrom &&
949 (opcodeInfo[opcode].canThrow || (isLoopHeader && pc == start_pos))) {
950 // If this instruction can throw exceptions, treat it as an edge to
951 // each in-scope catch handler. The instruction can throw exceptions
952 // if canThrow = true, or if this is the target of a backedge, where
953 // the implicit interrupt check can throw an exception.
954 for (int i=0, n=exTable->exception_count; i < n; i++) {
955 ExceptionHandler* handler = &exTable->exceptions[i];
956 if (pc >= code_pos + handler->from && pc < code_pos + handler->to) {
957 int saveStackDepth = state->stackDepth;
958 int saveScopeDepth = state->scopeDepth;
959 FrameValue stackEntryZero = saveStackDepth > 0 ? state->stackValue(0) : state->value(0);
960 state->stackDepth = 0;
961 state->scopeDepth = 0;
962
963 // add edge from try statement to catch block
964 const uint8_t* target = code_pos + handler->target;
965 // The thrown value is received as an atom but we will coerce it to
966 // the expected type before handing control to the catch block.
967 state->push(handler->traits);
968 checkTarget(pc, target);
969 state->pop();
970
971 state->stackDepth = saveStackDepth;
972 state->scopeDepth = saveScopeDepth;
973 if (saveStackDepth > 0)
974 state->stackValue(0) = stackEntryZero;
975
976 // Note that an exception may be caught in this method.
977 handlerIsReachable = truetrue;
978 }
979 }
980 }
981
982 uint32_t imm30=0, imm30b=0;
983 int32_t imm8=0, imm24=0;
984 AvmCore::readOperands(nextpc, imm30, imm24, imm30b, imm8);
985
986 // make sure U30 operands are within bounds,
987 // except for OP_pushshort, whose operand is sign extended from 16 bits
988 if (opcode != OP_pushshort && ((imm30|imm30b) & 0xc0000000))
989 verifyFailed(kCorruptABCError);
990 if (nextpc > code_end)
991 verifyFailed(kLastInstExceedsCodeSizeError);
992
993 #ifdef AVMPLUS_VERBOSE
994 if (verbose)
995 printOpcode(pc, code_end);
996 #endif
997
998 _nvprof("verify-instr", 1);
999 switch (opcode)
1000 {
1001 case OP_iflt:
1002 case OP_ifle:
1003 case OP_ifnlt:
1004 case OP_ifnle:
1005 case OP_ifgt:
1006 case OP_ifge:
1007 case OP_ifngt:
1008 case OP_ifnge:
1009 case OP_ifeq:
1010 case OP_ifstricteq:
1011 case OP_ifne:
1012 case OP_ifstrictne:
1013 checkStack(2,0);
1014 coder->writeOp1(state, pc, opcode, imm24);
1015 state->pop(2);
1016 checkTarget(pc, nextpc+imm24);
1017 break;
1018
1019 case OP_iftrue:
1020 case OP_iffalse:
1021 checkStack(1,0);
1022 emitCoerce(BOOLEAN_TYPE(core->traits.boolean_itraits), sp);
1023 coder->writeOp1(state, pc, opcode, imm24);
1024 state->pop();
1025 checkTarget(pc, nextpc+imm24);
1026 break;
1027
1028 case OP_jump:
1029 //checkStack(0,0)
1030 coder->writeOp1(state, pc, opcode, imm24);
1031 checkTarget(pc, nextpc+imm24); // target block;
1032 coder->writeOpcodeVerified(state, pc, opcode);
1033 return nextpc;
1034
1035 case OP_lookupswitch:
1036 {
1037 checkStack(1,0);
1038 peekType(INT_TYPE(core->traits.int_itraits));
1039 coder->write(state, pc, opcode);
1040 state->pop();
1041 checkTarget(pc, pc+imm24);
1042 uint32_t case_count = 1 + imm30b;
1043 // case_count*3 can't overflow a U32...
1044 uint32_t const case_skip = case_count * 3;
1045 // ...but adding it to nextpc could wrap around, so check.
1046 if (uintptr_t(nextpc) > uintptr_t(-1) - case_skip ||
1047 nextpc + case_skip > code_end)
1048 verifyFailed(kLastInstExceedsCodeSizeError);
1049 for (uint32_t i=0; i < case_count; i++)
1050 {
1051 int off = AvmCore::readS24(nextpc);
1052 checkTarget(pc, pc+off);
1053 nextpc += 3;
1054 }
1055 coder->writeOpcodeVerified(state, pc, opcode);
1056 return nextpc;
1057 }
1058
1059 case OP_throw:
1060 checkStack(1,0);
1061 coder->write(state, pc, opcode);
1062 state->pop();
1063 coder->writeOpcodeVerified(state, pc, opcode);
1064 return nextpc;
1065
1066 case OP_returnvalue:
1067 checkStack(1,0);
1068 emitCoerce(ms->returnTraits(), sp);
1069 coder->write(state, pc, opcode);
1070 state->pop();
1071 coder->writeOpcodeVerified(state, pc, opcode);
1072 return nextpc;
1073
1074 case OP_returnvoid:
1075 //checkStack(0,0)
1076 coder->write(state, pc, opcode);
1077 coder->writeOpcodeVerified(state, pc, opcode);
1078 return nextpc;
1079
1080 case OP_pushnull:
1081 checkStack(0,1);
1082 coder->write(state, pc, opcode, NULL_TYPE(core->traits.null_itraits));
1083 state->push(NULL_TYPE(core->traits.null_itraits));
1084 break;
1085
1086 case OP_pushundefined:
1087 checkStack(0,1);
1088 coder->write(state, pc, opcode, VOID_TYPE(core->traits.void_itraits));
1089 state->push(VOID_TYPE(core->traits.void_itraits));
1090 break;
1091
1092 case OP_pushtrue:
1093 checkStack(0,1);
1094 coder->write(state, pc, opcode, BOOLEAN_TYPE(core->traits.boolean_itraits));
1095 state->push(BOOLEAN_TYPE(core->traits.boolean_itraits), truetrue);
1096 break;
1097
1098 case OP_pushfalse:
1099 checkStack(0,1);
1100 coder->write(state, pc, opcode, BOOLEAN_TYPE(core->traits.boolean_itraits));
1101 state->push(BOOLEAN_TYPE(core->traits.boolean_itraits), truetrue);
1102 break;
1103
1104 case OP_pushnan:
1105 checkStack(0,1);
1106 coder->write(state, pc, opcode, NUMBER_TYPE(core->traits.number_itraits));
1107 state->push(NUMBER_TYPE(core->traits.number_itraits), truetrue);
1108 break;
1109
1110 case OP_pushshort:
1111 checkStack(0,1);
1112 coder->write(state, pc, opcode, INT_TYPE(core->traits.int_itraits));
1113 state->push(INT_TYPE(core->traits.int_itraits), truetrue);
1114 break;
1115
1116 case OP_pushbyte:
1117 checkStack(0,1);
1118 coder->write(state, pc, opcode, INT_TYPE(core->traits.int_itraits));
1119 state->push(INT_TYPE(core->traits.int_itraits), truetrue);
1120 break;
1121
1122 case OP_debugfile:
1123 //checkStack(0,0)
1124 // fixme: bugzilla 552988: remove ifdef.
1125 #if defined(DEBUGGER) || defined(VMCFG_VTUNE)
1126 checkStringOperand(imm30);
1127 #endif
1128 coder->write(state, pc, opcode);
1129 break;
1130
1131 case OP_dxns:
1132 //checkStack(0,0)
1133 if (!info->setsDxns())
1134 verifyFailed(kIllegalSetDxns, core->toErrorString(info));
1135 checkStringOperand(imm30);
1136 coder->write(state, pc, opcode);
1137 break;
1138
1139 case OP_dxnslate:
1140 checkStack(1,0);
1141 if (!info->setsDxns())
1142 verifyFailed(kIllegalSetDxns, core->toErrorString(info));
1143 // codgen will call intern on the input atom.
1144 coder->write(state, pc, opcode);
1145 state->pop();
1146 break;
1147
1148 case OP_pushstring:
1149 checkStack(0,1);
1150 checkStringOperand(imm30);
1151 coder->write(state, pc, opcode, STRING_TYPE(core->traits.string_itraits));
1152 state->push(STRING_TYPE(core->traits.string_itraits), pool->getString(imm30) != NULL__null);
1153 break;
1154
1155 case OP_pushint:
1156 checkStack(0,1);
1157 if (imm30 == 0 || imm30 >= pool->constantIntCount)
1158 verifyFailed(kCpoolIndexRangeError, core->toErrorString(imm30), core->toErrorString(pool->constantIntCount));
1159 coder->write(state, pc, opcode, INT_TYPE(core->traits.int_itraits));
1160 state->push(INT_TYPE(core->traits.int_itraits),truetrue);
1161 break;
1162
1163 case OP_pushuint:
1164 checkStack(0,1);
1165 if (imm30 == 0 || imm30 >= pool->constantUIntCount)
1166 verifyFailed(kCpoolIndexRangeError, core->toErrorString(imm30), core->toErrorString(pool->constantUIntCount));
1167 coder->write(state, pc, opcode, UINT_TYPE(core->traits.uint_itraits));
1168 state->push(UINT_TYPE(core->traits.uint_itraits),truetrue);
1169 break;
1170
1171 case OP_pushdouble:
1172 checkStack(0,1);
1173 if (imm30 == 0 || imm30 >= pool->constantDoubleCount)
1174 verifyFailed(kCpoolIndexRangeError, core->toErrorString(imm30), core->toErrorString(pool->constantDoubleCount));
1175 coder->write(state, pc, opcode, NUMBER_TYPE(core->traits.number_itraits));
1176 state->push(NUMBER_TYPE(core->traits.number_itraits), truetrue);
1177 break;
1178
1179 case OP_pushnamespace:
1180 checkStack(0,1);
1181 if (imm30 == 0 || imm30 >= pool->constantNsCount)
1182 verifyFailed(kCpoolIndexRangeError, core->toErrorString(imm30), core->toErrorString(pool->constantNsCount));
1183 coder->write(state, pc, opcode, NAMESPACE_TYPE(core->traits.namespace_itraits));
1184 state->push(NAMESPACE_TYPE(core->traits.namespace_itraits), pool->cpool_ns[imm30] != NULL__null);
1185 break;
1186
1187 case OP_setlocal:
1188 {
1189 checkStack(1,0);
1190 checkLocal(imm30);
1191 coder->write(state, pc, opcode);
1192 FrameValue &v = state->stackTop();
1193 state->setType(imm30, v.traits, v.notNull);
1194 state->pop();
1195 break;
1196 }
1197
1198 case OP_setlocal0:
1199 case OP_setlocal1:
1200 case OP_setlocal2:
1201 case OP_setlocal3:
1202 {
1203 checkStack(1,0);
1204 int index = opcode-OP_setlocal0;
1205 checkLocal(index);
1206 coder->write(state, pc, opcode);
1207 FrameValue &v = state->stackTop();
1208 state->setType(index, v.traits, v.notNull);
1209 state->pop();
1210 break;
1211 }
1212 case OP_getlocal:
1213 {
1214 checkStack(0,1);
1215 FrameValue& v = checkLocal(imm30);
1216 coder->write(state, pc, opcode);
1217 state->push(v);
1218 break;
1219 }
1220 case OP_getlocal0:
1221 case OP_getlocal1:
1222 case OP_getlocal2:
1223 case OP_getlocal3:
1224 {
1225 checkStack(0,1);
1226 FrameValue& v = checkLocal(opcode-OP_getlocal0);
1227 coder->write(state, pc, opcode);
1228 state->push(v);
1229 break;
1230 }
1231 case OP_kill:
1232 {
1233 //checkStack(0,0)
1234 checkLocal(imm30);
1235 coder->write(state, pc, opcode, NULL__null);
1236 state->setType(imm30, NULL__null, falsefalse);
1237 break;
1238 }
1239
1240 case OP_inclocal:
1241 case OP_declocal:
1242 //checkStack(0,0);
1243 checkLocal(imm30);
1244 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), imm30);
1245 coder->write(state, pc, opcode);
1246 break;
1247
1248 case OP_inclocal_i:
1249 case OP_declocal_i:
1250 //checkStack(0,0);
1251 checkLocal(imm30);
1252 emitCoerce(INT_TYPE(core->traits.int_itraits), imm30);
1253 coder->write(state, pc, opcode);
1254 break;
1255
1256 case OP_newfunction:
1257 {
1258 checkStack(0,1);
1259 checkMethodInfo(imm30);
1260 Traits* ftraits = core->traits.function_itraits;
1261 coder->writeOp1(state, pc, opcode, imm30, ftraits);
1262 state->push(ftraits, truetrue);
1263 break;
1264 }
1265
1266 case OP_getlex:
1267 {
1268 if (state->scopeDepth + info->declaringScope()->size == 0)
1269 verifyFailed(kFindVarWithNoScopeError);
1270 Multiname multiname;
1271 checkConstantMultiname(imm30, multiname);
1272 checkStackMulti(0, 1, &multiname);
1273 if (multiname.isRuntime())
1274 verifyFailed(kIllegalOpMultinameError, core->toErrorString(opcode), core->toErrorString(&multiname));
1275 emitFindProperty(OP_findpropstrict, multiname, imm30, pc);
1276 emitGetProperty(multiname, 1, imm30, pc);
1277 break;
1278 }
1279
1280 case OP_findpropstrict:
1281 case OP_findproperty:
1282 {
1283 if (state->scopeDepth + info->declaringScope()->size == 0)
1284 verifyFailed(kFindVarWithNoScopeError);
1285 Multiname multiname;
1286 checkConstantMultiname(imm30, multiname);
1287 checkStackMulti(0, 1, &multiname);
1288 emitFindProperty(opcode, multiname, imm30, pc);
1289 break;
1290 }
1291
1292 case OP_newclass:
1293 {
1294 checkStack(1, 1);
1295 // imm30 is the class_id of the class object to create.
1296 Traits* ctraits = checkClassInfo(imm30);
1297 emitCoerce(CLASS_TYPE(core->traits.class_itraits), state->sp());
1298 coder->writeOp1(state, pc, opcode, imm30, ctraits);
1299 state->pop_push(1, ctraits, truetrue);
1300 break;
1301 }
1302
1303 case OP_finddef:
1304 {
1305 // must be a CONSTANT_Multiname.
1306 Multiname multiname;
1307 checkConstantMultiname(imm30, multiname);
1308 checkStackMulti(0, 1, &multiname);
1309 if (!multiname.isBinding())
1310 {
1311 // error, def name must be CT constant, regular name
1312 verifyFailed(kIllegalOpMultinameError, core->toErrorString(opcode), core->toErrorString(&multiname));
1313 }
1314 MethodInfo* script = core->domainMgr()->findScriptInPoolByMultiname(pool, multiname);
1315 Traits* resultType;
1316 if (script != (MethodInfo*)BIND_NONE && script != (MethodInfo*)BIND_AMBIGUOUS) {
1317 // found a single matching traits
1318 resultType = script->declaringTraits();
1319 } else {
1320 // no traits, or ambiguous reference. use Object, anticipating
1321 // a runtime exception
1322 resultType = OBJECT_TYPE(core->traits.object_itraits);
1323 }
1324 coder->writeOp1(state, pc, opcode, imm30, resultType);
1325 state->push(resultType, truetrue);
1326 break;
1327 }
1328
1329 case OP_setproperty:
1330 case OP_initproperty:
1331 {
1332 // stack in: object [ns] [name] value
1333 Multiname multiname;
1334 checkConstantMultiname(imm30, multiname); // CONSTANT_Multiname
1335 checkStackMulti(2, 0, &multiname);
1336
1337 uint32_t n=2;
1338 checkPropertyMultiname(n, multiname);
1339
1340 Traitsp declarer = NULL__null;
1341 FrameValue& obj = state->peek(n);
1342 Binding b = (opcode == OP_initproperty) ?
1343 toplevel->getBindingAndDeclarer(obj.traits, multiname, declarer) :
1344 toplevel->getBinding(obj.traits, &multiname);
1345 Traits* propTraits = readBinding(obj.traits, b);
1346
1347 emitCheckNull(sp-(n-1));
1348
1349 if (AvmCore::isSlotBinding(b) &&
1350 // it's a var, or a const being set from the init function
1351 (!AvmCore::isConstBinding(b) ||
1352 (opcode == OP_initproperty && declarer->init == info)))
1353 {
1354 emitCoerce(propTraits, state->sp());
1355 coder->writeOp2(state, pc, OP_setslot, (uint32_t)AvmCore::bindingToSlotId(b), sp-(n-1), propTraits);
1356 state->pop(n);
1357 break;
1358 }
1359 // else: setting const from illegal context, fall through
1360
1361 // If it's an accessor that we can early bind, do so.
1362 // Note that this cannot be done on String or Namespace,
1363 // since those are represented by non-ScriptObjects
1364 if (AvmCore::hasSetterBinding(b))
1365 {
1366 // invoke the setter
1367 int disp_id = AvmCore::bindingToSetterId(b);
1368 const TraitsBindingsp objtd = obj.traits->getTraitsBindings();
1369 MethodInfo *f = objtd->getMethod(disp_id);
1370 AvmAssert(f != NULL)do { } while (0);
1371 MethodSignaturep fms = f->getMethodSignature();
1372 emitCoerceArgs(f, 1);
1373 Traits* propType = fms->returnTraits();
1374 coder->writeOp2(state, pc, opcode, imm30, n, propType);
1375 state->pop(n);
1376 break;
1377 }
1378
1379 if( obj.traits == VECTORINT_TYPE(core->traits.vectorint_itraits) || obj.traits == VECTORUINT_TYPE(core->traits.vectoruint_itraits) ||
1380 obj.traits == VECTORDOUBLE_TYPE(core->traits.vectordouble_itraits) )
1381 {
1382 boolbool attr = multiname.isAttr();
1383 Traits* indexType = state->value(state->sp()-1).traits;
1384
1385 // NOTE a dynamic name should have the same version as the current pool
1386 boolbool maybeIntegerIndex = !attr && multiname.isRtname() && multiname.containsAnyPublicNamespace();
1387 if( maybeIntegerIndex && (indexType == UINT_TYPE(core->traits.uint_itraits) || indexType == INT_TYPE(core->traits.int_itraits) || indexType == NUMBER_TYPE(core->traits.number_itraits)) )
1388 {
1389 if(obj.traits == VECTORINT_TYPE(core->traits.vectorint_itraits))
1390 emitCoerce(INT_TYPE(core->traits.int_itraits), state->sp());
1391 else if(obj.traits == VECTORUINT_TYPE(core->traits.vectoruint_itraits))
1392 emitCoerce(UINT_TYPE(core->traits.uint_itraits), state->sp());
1393 else if(obj.traits == VECTORDOUBLE_TYPE(core->traits.vectordouble_itraits))
1394 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), state->sp());
1395 }
1396 }
1397
1398 // Default: do setproperty or initproperty at runtime.
1399
1400 coder->writeOp2(state, pc, opcode, imm30, n, propTraits);
1401 state->pop(n);
1402 break;
1403 }
1404
1405 case OP_getproperty:
1406 {
1407 // stack in: object [ns [name]]
1408 // stack out: value
1409 Multiname multiname;
1410 checkConstantMultiname(imm30, multiname); // CONSTANT_Multiname
1411 checkStackMulti(1, 1, &multiname);
1412
1413 uint32_t n=1;
1414 checkPropertyMultiname(n, multiname);
1415
1416#ifdef VMCFG_RESTARG_OPTIMIZATION
1417 boolbool emitOptimizedRestArg = restArgAnalyzer.optimize;
1418
1419 if (emitOptimizedRestArg)
1420 emitOptimizedRestArg = restArgAnalyzer.getProperty(state, multiname, n);
1421
1422 if (emitPass && emitOptimizedRestArg)
1423 {
1424 FrameValue& obj = state->peek(n);
1425 if (multiname.isRtname())
1426 {
1427 // restarg assumes the property name is an atom, so we must coerce it to an atom on input
1428 emitCoerce(NULL__null, state->sp());
1429 coder->writeOp1(state, pc, OP_restarg, imm30, NULL__null);
1430 state->pop_push(n, NULL__null);
1431 }
1432 else if (multiname.getName() == core->klength)
1433 {
1434 Binding b = toplevel->getBinding(obj.traits, &multiname);
1435 Traits* propType = readBinding(obj.traits, b);
1436 coder->write(state, pc, OP_restargc, propType);
1437 state->pop_push(n, UINT_TYPE(core->traits.uint_itraits));
1438 // restargc produces an uint, so we must coerce to the target type on return
1439 emitCoerce(propType, sp);
1440 }
1441 else {
1442 AvmAssert(!"Can't happen")do { } while (0);
1443 }
1444
1445 }
1446 else {
1447 emitGetProperty(multiname, n, imm30, pc);
1448 }
1449#else
1450 emitGetProperty(multiname, n, imm30, pc);
1451#endif
1452 break;
1453 }
1454
1455 case OP_getdescendants:
1456 {
1457 // stack in: object [ns] [name]
1458 // stack out: value
1459 Multiname multiname;
1460 checkConstantMultiname(imm30, multiname);
1461 checkStackMulti(1, 1, &multiname);
1462
1463 uint32_t n=1;
1464 checkPropertyMultiname(n, multiname);
1465 emitCheckNull(sp-(n-1));
1466 coder->write(state, pc, opcode);
1467 state->pop_push(n, NULL__null);
1468 break;
1469 }
1470
1471 case OP_checkfilter:
1472 checkStack(1, 1);
1473 emitCheckNull(sp);
1474 coder->write(state, pc, opcode);
1475 break;
1476
1477 case OP_deleteproperty:
1478 {
1479 Multiname multiname;
1480 checkConstantMultiname(imm30, multiname);
1481 checkStackMulti(1, 1, &multiname);
1482 uint32_t n=1;
1483 checkPropertyMultiname(n, multiname);
1484 emitCheckNull(sp-(n-1));
1485 coder->write(state, pc, opcode);
1486 state->pop_push(n, BOOLEAN_TYPE(core->traits.boolean_itraits));
1487 break;
1488 }
1489
1490 case OP_astype:
1491 {
1492 checkStack(1, 1);
1493 // resolve operand into a traits, and push that type.
1494 Traits *t = checkTypeName(imm30); // CONSTANT_Multiname
1495 int index = sp;
1496 Traits* rhs = state->value(index).traits;
1497 if (!Traits::canAssign(t, rhs))
1498 {
1499 Traits* resultType = t;
1500 // result is typed value or null, so if type can't hold null,
1501 // then result type is Object.
1502 if (t && t->isMachineType())
1503 resultType = OBJECT_TYPE(core->traits.object_itraits);
1504 coder->write(state, pc, opcode, t);
1505 state->pop_push(1, resultType);
1506 }
1507 break;
1508 }
1509
1510 case OP_astypelate:
1511 {
1512 checkStack(2,1);
1513 FrameValue& classValue = state->peek(1); // rhs - class
1514 Traits* ct = classValue.traits;
1515 Traits* t = NULL__null;
1516 if (ct && (t=ct->itraits) != 0)
1517 if (t->isMachineType())
1518 t = OBJECT_TYPE(core->traits.object_itraits);
1519 coder->write(state, pc, opcode, t);
1520 state->pop_push(2, t);
1521 break;
1522 }
1523
1524 case OP_coerce:
1525 {
1526 checkStack(1,1);
1527 FrameValue &v = state->value(sp);
1528 Traits *type = checkTypeName(imm30);
1529 coder->write(state, pc, opcode, type);
1530 state->setType(sp, type, v.notNull);
1531 break;
1532 }
1533 case OP_convert_b:
1534 case OP_coerce_b:
1535 {
1536 checkStack(1,1);
1537 FrameValue &v = state->value(sp);
1538 Traits *type = BOOLEAN_TYPE(core->traits.boolean_itraits);
1539 coder->write(state, pc, opcode, type);
1540 state->setType(sp, type, v.notNull);
1541 break;
1542 }
1543 case OP_coerce_o:
1544 {
1545 checkStack(1,1);
1546 FrameValue &v = state->value(sp);
1547 Traits *type = OBJECT_TYPE(core->traits.object_itraits);
1548 coder->write(state, pc, opcode, type);
1549 state->setType(sp, type, v.notNull);
1550 break;
1551 }
1552 case OP_coerce_a:
1553 {
1554 checkStack(1,1);
1555 FrameValue &v = state->value(sp);
1556 Traits *type = NULL__null;
1557 coder->write(state, pc, opcode, type);
1558 state->setType(sp, type, v.notNull);
1559 break;
1560 }
1561 case OP_convert_i:
1562 case OP_coerce_i:
1563 {
1564 checkStack(1,1);
1565 FrameValue &v = state->value(sp);
1566 Traits *type = INT_TYPE(core->traits.int_itraits);
1567 coder->write(state, pc, opcode, type);
1568 state->setType(sp, type, v.notNull);
1569 break;
1570 }
1571 case OP_convert_u:
1572 case OP_coerce_u:
1573 {
1574 checkStack(1,1);
1575 FrameValue &v = state->value(sp);
1576 Traits *type = UINT_TYPE(core->traits.uint_itraits);
1577 coder->write(state, pc, opcode, type);
1578 state->setType(sp, type, v.notNull);
1579 break;
1580 }
1581 case OP_convert_d:
1582 case OP_coerce_d:
1583 {
1584 checkStack(1,1);
1585 FrameValue &v = state->value(sp);
1586 Traits *type = NUMBER_TYPE(core->traits.number_itraits);
1587 coder->write(state, pc, opcode, type);
1588 state->setType(sp, type, v.notNull);
1589 break;
1590 }
1591 case OP_coerce_s:
1592 {
1593 checkStack(1,1);
1594 FrameValue &v = state->value(sp);
1595 Traits *type = STRING_TYPE(core->traits.string_itraits);
1596 coder->write(state, pc, opcode, type);
1597 state->setType(sp, type, v.notNull);
1598 break;
1599 }
1600 case OP_istype:
1601 {
1602 checkStack(1,1);
1603 // resolve operand into a traits, and test if value is that type
1604 Traits* t = checkTypeName(imm30); // CONSTANT_Multiname
1605 coder->write(state, pc, opcode, t);
1606 state->pop(1);
1607 state->push(BOOLEAN_TYPE(core->traits.boolean_itraits));
1608 break;
1609 }
1610 case OP_istypelate:
1611 checkStack(2,1);
1612 coder->write(state, pc, opcode);
1613 // TODO if the only common base type of lhs,rhs is Object, then result is always false
1614 state->pop_push(2, BOOLEAN_TYPE(core->traits.boolean_itraits));
1615 break;
1616
1617 case OP_convert_o:
1618 checkStack(1,1);
1619 // ISSUE should result be Object, laundering the type?
1620 // ToObject throws an exception on null and undefined, so after this runs we
1621 // know the value is safe to dereference.
1622 emitCheckNull(sp);
1623 coder->write(state, pc, opcode);
1624 break;
1625
1626 case OP_convert_s:
1627 case OP_esc_xelem:
1628 case OP_esc_xattr:
1629 checkStack(1,1);
1630 // this is the ECMA ToString and ToXMLString operators, so the result must not be null
1631 // (ToXMLString is split into two variants - escaping elements and attributes)
1632 coder->write(state, pc, opcode);
1633 state->pop_push(1, STRING_TYPE(core->traits.string_itraits), truetrue);
1634 break;
1635
1636 case OP_callstatic:
1637 {
1638 // Ensure that the method is eligible for callstatic.
1639 // Note: This fails when called by verifyEarly(), since the
1640 // data structures being checked have not been initialized.
1641 // Need to either rearrange the initialization sequence or
1642 // mark this verify pass as "needs late retry."
1643 if ( imm30 >= pool->methodCount() || ! abc_env->getMethod(imm30) )
1644 verifyFailed(kCorruptABCError);
1645
1646 MethodInfo* m = checkMethodInfo(imm30);
1647 const uint32_t argc = imm30b;
1648 checkStack(argc+1, 1);
1649
1650 MethodSignaturep mms = m->getMethodSignature();
1651 if (!mms->paramTraits(0))
1652 {
1653 verifyFailed(kDanglingFunctionError, core->toErrorString(m), core->toErrorString(info));
1654 }
1655
1656 emitCoerceArgs(m, argc);
1657
1658 Traits *resultType = mms->returnTraits();
1659 emitCheckNull(sp-argc);
1660 coder->writeOp2(state, pc, OP_callstatic, (uint32_t)m->method_id(), argc, resultType);
1661 state->pop_push(argc+1, resultType);
1662 break;
1663 }
1664
1665 case OP_call:
1666 {
1667 const uint32_t argc = imm30;
1668 checkStack(argc+2, 1);
1669 // don't need null check, AvmCore::call() uses toFunction() for null check.
1670
1671 /*
1672 TODO optimizations
1673 - if this is a class closure for a non-native type, call == coerce
1674 - if this is a function closure, try early binding using the traits->call sig
1675 - optimize simple cases of casts to builtin types
1676 */
1677
1678 coder->writeOp1(state, pc, opcode, argc);
1679 state->pop_push(argc+2, NULL__null);
1680 break;
1681 }
1682
1683 case OP_construct:
1684 {
1685 const uint32_t argc = imm30;
1686 checkStack(argc+1, 1);
1687
1688 // don't need null check, AvmCore::construct() uses toFunction() for null check.
1689 Traits* ctraits = state->peek(argc+1).traits;
1690 Traits* itraits = ctraits ? (Traits*)(ctraits->itraits) : NULL__null;
1691 coder->writeOp1(state, pc, opcode, argc);
1692 state->pop_push(argc+1, itraits, truetrue);
1693 break;
1694 }
1695
1696 case OP_callmethod:
1697 {
1698 /*
1699 OP_callmethod will always throw a verify error. that's on purpose, it's a
1700 last minute change before we shipped FP9 and was necessary when we added methods to class Object.
1701
1702 since then we realized that OP_callmethod need only have failed when used outside
1703 of the builtin abc, but it's a moot point now. We dont have to worry about it.
1704
1705 code has since been simplified but existing failure modes preserved.
1706 */
1707 const uint32_t argc = imm30b;
1708 checkStack(argc+1,1);
1709
1710 const int disp_id = imm30-1;
1711 if (disp_id >= 0)
1712 {
1713 FrameValue& obj = state->peek(argc+1);
1714 if( !obj.traits )
1715 verifyFailed(kCorruptABCError);
1716 else
1717 verifyFailed(kIllegalEarlyBindingError, core->toErrorString(obj.traits));
1718 }
1719 else
1720 {
1721 verifyFailed(kZeroDispIdError);
1722 }
1723 break;
1724 }
1725
1726 case OP_callproperty:
1727 case OP_callproplex:
1728 case OP_callpropvoid:
1729 {
1730 // stack in: obj [ns [name]] args
1731 // stack out: result
1732 const uint32_t argc = imm30b;
1733 Multiname multiname;
1734 checkConstantMultiname(imm30, multiname);
1735 checkStackMulti(argc+1, 1, &multiname);
1736 checkCallMultiname(opcode, &multiname);
1737
1738 uint32_t n = argc+1; // index of receiver
1739 checkPropertyMultiname(n, multiname);
1740 emitCallproperty(opcode, sp, multiname, imm30, imm30b, pc);
1741 break;
1742 }
1743
1744 case OP_constructprop:
1745 {
1746 // stack in: obj [ns [name]] args
1747 const uint32_t argc = imm30b;
1748 Multiname multiname;
1749 checkConstantMultiname(imm30, multiname);
1750 checkStackMulti(argc+1, 1, &multiname);
1751 checkCallMultiname(opcode, &multiname);
1752
1753 uint32_t n = argc+1; // index of receiver
1754 checkPropertyMultiname(n, multiname);
1755
1756
1757 FrameValue& obj = state->peek(n); // make sure object is there
1758 Binding b = toplevel->getBinding(obj.traits, &multiname);
1759 Traits* ctraits = readBinding(obj.traits, b);
1760 emitCheckNull(sp-(n-1));
1761 coder->writeOp2(state, pc, opcode, imm30, argc, ctraits);
1762
1763 Traits* itraits = ctraits ? (Traits*)(ctraits->itraits) : NULL__null;
1764 state->pop_push(n, itraits, itraits==NULL__null?falsefalse:truetrue);
1765 break;
1766 }
1767
1768 case OP_applytype:
1769 {
1770 // in: factory arg1..N
1771 // out: type
1772 const uint32_t argc = imm30;
1773 checkStack(argc+1, 1);
1774 coder->write(state, pc, opcode);
1775 state->pop_push(argc+1, NULL__null, truetrue);
1776 break;
1777 }
1778
1779 case OP_callsuper:
1780 case OP_callsupervoid:
1781 {
1782 // stack in: obj [ns [name]] args
1783 const uint32_t argc = imm30b;
1784 Multiname multiname;
1785 checkConstantMultiname(imm30, multiname);
1786 checkStackMulti(argc+1, 1, &multiname);
1787
1788 if (multiname.isAttr())
1789 verifyFailed(kIllegalOpMultinameError, core->toErrorString(&multiname));
1790
1791 uint32_t n = argc+1; // index of receiver
1792 checkPropertyMultiname(n, multiname);
1793
1794 Traits* base = emitCoerceSuper(sp-(n-1));
1795 const TraitsBindingsp basetd = base->getTraitsBindings();
1796
1797 Binding b = toplevel->getBinding(base, &multiname);
1798
1799 Traits *resultType = NULL__null;
1800 if (AvmCore::isMethodBinding(b))
1801 {
1802 int disp_id = AvmCore::bindingToMethodId(b);
1803 MethodInfo* m = basetd->getMethod(disp_id);
1804 if( !m ) verifyFailed(kCorruptABCError);
1805 MethodSignaturep mms = m->getMethodSignature();
1806 resultType = mms->returnTraits();
1807 }
1808
1809 emitCheckNull(sp-(n-1));
1810 coder->writeOp2(state, pc, opcode, imm30, argc, base);
1811 state->pop_push(n, resultType);
1812
1813 if (opcode == OP_callsupervoid)
1814 state->pop();
1815
1816 break;
1817 }
1818
1819 case OP_getsuper:
1820 {
1821 // stack in: obj [ns [name]]
1822 // stack out: value
1823 Multiname multiname;
1824 checkConstantMultiname(imm30, multiname);
1825 checkStackMulti(1, 1, &multiname);
1826 uint32_t n=1;
1827 checkPropertyMultiname(n, multiname);
1828
1829 if (multiname.isAttr())
1830 verifyFailed(kIllegalOpMultinameError, core->toErrorString(&multiname));
1831
1832 Traits* base = emitCoerceSuper(sp-(n-1));
1833 Binding b = toplevel->getBinding(base, &multiname);
1834 Traits* propType = readBinding(base, b);
1835 emitCheckNull(sp-(n-1));
1836 coder->writeOp2(state, pc, opcode, imm30, n, base);
1837
1838 if (AvmCore::hasGetterBinding(b))
1839 {
1840 int disp_id = AvmCore::bindingToGetterId(b);
1841 const TraitsBindingsp basetd = base->getTraitsBindings();
1842 MethodInfo *f = basetd->getMethod(disp_id);
1843 AvmAssert(f != NULL)do { } while (0);
1844 MethodSignaturep fms = f->getMethodSignature();
1845 Traits* resultType = fms->returnTraits();
1846 state->pop_push(n, resultType);
1847 }
1848 else
1849 {
1850 state->pop_push(n, propType);
1851 }
1852 break;
1853 }
1854
1855 case OP_setsuper:
1856 {
1857 // stack in: obj [ns [name]] value
1858 Multiname multiname;
1859 checkConstantMultiname(imm30, multiname);
1860 checkStackMulti(2, 0, &multiname);
1861 uint32_t n=2;
1862 checkPropertyMultiname(n, multiname);
1863
1864 if (multiname.isAttr())
1865 verifyFailed(kIllegalOpMultinameError, core->toErrorString(&multiname));
1866
1867 Traits* base = emitCoerceSuper(sp-(n-1));
1868 emitCheckNull(sp-(n-1));
1869 coder->writeOp2(state, pc, opcode, imm30, n, base);
1870 state->pop(n);
1871 break;
1872 }
1873
1874 case OP_constructsuper:
1875 {
1876 // stack in: obj, args ...
1877 const uint32_t argc = imm30;
1878 checkStack(argc+1, 0);
1879
1880 int32_t ptrIndex = sp-argc;
1881 Traits* baseTraits = emitCoerceSuper(ptrIndex); // check receiver
1882
1883 MethodInfo *f = baseTraits->init;
1884 AvmAssert(f != NULL)do { } while (0);
1885
1886 emitCoerceArgs(f, argc);
1887 emitCheckNull(sp-argc);
1888 coder->writeOp2(state, pc, opcode, 0, argc, baseTraits);
1889 state->pop(argc+1);
1890 break;
1891 }
1892
1893 case OP_newobject:
1894 {
1895 uint32_t argc = imm30;
1896 checkStack(2*argc, 1);
1897 int n=0;
1898 while (argc-- > 0)
1899 {
1900 n += 2;
1901 peekType(STRING_TYPE(core->traits.string_itraits), n); // name; will call intern on it
1902 }
1903 coder->write(state, pc, opcode);
1904 state->pop_push(n, OBJECT_TYPE(core->traits.object_itraits), truetrue);
1905 break;
1906 }
1907
1908 case OP_newarray:
1909 checkStack(imm30, 1);
1910 coder->write(state, pc, opcode);
1911 state->pop_push(imm30, ARRAY_TYPE(core->traits.array_itraits), truetrue);
1912 break;
1913
1914 case OP_pushscope:
1915 {
1916 checkStack(1,0);
1917 if (state->scopeDepth + 1 > ms->max_scope())
1918 verifyFailed(kScopeStackOverflowError);
1919
1920 Traits* scopeTraits = state->peek().traits;
1921 const ScopeTypeChain* scope = info->declaringScope();
1922 if (scope->fullsize > (scope->size+state->scopeDepth))
1923 {
1924 // extra constraints on type of pushscope allowed
1925 Traits* requiredType = scope->getScopeTraitsAt(scope->size+state->scopeDepth);
1926 if (!scopeTraits || !scopeTraits->subtypeof(requiredType))
1927 {
1928 verifyFailed(kIllegalOperandTypeError, core->toErrorString(scopeTraits), core->toErrorString(requiredType));
1929 }
1930 }
1931
1932 emitCheckNull(sp);
1933 coder->writeOp1(state, pc, opcode, ms->scope_base() + state->scopeDepth);
1934 state->pop();
1935 state->setType(ms->scope_base() + state->scopeDepth, scopeTraits, truetrue, falsefalse);
1936 state->scopeDepth++;
1937 break;
1938 }
1939
1940 case OP_pushwith:
1941 {
1942 checkStack(1,0);
1943
1944 if (state->scopeDepth + 1 > ms->max_scope())
1945 verifyFailed(kScopeStackOverflowError);
1946
1947 emitCheckNull(sp);
1948 coder->writeOp1(state, pc, opcode, ms->scope_base() + state->scopeDepth);
1949
1950 Traits* scopeTraits = state->peek().traits;
1951 state->pop();
1952 state->setType(ms->scope_base() + state->scopeDepth, scopeTraits, truetrue, truetrue);
1953
1954 if (state->withBase == -1)
1955 state->withBase = state->scopeDepth;
1956
1957 state->scopeDepth++;
1958 break;
1959 }
1960
1961 case OP_newactivation:
1962 {
1963 checkStack(0, 1);
1964 if (!info->needActivation())
1965 verifyFailed(kInvalidNewActivationError);
1966 Traits* atraits = info->activationTraits();
1967 atraits->resolveSignatures(toplevel);
1968 coder->write(state, pc, opcode, atraits);
1969 state->push(atraits, truetrue);
1970 break;
1971 }
1972
1973 case OP_newcatch:
1974 {
1975 checkStack(0, 1);
1976 if (!info->abc_exceptions() || imm30 >= (uint32_t)info->abc_exceptions()->exception_count)
1977 verifyFailed(kInvalidNewActivationError);
1978 // FIXME better error msg
1979 ExceptionHandler* handler = &info->abc_exceptions()->exceptions[imm30];
1980 coder->write(state, pc, opcode);
1981 state->push(handler->scopeTraits, truetrue);
1982 break;
1983 }
1984 case OP_popscope:
1985 //checkStack(0,0)
1986 if (state->scopeDepth-- <= 0)
1987 verifyFailed(kScopeStackUnderflowError);
1988
1989 coder->write(state, pc, opcode);
1990
1991 if (state->withBase >= state->scopeDepth)
1992 state->withBase = -1;
1993 break;
1994
1995 case OP_getscopeobject:
1996 checkStack(0,1);
1997
1998 // local scope
1999 if (imm8 >= state->scopeDepth)
2000 verifyFailed(kGetScopeObjectBoundsError, core->toErrorString(imm8));
2001
2002 coder->writeOp1(state, pc, opcode, imm8);
2003
2004 // this will copy type and all attributes too
2005 state->push(state->scopeValue(imm8));
2006 break;
2007
2008 case OP_getouterscope:
2009 {
2010 checkStack(0,1);
2011 const ScopeTypeChain* scope = info->declaringScope();
2012 uint32_t index = imm30;
2013 int captured_depth = scope->size;
2014 if (captured_depth > 0)
2015 {
2016 // imm30 is unsigned, so can't be < 0
2017 if (index >= uint32_t(scope->size))
2018 toplevel->throwVerifyError(kGetScopeObjectBoundsError);
2019
2020 // enclosing scope
2021 Traits* t = scope->getScopeTraitsAt(index);
2022 coder->writeOp1(state, pc, opcode, index, t);
2023 state->push(t, truetrue);
2024 }
2025 else
2026 {
2027 #ifdef _DEBUG
2028 if (pool->isBuiltin)
2029 core->console << "getouterscope >= depth (" << index << " >= " << state->scopeDepth << ")\n";
2030 #endif
2031 verifyFailed(kGetScopeObjectBoundsError, core->toErrorString(index));
2032 }
2033 break;
2034 }
2035
2036 case OP_getglobalscope:
2037 checkStack(0,1);
2038 coder->write(state, pc, OP_getglobalscope);
2039 checkGetGlobalScope(); // after coder->write because mutates stack that coder depends on
2040 break;
2041
2042 case OP_getglobalslot:
2043 {
2044 checkStack(0,1);
2045 uint32_t slot = imm30-1;
2046 Traits* globalTraits = checkGetGlobalScope();
2047 checkEarlySlotBinding(globalTraits); // sets state->value(sp).traits so CodeWriter can see type
2048 Traits* slotTraits = checkSlot(globalTraits, slot);
2049 coder->writeOp1(state, pc, OP_getglobalslot, slot, slotTraits);
2050 state->pop_push(1, slotTraits);
2051 break;
2052 }
2053
2054 case OP_setglobalslot:
2055 {
2056 // FIXME need test case
2057 const ScopeTypeChain* scope = info->declaringScope();
2058 if (!state->scopeDepth && !scope->size)
2059 verifyFailed(kNoGlobalScopeError);
2060 Traits *globalTraits = scope->size > 0 ? scope->getScopeTraitsAt(0) : state->scopeValue(0).traits;
2061 checkStack(1,0);
2062 checkEarlySlotBinding(globalTraits);
2063 Traits* slotTraits = checkSlot(globalTraits, imm30-1);
2064 emitCoerce(slotTraits, state->sp());
2065 coder->writeOp1(state, pc, opcode, imm30-1, slotTraits);
2066 state->pop();
2067 break;
2068 }
2069
2070 case OP_getslot:
2071 {
2072 checkStack(1,1);
2073 FrameValue& obj = state->peek();
2074 checkEarlySlotBinding(obj.traits);
2075 Traits* slotTraits = checkSlot(obj.traits, imm30-1);
2076 emitCheckNull(state->sp());
2077 coder->write(state, pc, opcode);
2078 state->pop_push(1, slotTraits);
2079 break;
2080 }
2081
2082 case OP_setslot:
2083 {
2084 checkStack(2,0);
2085 FrameValue& obj = state->peek(2); // object
2086 checkEarlySlotBinding(obj.traits);
2087 Traits* slotTraits = checkSlot(obj.traits, imm30-1);
2088 emitCoerce(slotTraits, state->sp());
2089 emitCheckNull(state->sp()-1);
2090 coder->write(state, pc, opcode);
2091 state->pop(2);
2092 break;
2093 }
2094
2095 case OP_pop:
2096 checkStack(1,0);
2097 coder->write(state, pc, opcode);
2098 state->pop();
2099 break;
2100
2101 case OP_dup:
2102 {
2103 checkStack(1, 2);
2104 FrameValue& v = state->peek();
2105 coder->write(state, pc, opcode);
2106 state->push(v);
2107 break;
2108 }
2109
2110 case OP_swap:
2111 {
2112 checkStack(2,2);
2113 FrameValue v1 = state->peek(1);
2114 FrameValue v2 = state->peek(2);
2115 coder->write(state, pc, opcode);
2116 state->pop(2);
2117 state->push(v1);
2118 state->push(v2);
2119 break;
2120 }
2121
2122 case OP_lessthan:
2123 case OP_greaterthan:
2124 case OP_lessequals:
2125 case OP_greaterequals:
2126 {
2127 // if either the LHS or RHS is a number type, then we know
2128 // it will be a numeric comparison.
2129 checkStack(2,1);
2130 FrameValue& rhs = state->peek(1);
2131 FrameValue& lhs = state->peek(2);
2132 Traits *lhst = lhs.traits;
2133 Traits *rhst = rhs.traits;
2134 if (rhst && rhst->isNumeric() && lhst && !lhst->isNumeric())
2135 {
2136 // convert lhs to Number
2137 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), state->sp()-1);
2138 }
2139 else if (lhst && lhst->isNumeric() && rhst && !rhst->isNumeric())
2140 {
2141 // promote rhs to Number
2142 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), state->sp());
2143 }
2144 coder->write(state, pc, opcode, BOOLEAN_TYPE(core->traits.boolean_itraits));
2145 state->pop_push(2, BOOLEAN_TYPE(core->traits.boolean_itraits));
2146 break;
2147 }
2148
2149 case OP_equals:
2150 case OP_strictequals:
2151 case OP_instanceof:
2152 case OP_in:
2153 checkStack(2,1);
2154 coder->write(state, pc, opcode);
2155 state->pop_push(2, BOOLEAN_TYPE(core->traits.boolean_itraits));
2156 break;
2157
2158 case OP_not:
2159 checkStack(1,1);
2160 emitCoerce(BOOLEAN_TYPE(core->traits.boolean_itraits), sp);
2161 coder->write(state, pc, opcode, BOOLEAN_TYPE(core->traits.boolean_itraits));
2162 state->pop_push(1, BOOLEAN_TYPE(core->traits.boolean_itraits));
2163 break;
2164
2165 case OP_add:
2166 {
2167 checkStack(2,1);
2168
2169 FrameValue& rhs = state->peek(1);
2170 FrameValue& lhs = state->peek(2);
2171 Traits* lhst = lhs.traits;
2172 Traits* rhst = rhs.traits;
2173 if ((lhst == STRING_TYPE(core->traits.string_itraits) && lhs.notNull) || (rhst == STRING_TYPE(core->traits.string_itraits) && rhs.notNull))
2174 {
2175 coder->write(state, pc, OP_add, STRING_TYPE(core->traits.string_itraits));
2176 state->pop_push(2, STRING_TYPE(core->traits.string_itraits), truetrue);
2177 }
2178 else if (lhst && lhst->isNumeric() && rhst && rhst->isNumeric())
2179 {
2180 coder->write(state, pc, OP_add, NUMBER_TYPE(core->traits.number_itraits));
2181 state->pop_push(2, NUMBER_TYPE(core->traits.number_itraits));
2182 }
2183 else
2184 {
2185 coder->write(state, pc, OP_add, OBJECT_TYPE(core->traits.object_itraits));
2186 // NOTE don't know if it will return number or string, but
2187 // neither will be null
2188 state->pop_push(2, OBJECT_TYPE(core->traits.object_itraits), truetrue);
2189 }
2190 break;
2191 }
2192
2193 case OP_modulo:
2194 case OP_subtract:
2195 case OP_divide:
2196 case OP_multiply:
2197 checkStack(2,1);
2198 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), sp-1);
2199 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), sp);
2200 coder->write(state, pc, opcode);
2201 state->pop_push(2, NUMBER_TYPE(core->traits.number_itraits));
2202 break;
2203
2204 case OP_negate:
2205 checkStack(1,1);
2206 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), sp);
2207 coder->write(state, pc, opcode);
2208 break;
2209
2210 case OP_increment:
2211 case OP_decrement:
2212 checkStack(1,1);
2213 emitCoerce(NUMBER_TYPE(core->traits.number_itraits), sp);
2214 coder->write(state, pc, opcode);
2215 break;
2216
2217 case OP_increment_i:
2218 case OP_decrement_i:
2219 checkStack(1,1);
2220 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2221 coder->write(state, pc, opcode);
2222 break;
2223
2224 case OP_add_i:
2225 case OP_subtract_i:
2226 case OP_multiply_i:
2227 checkStack(2,1);
2228 emitCoerce(INT_TYPE(core->traits.int_itraits), sp-1);
2229 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2230 coder->write(state, pc, opcode);
2231 state->pop_push(2, INT_TYPE(core->traits.int_itraits));
2232 break;
2233
2234 case OP_negate_i:
2235 checkStack(1,1);
2236 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2237 coder->write(state, pc, opcode);
2238 break;
2239
2240 case OP_bitand:
2241 case OP_bitor:
2242 case OP_bitxor:
2243 checkStack(2,1);
2244 emitCoerce(INT_TYPE(core->traits.int_itraits), sp-1);
2245 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2246 coder->write(state, pc, opcode);
2247 state->pop_push(2, INT_TYPE(core->traits.int_itraits));
2248 break;
2249
2250 // ISSUE do we care if shift amount is signed or not? we mask
2251 // the result so maybe it doesn't matter.
2252 // CN says see tests e11.7.2, 11.7.3, 9.6
2253 case OP_lshift:
2254 case OP_rshift:
2255 checkStack(2,1);
2256 emitCoerce(INT_TYPE(core->traits.int_itraits), sp-1);
2257 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2258 coder->write(state, pc, opcode);
2259 state->pop_push(2, INT_TYPE(core->traits.int_itraits));
2260 break;
2261
2262 case OP_urshift:
2263 checkStack(2,1);
2264 emitCoerce(INT_TYPE(core->traits.int_itraits), sp-1);
2265 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2266 coder->write(state, pc, opcode);
2267 state->pop_push(2, UINT_TYPE(core->traits.uint_itraits));
2268 break;
2269
2270 case OP_bitnot:
2271 checkStack(1,1);
2272 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2273 coder->write(state, pc, opcode);
2274 break;
2275
2276 case OP_typeof:
2277 checkStack(1,1);
2278 coder->write(state, pc, opcode);
2279 state->pop_push(1, STRING_TYPE(core->traits.string_itraits), truetrue);
2280 break;
2281
2282 case OP_nop:
2283 // those show up but will be ignored
2284 case OP_bkpt:
2285 case OP_bkptline:
2286 case OP_timestamp:
2287 coder->write(state, pc, OP_nop);
2288 break;
2289
2290 case OP_debug:
2291 {
2292#ifdef DEBUGGER
2293 // fixme: bugzilla 552988: remove ifdef.
2294 uint8_t type = (uint8_t)*(pc + 1);
2295 if (type == DI_LOCAL) {
2296 // see Debugger::scanCode
2297 const uint8_t* pc2 = pc + 2;
2298 uint32_t index = AvmCore::readU32(pc2);
2299 checkStringOperand(index);
2300 }
2301#endif
2302 coder->write(state, pc, opcode);
2303 break;
2304 }
2305
2306 case OP_label:
2307 coder->write(state, pc, opcode);
2308 break;
2309
2310 case OP_debugline:
2311 coder->write(state, pc, opcode);
2312 break;
2313
2314 case OP_nextvalue:
2315 case OP_nextname:
2316 checkStack(2,1);
2317 peekType(INT_TYPE(core->traits.int_itraits), 1);
2318 coder->write(state, pc, opcode);
2319 state->pop_push(2, NULL__null);
2320 break;
2321
2322 case OP_hasnext:
2323 checkStack(2,1);
2324 peekType(INT_TYPE(core->traits.int_itraits),1);
2325 coder->write(state, pc, opcode);
2326 state->pop_push(2, INT_TYPE(core->traits.int_itraits));
2327 break;
2328
2329 case OP_hasnext2:
2330 {
2331 checkStack(0,1);
2332 checkLocal(imm30);
2333 FrameValue& v = checkLocal(imm30b);
2334 if (imm30 == imm30b)
2335 verifyFailed(kInvalidHasNextError);
2336 if (v.traits != INT_TYPE(core->traits.int_itraits))
2337 verifyFailed(kIllegalOperandTypeError, core->toErrorString(v.traits), core->toErrorString(INT_TYPE(core->traits.int_itraits)));
2338 coder->write(state, pc, opcode);
2339 state->setType(imm30, NULL__null, falsefalse);
2340 state->push(BOOLEAN_TYPE(core->traits.boolean_itraits));
2341 break;
2342 }
2343
2344 // sign extends
2345 case OP_sxi1:
2346 case OP_sxi8:
2347 case OP_sxi16:
2348 checkStack(1,1);
2349 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2350 coder->write(state, pc, opcode);
2351 state->pop_push(1, INT_TYPE(core->traits.int_itraits));
2352 break;
2353
2354 // loads
2355 case OP_li8:
2356 case OP_li16:
2357 if (pc+1 < code_end &&
2358 ((opcode == OP_li8 && pc[1] == OP_sxi8) || (opcode == OP_li16 && pc[1] == OP_sxi16)))
2359 {
2360 checkStack(1,1);
2361 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2362 coder->write(state, pc, (opcode == OP_li8) ? OP_lix8 : OP_lix16);
2363 state->pop_push(1, INT_TYPE(core->traits.int_itraits));
2364 // ++pc; // do not skip the sign-extend; if it's the target
2365 // of an implicit label, skipping it would cause verification failure.
2366 // instead, just emit it, and rely on LIR to ignore sxi instructions
2367 // in these situations.
2368 break;
2369 }
2370 // else fall thru
2371 case OP_li32:
2372 case OP_lf32:
2373 case OP_lf64:
2374 {
2375 Traits* result = (opcode == OP_lf32 || opcode == OP_lf64) ? NUMBER_TYPE(core->traits.number_itraits) : INT_TYPE(core->traits.int_itraits);
2376 checkStack(1,1);
2377 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2378 coder->write(state, pc, opcode);
2379 state->pop_push(1, result);
2380 break;
2381 }
2382
2383 // stores
2384 case OP_si8:
2385 case OP_si16:
2386 case OP_si32:
2387 case OP_sf32:
2388 case OP_sf64:
2389 checkStack(2,0);
2390 emitCoerce((opcode == OP_sf32 || opcode == OP_sf64) ? NUMBER_TYPE(core->traits.number_itraits) : INT_TYPE(core->traits.int_itraits), sp-1);
2391 emitCoerce(INT_TYPE(core->traits.int_itraits), sp);
2392 coder->write(state, pc, opcode);
2393 state->pop(2);
2394 break;
2395
2396 default:
2397 // size was nonzero, but no case handled the opcode. someone asleep at the wheel!
2398 AvmAssertMsg(false, "Unhandled opcode")do { } while (0);
2399 }
2400
2401 coder->writeOpcodeVerified(state, pc, opcode);
2402 #ifdef AVMPLUS_VERBOSE
2403 if (verbose) {
2404 StringBuffer buf(core);
2405 printState(buf, state);
2406 }
2407 #endif
2408 }
2409
2410 verifyFailed(kCannotFallOffMethodError);
2411 return code_end;
2412 }
2413
2414 void Verifier::checkPropertyMultiname(uint32_t &depth, Multiname &multiname)
2415 {
2416 if (multiname.isRtname())
2417 {
2418 if (multiname.isQName())
2419 {
2420 // a.ns::@[name] or a.ns::[name]
2421 peekType(STRING_TYPE(core->traits.string_itraits), depth++);
2422 }
2423 else
2424 {
2425 // a.@[name] or a[name]
2426 depth++;
2427 }
2428 }
2429
2430 if (multiname.isRtns())
2431 {
2432 peekType(NAMESPACE_TYPE(core->traits.namespace_itraits), depth++);
2433 }
2434 }
2435
2436 void Verifier::emitCallproperty(AbcOpcode opcode, int& sp, Multiname& multiname, uint32_t multiname_index, uint32_t argc, const uint8_t* pc)
2437 {
2438 uint32_t n = argc+1;
2439 checkPropertyMultiname(n, multiname);
2440 Traits* t = state->peek(n).traits;
2441
2442 if (t)
2443 t->resolveSignatures(toplevel);
2444 Binding b = toplevel->getBinding(t, &multiname);
2445
2446 emitCheckNull(sp-(n-1));
2447
2448 if (emitCallpropertyMethod(opcode, t, b, multiname, multiname_index, argc, pc))
2449 return;
2450
2451 if (emitCallpropertySlot(opcode, sp, t, b, argc, pc))
2452 return;
2453
2454 coder->writeOp2(state, pc, opcode, multiname_index, argc);
2455
2456 // If early binding then the state will have been updated, so this will be skipped
2457 state->pop_push(n, NULL__null);
2458 if (opcode == OP_callpropvoid)
2459 state->pop();
2460 }
2461
2462 boolbool Verifier::emitCallpropertyMethod(AbcOpcode opcode, Traits* t, Binding b, Multiname& multiname, uint32_t multiname_index, uint32_t argc, const uint8_t* pc)
2463 {
2464 (void) multiname_index; // FIXME remove
2465
2466 if (!AvmCore::isMethodBinding(b))
2467 return falsefalse;
2468
2469 uint32_t n = argc+1;
2470 const TraitsBindingsp tb = t->getTraitsBindings();
2471 if (t == core->traits.math_ctraits)
2472 b = findMathFunction(tb, multiname, b, argc);
2473 else if (t == core->traits.string_itraits)
2474 b = findStringFunction(tb, multiname, b, argc);
2475
2476 int disp_id = AvmCore::bindingToMethodId(b);
2477 MethodInfo* m = tb->getMethod(disp_id);
2478 MethodSignaturep mms = m->getMethodSignature();
2479
2480 if (!mms->argcOk(argc))
2481 return falsefalse;
2482
2483 Traits* resultType = mms->returnTraits();
2484
2485 emitCoerceArgs(m, argc);
2486 if (!t->isInterface())
2487 {
2488 coder->writeMethodCall(state, pc, OP_callmethod, m, disp_id, argc, resultType);
2489 if (opcode == OP_callpropvoid)
2490 coder->write(state, pc, OP_pop);
2491 }
2492 else
2493 {
2494 // NOTE when the interpreter knows how to dispatch through an
2495 // interface, we can rewrite this call as a 'writeOp2'.
2496 coder->writeMethodCall(state, pc, opcode, m, 0, argc, resultType);
2497 }
2498
2499 state->pop_push(n, resultType);
2500 if (opcode == OP_callpropvoid)
2501 {
2502 state->pop();
2503 }
2504
2505 return truetrue;
2506 }
2507
2508 boolbool Verifier::emitCallpropertySlot(AbcOpcode opcode, int& sp, Traits* t, Binding b, uint32_t argc, const uint8_t *pc)
2509 {
2510 if (!AvmCore::isSlotBinding(b) || argc != 1)
2511 return falsefalse;
2512
2513 const TraitsBindingsp tb = t->getTraitsBindings();
2514
2515 int slot_id = AvmCore::bindingToSlotId(b);
2516 Traits* slotType = tb->getSlotTraits(slot_id);
2517
2518 if (slotType == core->traits.int_ctraits)
2519 {
2520 coder->write(state, pc, OP_convert_i, INT_TYPE(core->traits.int_itraits));
2521 state->setType(sp, INT_TYPE(core->traits.int_itraits), truetrue);
2522 }
2523 else
2524 if (slotType == core->traits.uint_ctraits)
2525 {
2526 coder->write(state, pc, OP_convert_u, UINT_TYPE(core->traits.uint_itraits));
2527 state->setType(sp, UINT_TYPE(core->traits.uint_itraits), truetrue);
2528 }
2529 else
2530 if (slotType == core->traits.number_ctraits)
2531 {
2532 coder->write(state, pc, OP_convert_d, NUMBER_TYPE(core->traits.number_itraits));
2533 state->setType(sp, NUMBER_TYPE(core->traits.number_itraits), truetrue);
2534 }
2535 else
2536 if (slotType == core->traits.boolean_ctraits)
2537 {
2538 coder->write(state, pc, OP_convert_b, BOOLEAN_TYPE(core->traits.boolean_itraits));
2539 state->setType(sp, BOOLEAN_TYPE(core->traits.boolean_itraits), truetrue);
2540 }
2541 else
2542 if (slotType == core->traits.string_ctraits)
2543 {
2544 coder->write(state, pc, OP_convert_s, STRING_TYPE(core->traits.string_itraits));
2545 state->setType(sp, STRING_TYPE(core->traits.string_itraits), truetrue);
2546 }
2547 else
2548 // NOTE the following has been refactored so that both lir and wc coerce. previously
2549 // wc would be skipped and fall back on the method call the the class converter
2550 if (slotType && slotType->base == CLASS_TYPE(core->traits.class_itraits) && slotType->getCreateClassClosureProc() == NULL__null)
2551 {
2552 // is this a user defined class? A(1+ args) means coerce to A
2553 AvmAssert(slotType->itraits != NULL)do { } while (0);
2554 FrameValue &v = state->value(sp);
2555 coder->write(state, pc, OP_coerce, slotType->itraits);
2556 state->setType(sp, slotType->itraits, v.notNull);
2557 }
2558 else
2559 {
2560 return falsefalse;
2561 }
2562
2563 if (opcode == OP_callpropvoid)
2564 {
2565 coder->write(state, pc, OP_pop); // result
2566 coder->write(state, pc, OP_pop); // function
2567 state->pop(2);
2568 }
2569 else
2570 {
2571 FrameValue v = state->stackTop();
2572 // NOTE writeNip is necessary until lir optimizes the "nip"
2573 // case to avoid the extra copies that result from swap+pop
2574 coder->writeNip(state, pc);
2575 state->pop(2);
2576 state->push(v);
2577 }
2578 return truetrue;
2579 }
2580
2581 void Verifier::emitFindProperty(AbcOpcode opcode, Multiname& multiname, uint32_t imm30, const uint8_t *pc)
2582 {
2583 boolbool skip_translation = falsefalse;
2584 const ScopeTypeChain* scope = info->declaringScope();
2585 if (multiname.isBinding())
2586 {
2587 int scope_base = ms->scope_base();
2588 int base = scope_base;
2589 int index = base + state->scopeDepth - 1;
2590 if (scope->size == 0)
2591 {
2592 // if scope->size = 0, then global is a local
2593 // scope, and we dont want to early bind to global.
2594 base++;
2595 }
2596 for (; index >= base; index--)
2597 {
2598 FrameValue& v = state->value(index);
2599 Binding b = toplevel->getBinding(v.traits, &multiname);
2600 if (b != BIND_NONE)
2601 {
2602 coder->writeOp1(state, pc, OP_getscopeobject, index - scope_base);
2603 state->push(v);
2604 return;
2605 }
2606 if (v.isWith)
2607 break; // with scope could have dynamic property
2608 }
2609 if (index < base)
2610 {
2611 // look at captured scope types
2612 for (index = scope->size-1; index > 0; index--)
2613 {
2614 Traits* t = scope->getScopeTraitsAt(index);
2615 Binding b = toplevel->getBinding(t, &multiname);
2616 if (b != BIND_NONE)
2617 {
2618 coder->writeOp1(state, pc, OP_getouterscope, index);
2619 state->push(t, truetrue);
2620 return;
2621 }
2622 if (scope->getScopeIsWithAt(index))
2623 break; // with scope could have dynamic property
2624 }
2625 if (index <= 0)
2626 {
2627 // look at import table for a suitable script
2628 MethodInfo* script = core->domainMgr()->findScriptInPoolByMultiname(pool, multiname);
2629 if (script != (MethodInfo*)BIND_NONE && script != (MethodInfo*)BIND_AMBIGUOUS)
2630 {
2631 if (script == info)
2632 {
2633 // ISSUE what if there is an ambiguity at runtime? is VT too early to bind?
2634 // its defined here, use getscopeobject 0
2635 if (scope->size > 0)
2636 {
2637 coder->writeOp1(state, pc, OP_getouterscope, 0);
2638 }
2639 else
2640 {
2641 coder->write(state, pc, OP_getglobalscope);
2642 }
2643 }
2644 else // found a single matching traits
2645 {
2646 coder->writeOp1(state, pc, OP_finddef, imm30, script->declaringTraits());
2647 }
2648 state->push(script->declaringTraits(), truetrue);
2649 return;
2650 }
2651 else
2652 {
2653 switch (opcode) {
2654 case OP_findproperty:
2655 coder->writeOp1(state, pc, OP_findpropglobal, imm30);
2656 break;
2657 case OP_findpropstrict:
2658 coder->writeOp1(state, pc, OP_findpropglobalstrict, imm30);
2659 break;
2660 default:
2661 AvmAssert(false)do { } while (0);
2662 break;
2663 }
2664 skip_translation = truetrue;
2665 }
2666 }
2667 }
2668 }
2669 uint32_t n=1;
2670 checkPropertyMultiname(n, multiname);
2671 if (!skip_translation) coder->writeOp1(state, pc, opcode, imm30, OBJECT_TYPE(core->traits.object_itraits));
2672 state->pop_push(n-1, OBJECT_TYPE(core->traits.object_itraits), truetrue);
2673 }
2674
2675 void Verifier::emitGetProperty(Multiname &multiname, int n, uint32_t imm30, const uint8_t *pc)
2676 {
2677 FrameValue& obj = state->peek(n);
2678
2679 Binding b = toplevel->getBinding(obj.traits, &multiname);
2680 Traits* propType = readBinding(obj.traits, b);
2681
2682 emitCheckNull(state->sp()-(n-1));
2683
2684 // early bind slot
2685 if (AvmCore::isSlotBinding(b))
2686 {
2687 coder->writeOp1(state, pc, OP_getslot, AvmCore::bindingToSlotId(b), propType);
2688 state->pop_push(n, propType);
2689 return;
2690 }
2691
2692 // early bind accessor
2693 if (AvmCore::hasGetterBinding(b))
2694 {
2695 // Invoke the getter
2696 int disp_id = AvmCore::bindingToGetterId(b);
2697 const TraitsBindingsp objtd = obj.traits->getTraitsBindings();
2698 MethodInfo *f = objtd->getMethod(disp_id);
2699 AvmAssert(f != NULL)do { } while (0);
2700 emitCoerceArgs(f, 0);
2701 coder->writeOp2(state, pc, OP_getproperty, imm30, n, propType);
2702 AvmAssert(propType == f->getMethodSignature()->returnTraits())do { } while (0);
2703 state->pop_push(n, propType);
2704 return;
2705 }
2706 if( !propType )
2707 {
2708 if( obj.traits == VECTORINT_TYPE(core->traits.vectorint_itraits) || obj.traits == VECTORUINT_TYPE(core->traits.vectoruint_itraits) ||
2709 obj.traits == VECTORDOUBLE_TYPE(core->traits.vectordouble_itraits) )
2710 {
2711 boolbool attr = multiname.isAttr();
2712 Traits* indexType = state->value(state->sp()).traits;
2713 // NOTE a dynamic name should have the same version as the current pool
2714 boolbool maybeIntegerIndex = !attr && multiname.isRtname() && multiname.containsAnyPublicNamespace();
2715 if( maybeIntegerIndex && (indexType == UINT_TYPE(core->traits.uint_itraits) || indexType == INT_TYPE(core->traits.int_itraits) || indexType == NUMBER_TYPE(core->traits.number_itraits)) )
2716 {
2717 if(obj.traits == VECTORINT_TYPE(core->traits.vectorint_itraits))
2718 propType = INT_TYPE(core->traits.int_itraits);
2719 else if(obj.traits == VECTORUINT_TYPE(core->traits.vectoruint_itraits))
2720 propType = UINT_TYPE(core->traits.uint_itraits);
2721 else if(obj.traits == VECTORDOUBLE_TYPE(core->traits.vectordouble_itraits))
2722 propType = NUMBER_TYPE(core->traits.number_itraits);
2723 }
2724 }
2725 }
2726
2727 // default - do getproperty at runtime
2728
2729 coder->writeOp2(state, pc, OP_getproperty, imm30, n, propType);
2730 state->pop_push(n, propType);
2731 }
2732
2733 Traits* Verifier::checkGetGlobalScope()
2734 {
2735 const ScopeTypeChain* scope = info->declaringScope();
2736 int captured_depth = scope->size;
2737 if (captured_depth > 0) {
2738 // enclosing scope
2739 Traits* t = scope->getScopeTraitsAt(0);
2740 state->push(t, truetrue);
2741 return t;
2742 }
2743 else {
2744 // local scope
2745 if (state->scopeDepth == 0)
2746 verifyFailed(kGetScopeObjectBoundsError, core->toErrorString(0));
2747 Traits* t = state->scopeValue(0).traits;
2748 state->push(state->scopeValue(0));
2749 return t;
2750 }
2751 }
2752
2753 FrameState *Verifier::getFrameState(const uint8_t* pc) const
2754 {
2755 return blockStates ? blockStates->map.get(pc) : NULL__null;
2756 }
2757
2758 boolbool Verifier::hasFrameState(const uint8_t* pc) const
2759 {
2760 return blockStates && blockStates->map.containsKey(pc);
2761 }
2762
2763 int Verifier::getBlockCount() const
2764 {
2765 return blockStates ? blockStates->map.length() : 0;
2766 }
2767
2768 const uint8_t* Verifier::getTryFrom() const
2769 {
2770 return tryFrom;
2771 }
2772
2773 const uint8_t* Verifier::getTryTo() const
2774 {
2775 return tryTo;
2776 }
2777
2778 void Verifier::emitCheckNull(int i)
2779 {
2780 FrameValue& value = state->value(i);
2781 if (!value.notNull) {
2782 coder->writeCheckNull(state, i);
2783 value.notNull = truetrue;
2784 }
2785 }
2786
2787 void Verifier::checkCallMultiname(AbcOpcode /*opcode*/, Multiname* name) const
2788 {
2789 if (name->isAttr())
2790 {
2791 StringBuffer sb(core);
2792 sb << *name;
2793 verifyFailed(kIllegalOpMultinameError, core->toErrorString(name), sb.toString());
2794 }
2795 }
2796
2797 Traits* Verifier::emitCoerceSuper(int index)
2798 {
2799 Traits* base = info->declaringTraits()->base;
2800 if (base != NULL__null)
2801 {
2802 emitCoerce(base, index);
2803 }
2804 else
2805 {
2806 verifyFailed(kIllegalSuperCallError, core->toErrorString(info));
2807 }
2808 return base;
2809 }
2810
2811 void Verifier::emitCoerce(Traits* target, int index)
2812 {
2813 FrameValue &v = state->value(index);
2814 coder->writeCoerce(state, index, target);
2815 state->setType(index, target, v.notNull);
2816 }
2817
2818 Traits* Verifier::peekType(Traits* requiredType, int n)
2819 {
2820 Traits* t = state->peek(n).traits;
2821 if (t != requiredType)
2822 {
2823 verifyFailed(kIllegalOperandTypeError, core->toErrorString(t), core->toErrorString(requiredType));
2824 }
2825 return t;
2826 }
2827
2828 void Verifier::checkEarlySlotBinding(Traits* t)
2829 {
2830 if (!t || !t->allowEarlyBinding())
2831 verifyFailed(kIllegalEarlyBindingError, core->toErrorString(t));
2832 }
2833
2834 void Verifier::emitCoerceArgs(MethodInfo* m, int argc)
2835 {
2836 if (!m->isResolved())
2837 m->resolveSignature(toplevel);
2838
2839 MethodSignaturep mms = m->getMethodSignature();
2840 if (!mms->argcOk(argc))
2841 {
2842 verifyFailed(kWrongArgumentCountError, core->toErrorString(m), core->toErrorString(mms->requiredParamCount()), core->toErrorString(argc));
2843 }
2844
2845 // coerce parameter types
2846 int n=1;
2847 while (argc > 0)
2848 {
2849 Traits* target = (argc <= mms->param_count()) ? mms->paramTraits(argc) : NULL__null;
2850 emitCoerce(target, state->sp()-(n-1));
2851 argc--;
2852 n++;
2853 }
2854
2855 // coerce receiver type
2856 emitCoerce(mms->paramTraits(0), state->sp()-(n-1));
2857 }
2858
2859 void Verifier::checkStack(uint32_t pop, uint32_t push)
2860 {
2861 if (uint32_t(state->stackDepth) < pop)
2862 verifyFailed(kStackUnderflowError);
2863 if (state->stackDepth - pop + push > uint32_t(ms->max_stack()))
2864 verifyFailed(kStackOverflowError);
2865 }
2866
2867 void Verifier::checkStackMulti(uint32_t pop, uint32_t push, Multiname* m)
2868 {
2869 if (m->isRtname()) pop++;
2870 if (m->isRtns()) pop++;
2871 checkStack(pop,push);
2872 }
2873
2874 FrameValue& Verifier::checkLocal(int local)
2875 {
2876 if (local < 0 || local >= ms->local_count())
2877 verifyFailed(kInvalidRegisterError, core->toErrorString(local));
2878 return state->value(local);
2879 }
2880
2881 Traits* Verifier::checkSlot(Traits *traits, int imm30)
2882 {
2883 uint32_t slot = imm30;
2884 if (traits)
2885 traits->resolveSignatures(toplevel);
2886 TraitsBindingsp td = traits ? traits->getTraitsBindings() : NULL__null;
2887 const uint32_t count = td ? td->slotCount : 0;
2888 if (!traits || slot >= count)
2889 {
2890 verifyFailed(kSlotExceedsCountError, core->toErrorString(slot+1), core->toErrorString(count), core->toErrorString(traits));
2891 }
2892 return td->getSlotTraits(slot);
2893 }
2894
2895 Traits* Verifier::readBinding(Traits* traits, Binding b) const
2896 {
2897 if (traits)
2898 {
2899 traits->resolveSignatures(toplevel);
2900 }
2901 else
2902 {
2903 AvmAssert(AvmCore::bindingKind(b) == BKIND_NONE)do { } while (0);
2904 }
2905 return Traits::readBinding(traits, b);
2906 }
2907
2908 MethodInfo* Verifier::checkMethodInfo(uint32_t id)
2909 {
2910 const uint32_t c = pool->methodCount();
2911 if (id >= c)
2912 {
2913 verifyFailed(kMethodInfoExceedsCountError, core->toErrorString(id), core->toErrorString(c));
2914 }
2915
2916 return pool->getMethodInfo(id);
2917 }
2918
2919 Traits* Verifier::checkClassInfo(uint32_t id)
2920 {
2921 const uint32_t c = pool->classCount();
2922 if (id >= c)
2923 {
2924 verifyFailed(kClassInfoExceedsCountError, core->toErrorString(id), core->toErrorString(c));
2925 }
2926
2927 return pool->getClassTraits(id);
2928 }
2929
2930 Traits* Verifier::checkTypeName(uint32_t index)
2931 {
2932 Multiname name;
2933 checkConstantMultiname(index, name); // CONSTANT_Multiname
2934 Traits* t = core->domainMgr()->findTraitsInPoolByMultiname(pool, name);
2935 if (t == NULL__null)
2936 verifyFailed(kClassNotFoundError, core->toErrorString(&name));
2937 if (t == (Traits*)BIND_AMBIGUOUS)
2938 toplevel->throwReferenceError(kAmbiguousBindingError, name);
2939 if (name.isParameterizedType())
2940 {
2941 core->stackCheck(toplevel);
2942 Traits* param_traits = name.getTypeParameter() ? checkTypeName(name.getTypeParameter()) : NULL__null ;
2943 t = pool->resolveParameterizedType(toplevel, t, param_traits);
2944 }
2945 return t;
2946 }
2947
2948 void Verifier::verifyFailed(int errorID, Stringp arg1, Stringp arg2, Stringp arg3) const
2949 {
2950 #ifdef AVMPLUS_VERBOSE
2951 if (!secondTry && !verbose) {
2952 // capture the verify trace even if verbose is false.
2953 Verifier v2(info, ms, toplevel, abc_env, truetrue);
2954 v2.verbose = truetrue;
2955 v2.tryFrom = tryFrom;
2956 v2.tryTo = tryTo;
2957 CodeWriter stubWriter;
2958
2959 // The second verification pass will presumably always throw an
2960 // error, which we ignore. But we /must/ catch it so that we can
2961 // clean up the verifier resources. Cleanup happens automatically
2962 // when execution reaches the end of the block.
2963
2964 TRY(core, kCatchAction_Ignore){ avmplus::ExceptionFrame _ef; _ef.beginTry(core); _ef.catchAction
= (kCatchAction_Ignore); int _setjmpVal = ::_setjmp(_ef.jmpbuf
); avmplus::Exception* _ee = core->exceptionAddr; if (!_setjmpVal
)
{
2965 v2.verify(&stubWriter);
2966 }
2967 CATCH(Exception *ignored)else { _ef.beginCatch(); Exception *ignored = _ee; {
2968 (void)ignored;
2969 }
2970 END_CATCH}
2971 END_TRY}
2972 }
2973 #endif
2974 toplevel->throwVerifyError(errorID, arg1, arg2, arg3);
2975
2976 // This function throws, and should never return.
2977 AvmAssert(false)do { } while (0);
2978 }
2979
2980 // Merge the current FrameState (this->state) with the target
2981 // FrameState (getFrameState(target)), and report verify errors.
2982 // Fixme: Bug 558876 - |current| must not be dereferenced, it could point
2983 // outside the valid range of bytecodes. Its only for back-edge detection.
2984 void Verifier::checkTarget(const uint8_t* current, const uint8_t* target)
2985 {
2986 if (emitPass) {
2987 AvmAssert(hasFrameState(target))do { } while (0);
2988 return;
2989 }
2990
2991 // branches must stay inside code, and back edges must land on an OP_label,
2992 // or a location already known as a forward-branch target
2993 if (target < code_pos || target >= code_pos+code_length ||
2994 (target <= current && !hasFrameState(target) && *target != OP_label)) {
2995 verifyFailed(kInvalidBranchTargetError);
2996 }
2997
2998 FrameState *targetState = getFrameState(target);
2999 boolbool targetChanged;
3000 if (!targetState) {
3001 if (!blockStates)
3002 blockStates = new (core->GetGC()) BlockStatesType(core->GetGC());
3003 targetState = mmfx_new( FrameState(ms) )new (MMgc::kUseFixedMalloc) FrameState(ms);
3004 targetState->abc_pc = target;
3005 blockStates->map.put(target, targetState);
3006
3007 // first time visiting target block
3008 targetChanged = truetrue;
3009 AvmAssert(!state->targetOfBackwardsBranch)do { } while (0);
3010 targetState->init(state);
3011
3012 #ifdef AVMPLUS_VERBOSE
3013 if (verbose) {
3014 core->console << "------------------------------------\n";
3015 StringBuffer buf(core);
3016 buf << "MERGE FIRST B" << int(targetState->abc_pc - code_pos) << ":";
3017 printState(buf, targetState);
3018 core->console << "------------------------------------\n";
3019 }
3020 #endif
3021 } else {
3022 targetChanged = mergeState(targetState);
3023 }
3024 boolbool targetOfBackwardsBranch = targetState->targetOfBackwardsBranch || target <= current;
3025 if (targetOfBackwardsBranch != targetState->targetOfBackwardsBranch)
3026 targetChanged |= truetrue;
3027 targetState->targetOfBackwardsBranch = targetOfBackwardsBranch;
3028 if (targetChanged && !targetState->wl_pending) {
3029 targetState->wl_pending = truetrue;
3030 targetState->wl_next = worklist;
3031 worklist = targetState;
3032 }
3033 }
3034
3035 boolbool Verifier::mergeState(FrameState* targetState)
3036 {
3037#ifdef AVMPLUS_VERBOSE
3038 if (verbose) {
3039 core->console << "------------------------------------\n";
3040 StringBuffer buf(core);
3041 buf << "MERGE CURRENT " << int(state->abc_pc - code_pos) << ":";
3042 printState(buf, state);
3043 buf.reset();
3044 buf << "MERGE TARGET B" << int(targetState->abc_pc - code_pos) << ":";
3045 printState(buf, targetState);
3046 }
3047#endif
3048
3049 // check matching stack depth
3050 if (state->stackDepth != targetState->stackDepth)
3051 verifyFailed(kStackDepthUnbalancedError, core->toErrorString((int)state->stackDepth), core->toErrorString((int)targetState->stackDepth));
3052
3053 // check matching scope chain depth
3054 if (state->scopeDepth != targetState->scopeDepth)
3055 verifyFailed(kScopeDepthUnbalancedError, core->toErrorString(state->scopeDepth), core->toErrorString(targetState->scopeDepth));
3056
3057 // Merge types of locals, scopes, and operands.
3058 // Merge could preserve common interfaces even when
3059 // common supertype does not:
3060 // class A implements I {}
3061 // class B implements I {}
3062 // var i:I = b ? new A : new B
3063 // Doing so would require different specification for verify-time analysis,
3064 // essentially a differnet ABC spec, yet each abc version needs predictable
3065 // verifier semantics.
3066 // On the other hand, later optimization passes are free to be as accurate as
3067 // they like, if it produces better code.
3068
3069 boolbool targetChanged = falsefalse;
3070 const int scopeTop = ms->scope_base() + targetState->scopeDepth;
3071 const int stackTop = ms->stack_base() + targetState->stackDepth;
3072 for (int i=0, n=stackTop; i < n; i++)
3073 {
3074 // ignore empty locations between scopeTop and stackBase
3075 if (i >= scopeTop && i < ms->stack_base())
3076 continue;
3077
3078 const FrameValue& curValue = state->value(i);
3079 FrameValue& targetValue = targetState->value(i);
3080
3081 if (curValue.isWith != targetValue.isWith) {
3082 // failure: pushwith on one edge, pushscope on other edge, cannot merge.
3083 verifyFailed(kCannotMergeTypesError, core->toErrorString(targetValue.traits), core->toErrorString(curValue.traits));
3084 }
3085
3086 Traits* merged_traits = findCommonBase(targetValue.traits, curValue.traits);
3087 boolbool merged_notNull = targetValue.notNull && curValue.notNull;
3088
3089 if (targetValue.traits != merged_traits || targetValue.notNull != merged_notNull)
3090 targetChanged = truetrue;
3091
3092 targetValue.traits = merged_traits;
3093 targetValue.notNull = merged_notNull;
3094#ifdef VMCFG_NANOJIT
3095 uint8_t merged_sst = targetValue.sst_mask | curValue.sst_mask;
3096 if (targetValue.sst_mask != merged_sst)
3097 targetChanged = truetrue;
3098 targetValue.sst_mask = merged_sst;
3099#endif
3100 }
3101
3102#ifdef AVMPLUS_VERBOSE
3103 if (verbose) {
3104 StringBuffer buf(core);
3105 buf << "AFTER MERGE B" << int(targetState->abc_pc - code_pos) << ":";
3106 printState(buf, targetState);
3107 core->console << "------------------------------------\n";
3108 }
3109#endif
3110 return targetChanged;
3111 }
3112
3113 /**
3114 * find common base class of these two types
3115 */
3116 Traits* Verifier::findCommonBase(Traits* t1, Traits* t2)
3117 {
3118 if (t1 == t2)
3119 return t1;
3120
3121 if (t1 == NULL__null) {
3122 // assume t1 is always non-null
3123 Traits *temp = t1;
3124 t1 = t2;
3125 t2 = temp;
3126 }
3127
3128 if (t1 == NULL_TYPE(core->traits.null_itraits) && t2 && !t2->isMachineType())
3129 {
3130 // okay to merge null with pointer type
3131 return t2;
3132 }
3133 if (t2 == NULL_TYPE(core->traits.null_itraits) && t1 && !t1->isMachineType())
3134 {
3135 // okay to merge null with pointer type
3136 return t1;
3137 }
3138
3139 // all commonBase flags start out false. set the cb bits on
3140 // t1 and its ancestors.
3141 Traits* t = t1;
3142 do t->commonBase = truetrue;
3143 while ((t = t->base) != NULL__null);
3144
3145 // now search t2 and its ancestors looking for the first cb=true
3146 t = t2;
3147 while (t != NULL__null && !t->commonBase)
3148 t = t->base;
3149
3150 Traits* common = t;
3151
3152 // finally reset the cb bits to false for next time
3153 t = t1;
3154 do t->commonBase = falsefalse;
3155 while ((t = t->base) != NULL__null);
3156
3157 return common;
3158 }
3159
3160 void Verifier::checkStringOperand(uint32_t index)
3161 {
3162 if (!index || index >= pool->constantStringCount)
3163 verifyFailed(kCpoolIndexRangeError, core->toErrorString(index),
3164 core->toErrorString(pool->constantStringCount));
3165 }
3166
3167 void Verifier::checkNameOperand(uint32_t index)
3168 {
3169 if (!index || index >= pool->cpool_mn_offsets.length())
3170 verifyFailed(kCpoolIndexRangeError, core->toErrorString(index),
3171 core->toErrorString(pool->cpool_mn_offsets.length()));
3172 }
3173
3174 void Verifier::checkConstantMultiname(uint32_t index, Multiname& m)
3175 {
3176 checkNameOperand(index);
3177 pool->parseMultiname(m, index);
3178 }
3179
3180 Binding Verifier::findMathFunction(TraitsBindingsp math, const Multiname& multiname, Binding b, int argc)
3181 {
3182 Stringp newname = core->internString(core->concatStrings(core->kUnderscore, multiname.getName()));
3183 Binding newb = math->findBinding(newname);
3184 if (AvmCore::isMethodBinding(newb))
3185 {
3186 int disp_id = AvmCore::bindingToMethodId(newb);
3187 MethodInfo* newf = math->getMethod(disp_id);
3188 MethodSignaturep newfms = newf->getMethodSignature();
3189 const int param_count = newfms->param_count();
3190 if (argc == param_count)
3191 {
3192 for (int i=state->stackDepth-argc, n=state->stackDepth; i < n; i++)
3193 {
3194 Traits* t = state->stackValue(i).traits;
3195 if (!t || !t->isNumeric())
3196 return b;
3197 }
3198 b = newb;
3199 }
3200 }
3201 return b;
3202 }
3203
3204 Binding Verifier::findStringFunction(TraitsBindingsp str, const Multiname& multiname, Binding b, int argc)
3205 {
3206 Stringp newname = core->internString(core->concatStrings(core->kUnderscore, multiname.getName()));
3207 Binding newb = str->findBinding(newname);
3208 if (AvmCore::isMethodBinding(newb))
3209 {
3210 int disp_id = AvmCore::bindingToMethodId(newb);
3211 MethodInfo* newf = str->getMethod(disp_id);
3212 // We have all required parameters but not more than required.
3213 MethodSignaturep newfms = newf->getMethodSignature();
3214 const int param_count = newfms->param_count();
3215 const int optional_count = newfms->optional_count();
3216 if ((argc >= (param_count - optional_count)) && (argc <= param_count))
3217 {
3218 for (int i=state->stackDepth-argc, k = 1, n=state->stackDepth; i < n; i++, k++)
3219 {
3220 Traits* t = state->stackValue(i).traits;
3221 if (t != newfms->paramTraits(k))
3222 return b;
3223 }
3224 b = newb;
3225 }
3226 }
3227 return b;
3228 }
3229
3230#ifndef SIZE_T_MAX(2147483647L *2UL +1UL)
3231# ifdef SIZE_MAX4294967295U
3232# define SIZE_T_MAX(2147483647L *2UL +1UL) SIZE_MAX4294967295U
3233# else
3234# define SIZE_T_MAX(2147483647L *2UL +1UL) UINT_MAX(2147483647 *2U +1U)
3235# endif
3236#endif
3237
3238 void Verifier::parseExceptionHandlers()
3239 {
3240 if (info->abc_exceptions()) {
3241 AvmAssert(tryFrom && tryTo)do { } while (0);
3242 return;
3243 }
3244
3245 const uint8_t* pos = code_pos + code_length;
3246 int exception_count = toplevel->readU30(pos); // will be nonnegative and less than 0xC0000000
3247
3248 if (exception_count != 0)
3249 {
3250 if (exception_count == 0 || (size_t)(exception_count-1) > SIZE_T_MAX(2147483647L *2UL +1UL) / sizeof(ExceptionHandler))
3251 verifyFailed(kIllegalExceptionHandlerError);
3252
3253 ExceptionHandlerTable* table = ExceptionHandlerTable::create(core->GetGC(), exception_count);
3254 ExceptionHandler *handler = table->exceptions;
3255 for (int i=0; i < exception_count; i++, handler++)
3256 {
3257 handler->from = toplevel->readU30(pos);
3258 handler->to = toplevel->readU30(pos);
3259 handler->target = toplevel->readU30(pos);
3260
3261 const uint8_t* const scopePosInPool = pos;
3262
3263 int type_index = toplevel->readU30(pos);
3264 Traits* t = type_index ? checkTypeName(type_index) : NULL__null;
3265
3266 Multiname qn;
3267 int name_index = (pool->version != (46<<16|15)) ? toplevel->readU30(pos) : 0;
3268 if (name_index != 0)
3269 {
3270 pool->parseMultiname(qn, name_index);
3271 if (!qn.isBinding()) {
3272 // abc docs specify that the name is a string but asc generates QNames.
3273 // Multinames with no namespaces could be supported, but Tamarin currently can't
3274 // handle them in this context.
3275 verifyFailed(kCorruptABCError); // the error code could be more precise
3276 }
3277 }
3278
3279 #ifdef AVMPLUS_VERBOSE
3280 if (verbose)
3281 {
3282 core->console << " exception["<<i<<"] from="<< handler->from
3283 << " to=" << handler->to
3284 << " target=" << handler->target
3285 << " type=" << t
3286 << " name=";
3287 if (name_index != 0)
3288 core->console << qn;
3289 else
3290 core->console << "(none)";
3291 core->console << "\n";
3292 }
3293 #endif
3294
3295 if (handler->from < 0 ||
3296 handler->to < handler->from ||
3297 handler->target < handler->to ||
3298 handler->target >= code_length)
3299 {
3300 // illegal range in handler record
3301 verifyFailed(kIllegalExceptionHandlerError);
3302 }
3303
3304 // save maximum try range
3305 if (!tryFrom || (code_pos + handler->from) < tryFrom)
3306 tryFrom = code_pos + handler->from;
3307 if (code_pos + handler->to > tryTo)
3308 tryTo = code_pos + handler->to;
3309
3310 // note: since we require (code_len > target >= to >= from >= 0),
3311 // all implicit exception edges are forward edges.
3312
3313 // handler->traits = t
3314 WB(core->GetGC(), table, &handler->traits, t)core->GetGC()->privateWriteBarrier(table, &handler->
traits, (const void *) (t))
;
3315
3316 Traits* scopeTraits = name_index == 0 ? OBJECT_TYPE(core->traits.object_itraits) :
3317 Traits::newCatchTraits(toplevel, pool, scopePosInPool, qn.getName(), qn.getNamespace());
3318
3319 // handler->scopeTraits = scopeTraits
3320 WB(core->GetGC(), table, &handler->scopeTraits, scopeTraits)core->GetGC()->privateWriteBarrier(table, &handler->
scopeTraits, (const void *) (scopeTraits))
;
3321 }
3322
3323 info->set_abc_exceptions(core->GetGC(), table);
3324 }
3325 else
3326 {
3327 info->set_abc_exceptions(core->GetGC(), NULL__null);
3328 }
3329 }
3330
3331 #ifdef AVMPLUS_VERBOSE
3332 void Verifier::printOpcode(const uint8_t* pc, const uint8_t* code_end)
3333 {
3334 int offset = int(pc - code_pos);
3335 core->console << " " << offset << ':';
3336 core->formatOpcode(core->console, pc, code_end, (AbcOpcode)*pc, offset, pool);
3337 core->console << '\n';
3338 }
3339
3340 /**
3341 * display contents of current stack frame only.
3342 */
3343 void Verifier::printState(StringBuffer& prefix, FrameState *state)
3344 {
3345 PrintWriter& out = core->console;
3346 if (prefix.length() > 0) {
3347 char buf[80]; // plenty for currently known prefixes
3348 VMPI_sprintf::sprintf(buf, "%-23s[", prefix.c_str());
3349 out << buf;
3350 } else {
3351 out << " [";
3352 }
3353
3354 // locals
3355 int scope_base = ms->scope_base();
3356 for (int i=0, n = scope_base; i < n; i++) {
3357 printValue(state->value(i));
3358 if (i+1 < n)
3359 out << ' ';
3360 }
3361 out << "] {";
3362
3363 // scope chain
3364 for (int i = scope_base, n = scope_base + state->scopeDepth; i < n; i++) {
3365 printValue(state->value(i));
3366 if (i+1 < n)
3367 out << ' ';
3368 }
3369 out << "} (";
3370
3371 // stack
3372 int stackStart;
3373 const int stackLimit = 20; // don't display more than this, to reduce verbosity
3374 if (state->stackDepth > stackLimit) {
3375 stackStart = ms->stack_base() + state->stackDepth - stackLimit;
3376 out << "..." << stackStart << ": ";
3377 } else {
3378 stackStart = ms->stack_base();
3379 }
3380 for (int i = stackStart, n = ms->stack_base() + state->stackDepth; i < n; i++) {
3381 printValue(state->value(i));
3382 if (i+1 < n)
3383 out << ' ';
3384 }
3385 out << ")\n";
3386 }
3387
3388 /** display contents of a captured scope chain */
3389 void Verifier::printScope(const char* title, const ScopeTypeChain* scope)
3390 {
3391 PrintWriter& out = core->console;
3392 out << " " << title << " = ";
3393 if (scope && scope->size > 0) {
3394 out << '[';
3395 for (int i=0, n=scope->size; i < n; i++) {
3396 Traits* t = scope->getScopeTraitsAt(i);
3397 if (!t)
3398 out << "*!";
3399 else
3400 out << t;
3401 if (i+1 < n)
3402 out << ' ';
3403 }
3404 out << "]\n";
3405 } else {
3406 out << "null\n";
3407 }
3408 }
3409
3410 void Verifier::printValue(FrameValue& v)
3411 {
3412 Traits* t = v.traits;
3413 PrintWriter& out = core->console;
3414 out << t;
3415 if (!t || (!t->isNumeric() && t != BOOLEAN_TYPE(core->traits.boolean_itraits) && t != NULL_TYPE(core->traits.null_itraits) && t != VOID_TYPE(core->traits.void_itraits)))
3416 out << (v.notNull ? "~" : "");
3417
3418#ifdef VMCFG_NANOJIT
3419 if (v.sst_mask) {
3420 out << '[';
3421 if (v.sst_mask & (1 << SST_atom)) out << 'A';
3422 if (v.sst_mask & (1 << SST_string)) out << 'S';
3423 if (v.sst_mask & (1 << SST_namespace)) out << 'N';
3424 if (v.sst_mask & (1 << SST_scriptobject)) out << 'O';
3425 if (v.sst_mask & (1 << SST_int32)) out << 'I';
3426 if (v.sst_mask & (1 << SST_uint32)) out << 'U';
3427 if (v.sst_mask & (1 << SST_bool32)) out << 'B';
3428 if (v.sst_mask & (1 << SST_double)) out << 'D';
3429 out << ']';
3430 }
3431#endif
3432 }
3433 #endif /* AVMPLUS_VERBOSE */
3434}