Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / core / MethodInfo.cpp
blob851abaa0b07366e37d100d5621464922ad28a4e4
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
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/
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.
16 * The Original Code is [Open Source Virtual Machine.].
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.
23 * Contributor(s):
24 * Adobe AS3 Team
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.
38 * ***** END LICENSE BLOCK ***** */
41 #include "avmplus.h"
43 //#define DOPROF
44 //#include "../vprof/vprof.h"
46 namespace avmplus
48 using namespace MMgc;
50 /**
51 * MethodInfo wrapper around a system-generated init method. Used when
52 * there is no init method defined in the abc; this only occurs for activation
53 * object traits and catch-block activation traits.
55 MethodInfo::MethodInfo(InitMethodStub, Traits* declTraits) :
56 _msref(declTraits->pool->core->GetGC()->emptyWeakRef),
57 _declarer(declTraits),
58 _activation(NULL),
59 _pool(declTraits->pool),
60 _abc_info_pos(NULL),
61 _method_id(-1),
62 _hasMethodBody(1),
63 _isResolved(1)
65 declTraits->core->exec->init(this, NULL);
68 #ifdef VMCFG_AOT
69 MethodInfo::MethodInfo(InitMethodStub, Traits* declTraits, const NativeMethodInfo* native_info, const AvmThunkNativeHandler& handler, int32_t method_id) :
70 MethodInfoProcHolder(),
71 _msref(declTraits->pool->core->GetGC()->emptyWeakRef),
72 _declarer(declTraits),
73 _activation(NULL),
74 _pool(declTraits->pool),
75 _abc_info_pos(NULL),
76 _method_id(method_id),
77 _hasMethodBody(1),
78 _isResolved(1)
80 AvmAssert(native_info != NULL);
81 this->_native.thunker = native_info->thunker;
82 this->setAotCompiled(handler);
84 declTraits->core->exec->init(this, native_info);
86 #endif
88 /**
89 * ordinary MethodInfo for abc or native method.
91 MethodInfo::MethodInfo(int32_t method_id,
92 PoolObject* pool,
93 const uint8_t* abc_info_pos,
94 uint8_t abcFlags,
95 const NativeMethodInfo* native_info) :
96 _msref(pool->core->GetGC()->emptyWeakRef),
97 _declarer(NULL),
98 _activation(NULL),
99 _pool(pool),
100 _abc_info_pos(abc_info_pos),
101 _method_id(method_id),
102 _needArguments((abcFlags & abcMethod_NEED_ARGUMENTS) != 0),
103 _needActivation((abcFlags & abcMethod_NEED_ACTIVATION) != 0),
104 _needRest((abcFlags & abcMethod_NEED_REST) != 0),
105 _hasOptional((abcFlags & abcMethod_HAS_OPTIONAL) != 0),
106 _ignoreRest((abcFlags & abcMethod_IGNORE_REST) != 0),
107 _isNative((abcFlags & abcMethod_NATIVE) != 0),
108 _setsDxns((abcFlags & abcMethod_SETS_DXNS) != 0),
109 _hasParamNames((abcFlags & abcMethod_HAS_PARAM_NAMES) != 0),
110 _hasMethodBody(1) // assume we have bytecode body until set otherwise
112 AvmAssert(method_id >= 0);
114 if (native_info)
116 _needsCodeContext = 1;
117 _needsDxns = 1;
118 _hasMethodBody = 0;
120 pool->core->exec->init(this, native_info);
123 void MethodInfo::gcTraceHook_MethodInfo(MMgc::GC* gc)
125 if (_isNative) {
126 // _native - nothing to do
128 else {
129 gc->TraceLocation(&_abc.exceptions);
130 #ifdef VMCFG_WORDCODE
131 gc->TraceLocation(&_abc.word_code.translated_code);
132 gc->TraceLocation(&_abc.word_code.exceptions);
133 #endif
137 void MethodInfo::init_activationTraits(Traits* t)
139 AvmAssert(_activation.getTraits() == NULL);
140 _activation.setTraits(pool()->core->GetGC(), this, t);
143 void MethodInfo::init_activationScope(const ScopeTypeChain* scope)
145 AvmAssert(!_activation.hasScope());
146 _activation.setScope(pool()->core->GetGC(), this, scope);
149 REALLY_INLINE double unpack_double(const void* src)
151 #if defined(AVMPLUS_64BIT) || defined(VMCFG_UNALIGNED_FP_ACCESS)
152 return *(const double*)src;
153 #else
154 double_overlay u;
155 u.bits32[0] = ((const uint32_t*)src)[0];
156 u.bits32[1] = ((const uint32_t*)src)[1];
157 return u.value;
158 #endif
161 #ifdef DEBUGGER
162 // note that the "local" can be a true local (0..local_count-1)
163 // or an entry on the scopechain (local_count...(local_count+max_scope)-1)
164 // FIXME: this is exactly the same as makeatom() in jit-calls.h,
165 // except for the decoding of unaligned doubles
166 static Atom nativeLocalToAtom(AvmCore* core, void* src, SlotStorageType sst)
168 switch (sst)
170 case SST_double:
171 return core->doubleToAtom(unpack_double(src));
172 default:
173 AvmAssert(false);
174 case SST_int32:
175 return core->intToAtom(*(const int32_t*)src);
176 case SST_uint32:
177 return core->uintToAtom(*(const uint32_t*)src);
178 case SST_bool32:
179 return *(const int32_t*)src ? trueAtom : falseAtom;
180 case SST_atom:
181 return *(const Atom*)src;
182 case SST_string:
183 return (*(const Stringp*)src)->atom();
184 case SST_namespace:
185 return (*(const Namespacep*)src)->atom();
186 case SST_scriptobject:
187 return (*(ScriptObject**)src)->atom();
190 #endif
192 // this looks deceptively similar to nativeLocalToAtom, but is subtly different:
193 // for locals, int/uint/bool are always stored as a 32-bit value in the 4 bytes
194 // of the memory slot (regardless of wordsize and endianness);
195 // for args, int/uint/bool are always expanded to full intptr size. In practice
196 // this only makes a difference on big-endian 64-bit systems (eg PPC64) which makes
197 // it a hard bug to notice.
198 static Atom nativeArgToAtom(AvmCore* core, void* src, BuiltinType bt)
200 switch (bt)
202 case BUILTIN_number:
204 return core->doubleToAtom(unpack_double(src));
206 case BUILTIN_int:
208 return core->intToAtom((int32_t)*(const intptr_t*)src);
210 case BUILTIN_uint:
212 return core->uintToAtom((uint32_t)*(const uintptr_t*)src);
214 case BUILTIN_boolean:
216 return *(const intptr_t*)src ? trueAtom : falseAtom;
218 case BUILTIN_any:
219 case BUILTIN_object:
220 case BUILTIN_void:
222 return *(const Atom*)src;
224 case BUILTIN_string:
226 return (*(const Stringp*)src)->atom();
228 case BUILTIN_namespace:
230 return (*(const Namespacep*)src)->atom();
232 default:
234 return (*(ScriptObject**)src)->atom();
239 #ifdef DEBUGGER
241 /*static*/ DebuggerMethodInfo* DebuggerMethodInfo::create(AvmCore* core, int32_t local_count, uint32_t codeSize, int32_t max_scopes)
243 MMgc::GC* gc = core->GetGC();
244 const uint32_t extra = (local_count <= 1) ? 0 : (sizeof(Stringp)*(local_count-1));
246 DebuggerMethodInfo* dmi = new (gc, MMgc::kExact, extra) DebuggerMethodInfo(local_count, codeSize, max_scopes);
247 const Stringp undef = core->kundefined;
248 for (int32_t i=0; i<local_count; i++)
250 WBRC(gc, dmi, &dmi->localNames[i], undef);
252 return dmi;
255 AbcFile* MethodInfo::file() const
257 DebuggerMethodInfo* dmi = this->dmi();
258 return dmi ? (AbcFile*)(dmi->file) : NULL;
261 int32_t MethodInfo::firstSourceLine() const
263 DebuggerMethodInfo* dmi = this->dmi();
264 return dmi ? dmi->firstSourceLine : 0;
267 int32_t MethodInfo::lastSourceLine() const
269 DebuggerMethodInfo* dmi = this->dmi();
270 return dmi ? dmi->lastSourceLine : 0;
273 int32_t MethodInfo::offsetInAbc() const
275 DebuggerMethodInfo* dmi = this->dmi();
276 return dmi ? dmi->offsetInAbc : 0;
279 uint32_t MethodInfo::codeSize() const
281 DebuggerMethodInfo* dmi = this->dmi();
282 return dmi ? dmi->codeSize : 0;
285 int32_t MethodInfo::local_count() const
287 DebuggerMethodInfo* dmi = this->dmi();
288 return dmi ? dmi->local_count : 0;
291 int32_t MethodInfo::max_scopes() const
293 DebuggerMethodInfo* dmi = this->dmi();
294 return dmi ? dmi->max_scopes : 0;
297 void MethodInfo::setFile(AbcFile* file)
299 DebuggerMethodInfo* dmi = this->dmi();
300 if (dmi)
301 dmi->file = file;
304 Stringp MethodInfo::getArgName(int32_t index)
306 return getRegName(index);
309 Stringp MethodInfo::getLocalName(int32_t index)
311 return getRegName(index+getMethodSignature()->param_count());
314 void MethodInfo::updateSourceLines(int32_t linenum, int32_t offset)
316 DebuggerMethodInfo* dmi = this->dmi();
317 if (dmi)
319 if (dmi->firstSourceLine == 0 || linenum < dmi->firstSourceLine)
320 dmi->firstSourceLine = linenum;
322 if (dmi->offsetInAbc == 0 || offset < dmi->offsetInAbc)
323 dmi->offsetInAbc = offset;
325 if (dmi->lastSourceLine == 0 || linenum > dmi->lastSourceLine)
326 dmi->lastSourceLine = linenum;
330 // Note: dmi() can legitimately return NULL (for MethodInfo's that were synthesized by Traits::genInitBody,
331 // or for MethodInfo's that have no body, e.g. interface methods).
332 DebuggerMethodInfo* MethodInfo::dmi() const
334 // rely on the fact that not-in-pool MethodInfo returns -1,
335 // which will always be > methodCount as uint32_t
336 const uint32_t method_id = uint32_t(this->method_id());
337 AvmAssert(_pool->core->debugger() != NULL);
338 // getDebuggerMethodInfo quietly returns NULL for out-of-range.
339 return _pool->getDebuggerMethodInfo(method_id);
342 Stringp MethodInfo::getRegName(int32_t slot) const
344 DebuggerMethodInfo* dmi = this->dmi();
346 if (dmi && slot >= 0 && slot < dmi->local_count)
347 return dmi->localNames[slot];
349 return this->pool()->core->kundefined;
352 void MethodInfo::setRegName(int32_t slot, Stringp name)
354 DebuggerMethodInfo* dmi = this->dmi();
356 if (!dmi || slot < 0 || slot >= dmi->local_count)
357 return;
359 AvmCore* core = this->pool()->core;
361 // [mmorearty 5/3/05] temporary workaround for bug 123237: if the register
362 // already has a name, don't assign a new one
363 if (dmi->localNames[slot] != core->kundefined)
364 return;
366 WBRC(core->GetGC(), dmi, &dmi->localNames[slot], core->internString(name));
369 // note that the "local" can be a true local (0..local_count-1)
370 // or an entry on the scopechain (local_count...(local_count+max_scope)-1)
371 Atom MethodInfo::boxOneLocal(FramePtr src, int32_t srcPos, const uint8_t* sstArr)
373 // if we are running jit then the types are native and we need to box them.
374 if (_isJitImpl)
376 src = FramePtr(uintptr_t(src) + srcPos * VARSIZE);
377 AvmAssert(sstArr != NULL);
378 return nativeLocalToAtom(this->pool()->core, src, (SlotStorageType)sstArr[srcPos]);
380 else
382 AvmAssert(sstArr == NULL);
383 src = FramePtr(uintptr_t(src) + srcPos*sizeof(Atom));
384 return *(const Atom*)src;
390 * convert ap[start]...ap[start+count-1] entries from their native types into
391 * Atoms. The result is placed into out[to]...out[to+count-1].
393 * The traitArr is used to determine the type of conversion that should take place.
394 * traitArr[start]...traitArr[start+count-1] are used.
396 * If the method is interpreted then we just copy the Atom, no conversion is needed.
398 void MethodInfo::boxLocals(FramePtr src, int32_t srcPos, const uint8_t* sstArr, Atom* dest, int32_t destPos, int32_t length)
400 for (int32_t i = srcPos, n = srcPos+length; i < n; i++)
402 #ifdef VMCFG_AOT
403 AvmAssert(i >= 0 && (dmi() == NULL || i < local_count()));
404 #else
405 AvmAssert(i >= 0 && i < getMethodSignature()->local_count());
406 #endif
407 dest[destPos++] = boxOneLocal(src, i, sstArr);
412 // note that the "local" can be a true local (0..local_count-1)
413 // or an entry on the scopechain (local_count...(local_count+max_scope)-1)
414 void MethodInfo::unboxOneLocal(Atom src, FramePtr dst, int32_t dstPos, const uint8_t* sstArr)
416 if (_isJitImpl)
418 AvmAssert(sstArr != NULL);
419 dst = FramePtr(uintptr_t(dst) + dstPos * VARSIZE);
420 switch ((SlotStorageType)sstArr[dstPos])
422 case SST_double:
424 *(double*)dst = AvmCore::number_d(src);
425 break;
427 case SST_int32:
429 *(int32_t*)dst = AvmCore::integer_i(src);
430 break;
432 case SST_uint32:
434 *(uint32_t*)dst = AvmCore::integer_u(src);
435 break;
437 case SST_bool32:
439 *(int32_t*)dst = (int32_t)atomGetBoolean(src);
440 break;
442 case SST_atom:
444 *(Atom*)dst = src;
445 break;
447 default: // SST_string, SST_namespace, SST_scriptobject
449 // ScriptObject, String, Namespace, or Null
450 *(void**)dst = atomPtr(src);
451 break;
455 else
457 AvmAssert(sstArr == NULL);
458 dst = FramePtr(uintptr_t(dst) + dstPos*sizeof(Atom));
459 *(Atom*)dst = src;
464 * convert in[0]...in[count-1] entries from Atoms to native types placing them
465 * in ap[start]...out[start+count-1].
467 * The traitArr is used to determine the type of conversion that should take place.
468 * traitArr[start]...traitArr[start+count-1] are used.
470 * If the method is interpreted then we just copy the Atom, no conversion is needed.
472 void MethodInfo::unboxLocals(const Atom* src, int32_t srcPos, const uint8_t* sstArr, FramePtr dest, int32_t destPos, int32_t length)
474 for (int32_t i = destPos, n = destPos+length; i < n; i++)
476 #ifdef VMCFG_AOT
477 AvmAssert(i >= 0 && (dmi() == NULL || i < local_count()));
478 #else
479 AvmAssert(i >= 0 && i < getMethodSignature()->local_count());
480 #endif
481 unboxOneLocal(src[srcPos++], dest, i, sstArr);
485 #endif //DEBUGGER
487 #ifdef AVMPLUS_VERBOSE
488 PrintWriter& MethodInfo::print(PrintWriter& prw) const
490 String* n = getMethodName();
491 return n ? prw << n << "()"
492 : prw << "?()";
494 #endif // AVMPLUS_VERBOSE
496 bool MethodInfo::makeMethodOf(Traits* traits)
498 AvmAssert(!isResolved());
499 // begin AVMPLUS_UNCHECKED_HACK
500 AvmAssert(!_isProtoFunc);
501 // end AVMPLUS_UNCHECKED_HACK
503 _hasMakeMethodOfBeenCalled = 1;
505 if (_declarer.getTraits() == NULL)
507 _declarer.setTraits(pool()->core->GetGC(), this, traits);
508 _needClosure = 1;
509 return true;
511 else
513 #ifdef AVMPLUS_VERBOSE
514 if (pool()->isVerbose(VB_parse))
515 pool()->core->console << "WARNING: method " << this << " was already bound to " << declaringTraits() << "\n";
516 #endif
518 return false;
522 void MethodInfo::makeIntoPrototypeFunction(const Toplevel* toplevel, const ScopeTypeChain* fscope)
524 // Once a MethodInfo has been made a method of a particular class,
525 // it is an error to attempt to use it for OP_newfunction; we may have
526 // jitted code with the method and made early-binding assumptions about the
527 // receiver type that this would invalidate (by allowing us to call the method
528 // with a different type of object).
529 if (_hasMakeMethodOfBeenCalled)
530 toplevel->throwVerifyError(kCorruptABCError);
532 AvmAssert(_declarer.getScope() == NULL);
534 _declarer.setScope(toplevel->core()->GetGC(), this, fscope);
536 // begin AVMPLUS_UNCHECKED_HACK
537 this->_isProtoFunc = 1;
538 // end AVMPLUS_UNCHECKED_HACK
540 // make sure param & return types are fully resolved.
541 // this does not set the verified flag, so real verification will
542 // still happen before the function runs the first time.
543 resolveSignature(toplevel);
547 * convert native args to atoms. argc is the number of
548 * args, not counting the instance which is arg[0]. the
549 * layout is [instance][arg1..argN]
551 void MethodSignature::boxArgs(AvmCore* core, int32_t argc, const uint32_t* ap, Atom* out) const
553 MMGC_STATIC_ASSERT(sizeof(Atom) == sizeof(void*)); // if this ever changes, this function needs smartening
554 typedef const Atom* ConstAtomPtr;
555 // box the typed args, up to param_count
556 const int32_t param_count = this->param_count();
557 for (int32_t i=0; i <= argc; i++)
559 const BuiltinType bt = (i <= param_count) ? this->paramTraitsBT(i) : BUILTIN_any;
560 out[i] = nativeArgToAtom(core, (void*)ap, bt);
561 ap += (bt == BUILTIN_number ? sizeof(double) : sizeof(Atom)) / sizeof(int32_t);
565 MethodSignature* FASTCALL MethodInfo::_buildMethodSignature(const Toplevel* toplevel)
567 PoolObject* pool = this->pool();
568 AvmCore* core = pool->core;
569 GC* gc = core->GetGC();
571 const uint8_t* pos = this->_abc_info_pos;
572 const uint32_t param_count = pos ? AvmCore::readU32(pos) : 0;
573 uint32_t optional_count = 0;
574 uint32_t rest_offset = 0;
575 Traits* returnType;
576 Traits* receiverType;
578 // we only need param_count+optional_count extra, but we don't know
579 // optional_count yet, so over-allocate for the worst case. (we know optional_count<=param_count).
580 // this wastes space, but since we only cache a few dozen of these, it's preferable to walking the data twice
581 // to get an exact count.
583 // It is /critical/ to correct exact tracing of the MethodSignature that param_count is written
584 // into the object before any types are written into _args, and that optional_count is written
585 // into the object before any default values are written into _args.
587 const uint32_t extra = sizeof(MethodSignature::AtomOrType) * (param_count + (hasOptional() ? param_count : 0));
588 MethodSignature* ms = MethodSignature::create(gc, extra, param_count);
590 if (pos)
592 returnType = pool->resolveTypeName(pos, toplevel, /*allowVoid=*/true);
593 receiverType = _needClosure ? declaringTraits() : core->traits.object_itraits;
594 rest_offset = argSize(receiverType);
595 // begin AVMPLUS_UNCHECKED_HACK
596 uint32_t untyped_args = 0;
597 // end AVMPLUS_UNCHECKED_HACK
598 for (uint32_t i=1; i <= param_count; i++)
600 Traits* argType = pool->resolveTypeName(pos, toplevel);
601 WB(gc, ms, &ms->_args[i].paramType, argType);
602 rest_offset += argSize(argType);
603 // begin AVMPLUS_UNCHECKED_HACK
604 untyped_args += (argType == NULL);
605 // end AVMPLUS_UNCHECKED_HACK
607 AvmCore::skipU32(pos); // name_index;
608 pos++; // abcFlags;
609 // begin AVMPLUS_UNCHECKED_HACK
610 if (untyped_args == param_count)
611 _onlyUntypedParameters = 1;
612 // toplevel!=NULL check is so we only check when resolveSignature calls us (not subsequently)
613 if (toplevel != NULL && _isProtoFunc)
615 // HACK - compiler should do this, and only to toplevel functions
616 // that meet the E4 criteria for being an "unchecked function"
617 // the tests below are too loose
619 // if all params and return types are Object then make all params optional=undefined
620 if (param_count == 0)
621 _ignoreRest = 1;
622 if (!hasOptional() && returnType == NULL && param_count > 0 && untyped_args == param_count)
624 _hasOptional = 1;
625 _ignoreRest = 1;
626 _isUnchecked = 1;
627 // oops -- the ms we allocated is too small, has no space for optional values
628 // but it's easy to re-create, especially since we know the types are all null
629 const uint32_t extra = sizeof(MethodSignature::AtomOrType) * (param_count + param_count);
630 ms = MethodSignature::create(gc, extra, param_count);
631 // don't need to re-set paramTypes: they are inited to NULL which is the right value
634 if (_isUnchecked)
636 optional_count = param_count;
637 ms->_optional_count = optional_count;
638 for (uint32_t j=0; j < optional_count; j++)
640 //WBATOM(gc, ms, &ms->_args[param_count+1+j].defaultValue, undefinedAtom);
641 // since we know we're going from NULL->undefinedAtom we can skip the WBATOM call
642 ms->_args[param_count+1+j].defaultValue = undefinedAtom;
645 else
646 // end AVMPLUS_UNCHECKED_HACK
647 if (hasOptional())
649 optional_count = AvmCore::readU32(pos);
650 ms->_optional_count = optional_count;
651 for (uint32_t j=0; j < optional_count; j++)
653 const int32_t param = param_count-optional_count+1+j;
654 const int32_t index = AvmCore::readU32(pos);
655 CPoolKind kind = (CPoolKind)*pos++;
657 // check that the default value is legal for the param type
658 Traits* argType = ms->_args[param].paramType;
659 const Atom value = pool->getLegalDefaultValue(toplevel, index, kind, argType);
660 WBATOM(gc, ms, &ms->_args[param_count+1+j].defaultValue, value);
664 if (!isNative())
666 const uint8_t* body_pos = this->abc_body_pos();
667 if (body_pos)
669 ms->_max_stack = AvmCore::readU32(body_pos);
670 ms->_local_count = AvmCore::readU32(body_pos);
671 const int32_t init_scope_depth = AvmCore::readU32(body_pos);
672 ms->_max_scope = AvmCore::readU32(body_pos) - init_scope_depth;
673 #ifdef VMCFG_WORDCODE
674 #else
675 ms->_abc_code_start = body_pos;
676 AvmCore::skipU32(ms->_abc_code_start); // code_length
677 #endif
681 else
683 // this is a synthesized MethodInfo from genInitBody
684 AvmAssert(param_count == 0);
685 rest_offset = sizeof(Atom);
686 returnType = pool->core->traits.void_itraits;
687 receiverType = declaringTraits();
688 // values derived from Traits::genInitBody()
689 const int32_t max_stack = 2;
690 const int32_t local_count = 1;
691 const int32_t init_scope_depth = 1;
692 const int32_t max_scope_depth = 1;
693 ms->_max_stack = max_stack;
694 ms->_local_count = local_count;
695 ms->_max_scope = max_scope_depth - init_scope_depth;
696 #if defined(VMCFG_WORDCODE) || defined(VMCFG_AOT)
697 #else
698 ms->_abc_code_start = this->abc_body_pos();
699 AvmCore::skipU32(ms->_abc_code_start, 5);
700 #endif
702 ms->_frame_size = ms->_local_count + ms->_max_scope + ms->_max_stack;
703 #ifndef AVMPLUS_64BIT
704 // The interpreter wants this to be padded to a doubleword boundary because
705 // it allocates two objects in a single alloca() request - the frame and
706 // auxiliary storage, in that order - and wants the second object to be
707 // doubleword aligned.
708 ms->_frame_size = (ms->_frame_size + 1) & ~1;
709 #endif
710 // _param_count and _optional_count were written earlier for reasons of GC correctness
711 //ms->_param_count = param_count;
712 //ms->_optional_count = optional_count;
713 ms->_rest_offset = rest_offset;
714 ms->_isNative = this->_isNative;
715 ms->_allowExtraArgs = this->_needRest || this->_needArguments || this->_ignoreRest;
716 WB(gc, ms, &ms->_returnTraits, returnType);
717 WB(gc, ms, &ms->_args[0].paramType, receiverType);
719 AvmAssert(_msref->isNull());
720 _msref = ms->GetWeakRef();
721 core->msCache()->add(ms);
722 return ms;
725 MethodSignature* FASTCALL MethodInfo::_getMethodSignature()
727 AvmAssert(this->isResolved());
728 // note: MethodSignaturep are always built the first time in resolveSignature; this is only
729 // executed for subsequent re-buildings. Thus we pass NULL for toplevel (it's only used
730 // for verification errors, but those will have been caught prior to this) and for
731 // abcGen and imtBuilder (since those only need to be done once).
732 MethodSignature* ms = _buildMethodSignature(NULL);
733 return ms;
736 void MethodInfo::update_max_stack(int32_t max_stack)
738 MethodSignature* ms = (MethodSignature*)_msref->get();
739 if (ms)
741 ms->_max_stack = max_stack;
745 uint32_t MethodInfo::parse_code_length() const
747 // Parse the code length out of ABC sice it is not stored elsewhere.
748 const uint8_t* pos = abc_body_pos();
749 AvmCore::skipU32(pos, 4);
750 return AvmCore::readU32(pos);
753 void MethodInfo::resolveSignature(const Toplevel* toplevel)
755 if (!isResolved())
757 MethodSignature* ms = _buildMethodSignature(toplevel);
759 if (!isNative())
761 if (ms->frame_size() < 0 || ms->local_count() < 0 || ms->max_scope() < 0)
762 toplevel->throwVerifyError(kCorruptABCError);
765 if (ms->paramTraits(0) != NULL && ms->paramTraits(0)->isInterface())
766 _hasMethodBody = 0;
768 _isResolved = 1;
769 pool()->core->exec->notifyMethodResolved(this, ms);
773 #ifdef DEBUGGER
774 uint64_t MethodInfo::bytesUsed()
776 uint64_t size = sizeof(MethodInfo);
777 size += getMethodSignature()->param_count() * 2 * sizeof(Atom);
778 size += codeSize();
779 return size;
781 #endif
783 bool MethodInfo::usesCallerContext() const
785 return pool()->isBuiltin && (!_isNative || _needsCodeContext);
788 // Builtin + non-native functions always need the dxns code emitted
789 // Builtin + native functions have flags to specify if they need the dxns code
790 bool MethodInfo::usesDefaultXmlNamespace() const
792 return pool()->isBuiltin && (!_isNative || _needsDxns);
795 bool MethodInfo::isTrivial()
797 if (_isTrivial)
798 return true;
799 if (_isNonTrivial)
800 return false;
801 bool trivial = computeIsTrivial();
802 if (trivial)
803 _isTrivial = 1;
804 else
805 _isNonTrivial = 1;
806 return trivial;
809 // Compute a conservative approximation to triviality. It is possible to
810 // do better. For example, IFTRUE and IFFALSE don't throw exceptions but
811 // termination is assured only if all branches are forward; also, RETURNVALUE
812 // is acceptable if data flow and type analyses shows that the returned value
813 // will not trigger a coercion exception. (That's true for many instructions
814 // generally.)
816 bool MethodInfo::computeIsTrivial()
818 #ifdef VMCFG_AOT
819 return false;
820 #else
821 // Initial attribute guard:
823 // _needRest and _needArguments are here because they invoke
824 // the Array constructor, ie, they may update system state.
826 // _isNative and _hasMethodBody are here because those methods have
827 // no bytecode, and this computation is bytecode-based.
829 // _setsDxns is here because the "default xml namespace" semantics
830 // are wild & crazy and some testing suggests that all bets are
831 // off when using it. (Belt and suspenders, belt and suspenders...)
833 // _needActivation is here mostly as a shortcut; it will usually pair
834 // with NEWACTIVATION and GETPROPERTY and so on, and so the method will
835 // be tossed out anyway.
836 if (_needActivation ||
837 _needRest ||
838 _needArguments ||
839 _isNative ||
840 _setsDxns ||
841 !_hasMethodBody)
842 return false;
844 const uint8_t* pc = _abc.body_pos;
845 AvmCore::skipU32(pc, 4);
846 uint32_t code_length = AvmCore::readU32(pc);
847 const uint8_t* code_end = pc + code_length;
849 while (pc < code_end) {
850 const uint8_t* nextpc = pc;
851 uint32_t imm30=0, imm30b=0;
852 int32_t imm8=0, imm24=0;
854 AbcOpcode opcode = (AbcOpcode) *pc;
855 AvmCore::readOperands(nextpc, imm30, imm24, imm30b, imm8);
857 // We may want to fold this logic into the table in ActionBlockConstants.cpp
858 // rather than having a dedicated switch.
860 switch (opcode) {
861 case OP_nop:
862 case OP_kill:
863 case OP_label:
864 case OP_popscope:
865 case OP_pushnull:
866 case OP_pushundefined:
867 case OP_pushbyte:
868 case OP_pushshort:
869 case OP_pushtrue:
870 case OP_pushfalse:
871 case OP_pushnan:
872 case OP_pop:
873 case OP_dup:
874 case OP_swap:
875 case OP_pushstring:
876 case OP_pushint:
877 case OP_pushuint:
878 case OP_pushdouble:
879 case OP_pushscope:
880 case OP_pushnamespace:
881 case OP_returnvoid:
882 case OP_getlocal:
883 case OP_getlocal0:
884 case OP_getlocal1:
885 case OP_getlocal2:
886 case OP_getlocal3:
887 case OP_setlocal:
888 case OP_setlocal0:
889 case OP_setlocal1:
890 case OP_setlocal2:
891 case OP_setlocal3:
892 case OP_getglobalscope:
893 case OP_getscopeobject:
894 case OP_getouterscope:
895 case OP_getglobalslot:
896 case OP_typeof:
897 case OP_not:
898 pc = nextpc;
899 break;
900 case OP_bkpt:
901 case OP_debug:
902 case OP_debugline:
903 case OP_debugfile:
904 case OP_bkptline:
905 case OP_timestamp:
906 #ifdef DEBUGGER
907 // Debugging instructions are nontrivial if the debugger
908 // is present, we don't want to confuse the programmer.
909 if (pool()->core->debugger() != NULL)
910 return false;
911 #endif
912 pc = nextpc;
913 break;
914 default:
915 return false;
918 return true;
919 #endif
922 bool MethodInfo::isConstructor() const
924 return declaringTraits()->init == this;
927 Stringp MethodInfo::getMethodName(bool includeAllNamespaces) const
929 Stringp methodName = NULL;
931 #ifdef AVMPLUS_SAMPLER
932 // We cache method names, because the profiler requests them over and
933 // over. (Bug 2547382)
934 methodName = _methodName;
935 #endif
937 if (!methodName)
939 Traits* declaringTraits = this->declaringTraits();
941 methodName = getMethodNameWithTraits(declaringTraits, includeAllNamespaces);
943 #ifdef AVMPLUS_SAMPLER
944 Sampler* sampler = declaringTraits ? declaringTraits->core->get_sampler() : NULL;
945 if (sampler && sampler->sampling())
946 _methodName = methodName;
947 #endif
950 return methodName;
953 Stringp MethodInfo::getMethodNameWithTraits(Traits* t, bool includeAllNamespaces) const
955 Stringp name = NULL;
956 const int32_t method_id = this->method_id();
958 PoolObject* pool = this->pool();
959 AvmCore* core = pool->core;
960 if (core->config.methodNames)
962 name = pool->getMethodInfoName(method_id);
963 if (name && name->length() == 0)
965 name = core->kanonymousFunc;
968 if (t)
970 StringBuffer sb(core);
971 t->print(sb, includeAllNamespaces);
972 Stringp tname = sb.toString();
973 if (core->config.oldVectorMethodNames)
975 // Tamarin used to incorrectly return the internal name of these
976 // Vector types rather than the "official" name due to initialization
977 // order. Names on the left are "more correct" but old builds might
978 // require the "classic" name for compatibility purposes, so check.
979 struct NameMapRec { const char* n; const char* o; };
980 static const NameMapRec kNameMap[4] =
982 { "Vector.<Number>", "Vector$double" },
983 { "Vector.<int>", "Vector$int" },
984 { "Vector.<uint>", "Vector$uint" },
985 { "Vector.<*>", "Vector$object" },
987 for (int32_t i = 0; i < 4; ++i)
989 if (tname->equalsLatin1(kNameMap[i].n))
991 tname = core->newConstantStringLatin1(kNameMap[i].o);
992 break;
997 if (this == t->init)
999 // careful, name could be null, that's ok for init methods
1000 if (t->posType() == TRAITSTYPE_SCRIPT)
1002 name = tname->appendLatin1("$init");
1004 else if (t->posType() == TRAITSTYPE_CLASS)
1006 name = tname->appendLatin1("cinit");
1008 else
1010 AvmAssert(t->isInstanceType() || t->isActivationTraits());
1011 name = tname;
1014 else if (name)
1016 const char* sep;
1017 if (_isGetter)
1018 sep = "/get ";
1019 else if (_isSetter)
1020 sep = "/set ";
1021 else
1022 sep = "/";
1023 name = tname->appendLatin1(sep)->append(name);
1028 // if config.methodNames isn't set, might as well still return a non-null result
1029 if (name == NULL)
1030 name = core->concatStrings(core->newConstantStringLatin1("MethodInfo-"), core->intToString(method_id));
1032 return name;
1035 void MethodSignature::gcTraceHook_MethodSignature(MMgc::GC* gc)
1037 int32_t numitems = 1+_param_count+_optional_count;
1038 for ( int32_t i=0 ; i < numitems ; i++ ) {
1039 if (atomKind(_args[i].defaultValue) == 0)
1040 gc->TraceLocation(&_args[i].paramType);