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
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.
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 ***** */
44 //#include "../vprof/vprof.h"
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
),
59 _pool(declTraits
->pool
),
65 declTraits
->core
->exec
->init(this, NULL
);
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
),
74 _pool(declTraits
->pool
),
76 _method_id(method_id
),
80 AvmAssert(native_info
!= NULL
);
81 this->_native
.thunker
= native_info
->thunker
;
82 this->setAotCompiled(handler
);
84 declTraits
->core
->exec
->init(this, native_info
);
89 * ordinary MethodInfo for abc or native method.
91 MethodInfo::MethodInfo(int32_t method_id
,
93 const uint8_t* abc_info_pos
,
95 const NativeMethodInfo
* native_info
) :
96 _msref(pool
->core
->GetGC()->emptyWeakRef
),
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);
116 _needsCodeContext
= 1;
120 pool
->core
->exec
->init(this, native_info
);
123 void MethodInfo::gcTraceHook_MethodInfo(MMgc::GC
* gc
)
126 // _native - nothing to do
129 gc
->TraceLocation(&_abc
.exceptions
);
130 #ifdef VMCFG_WORDCODE
131 gc
->TraceLocation(&_abc
.word_code
.translated_code
);
132 gc
->TraceLocation(&_abc
.word_code
.exceptions
);
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
;
155 u
.bits32
[0] = ((const uint32_t*)src
)[0];
156 u
.bits32
[1] = ((const uint32_t*)src
)[1];
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
)
171 return core
->doubleToAtom(unpack_double(src
));
175 return core
->intToAtom(*(const int32_t*)src
);
177 return core
->uintToAtom(*(const uint32_t*)src
);
179 return *(const int32_t*)src
? trueAtom
: falseAtom
;
181 return *(const Atom
*)src
;
183 return (*(const Stringp
*)src
)->atom();
185 return (*(const Namespacep
*)src
)->atom();
186 case SST_scriptobject
:
187 return (*(ScriptObject
**)src
)->atom();
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
)
204 return core
->doubleToAtom(unpack_double(src
));
208 return core
->intToAtom((int32_t)*(const intptr_t*)src
);
212 return core
->uintToAtom((uint32_t)*(const uintptr_t*)src
);
214 case BUILTIN_boolean
:
216 return *(const intptr_t*)src
? trueAtom
: falseAtom
;
222 return *(const Atom
*)src
;
226 return (*(const Stringp
*)src
)->atom();
228 case BUILTIN_namespace
:
230 return (*(const Namespacep
*)src
)->atom();
234 return (*(ScriptObject
**)src
)->atom();
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
);
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();
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();
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
)
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
)
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.
376 src
= FramePtr(uintptr_t(src
) + srcPos
* VARSIZE
);
377 AvmAssert(sstArr
!= NULL
);
378 return nativeLocalToAtom(this->pool()->core
, src
, (SlotStorageType
)sstArr
[srcPos
]);
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
++)
403 AvmAssert(i
>= 0 && (dmi() == NULL
|| i
< local_count()));
405 AvmAssert(i
>= 0 && i
< getMethodSignature()->local_count());
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
)
418 AvmAssert(sstArr
!= NULL
);
419 dst
= FramePtr(uintptr_t(dst
) + dstPos
* VARSIZE
);
420 switch ((SlotStorageType
)sstArr
[dstPos
])
424 *(double*)dst
= AvmCore::number_d(src
);
429 *(int32_t*)dst
= AvmCore::integer_i(src
);
434 *(uint32_t*)dst
= AvmCore::integer_u(src
);
439 *(int32_t*)dst
= (int32_t)atomGetBoolean(src
);
447 default: // SST_string, SST_namespace, SST_scriptobject
449 // ScriptObject, String, Namespace, or Null
450 *(void**)dst
= atomPtr(src
);
457 AvmAssert(sstArr
== NULL
);
458 dst
= FramePtr(uintptr_t(dst
) + dstPos
*sizeof(Atom
));
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
++)
477 AvmAssert(i
>= 0 && (dmi() == NULL
|| i
< local_count()));
479 AvmAssert(i
>= 0 && i
< getMethodSignature()->local_count());
481 unboxOneLocal(src
[srcPos
++], dest
, i
, sstArr
);
487 #ifdef AVMPLUS_VERBOSE
488 PrintWriter
& MethodInfo::print(PrintWriter
& prw
) const
490 String
* n
= getMethodName();
491 return n
? prw
<< n
<< "()"
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
);
513 #ifdef AVMPLUS_VERBOSE
514 if (pool()->isVerbose(VB_parse
))
515 pool()->core
->console
<< "WARNING: method " << this << " was already bound to " << declaringTraits() << "\n";
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;
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
);
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;
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)
622 if (!hasOptional() && returnType
== NULL
&& param_count
> 0 && untyped_args
== param_count
)
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
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
;
646 // end AVMPLUS_UNCHECKED_HACK
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
);
666 const uint8_t* body_pos
= this->abc_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
675 ms
->_abc_code_start
= body_pos
;
676 AvmCore::skipU32(ms
->_abc_code_start
); // code_length
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)
698 ms
->_abc_code_start
= this->abc_body_pos();
699 AvmCore::skipU32(ms
->_abc_code_start
, 5);
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;
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
);
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
);
736 void MethodInfo::update_max_stack(int32_t max_stack
)
738 MethodSignature
* ms
= (MethodSignature
*)_msref
->get();
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
)
757 MethodSignature
* ms
= _buildMethodSignature(toplevel
);
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())
769 pool()->core
->exec
->notifyMethodResolved(this, ms
);
774 uint64_t MethodInfo::bytesUsed()
776 uint64_t size
= sizeof(MethodInfo
);
777 size
+= getMethodSignature()->param_count() * 2 * sizeof(Atom
);
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()
801 bool trivial
= computeIsTrivial();
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
816 bool MethodInfo::computeIsTrivial()
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
||
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.
866 case OP_pushundefined
:
880 case OP_pushnamespace
:
892 case OP_getglobalscope
:
893 case OP_getscopeobject
:
894 case OP_getouterscope
:
895 case OP_getglobalslot
:
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
)
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
;
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
;
953 Stringp
MethodInfo::getMethodNameWithTraits(Traits
* t
, bool includeAllNamespaces
) const
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
;
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
);
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");
1010 AvmAssert(t
->isInstanceType() || t
->isActivationTraits());
1023 name
= tname
->appendLatin1(sep
)->append(name
);
1028 // if config.methodNames isn't set, might as well still return a non-null result
1030 name
= core
->concatStrings(core
->newConstantStringLatin1("MethodInfo-"), core
->intToString(method_id
));
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
);