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) 1993-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 ***** */
41 // Adobe patent application tracking #P721, entitled Application Profiling, inventors: T. Reilly
47 #include "platformbuild.h"
48 #include "avmplayer.h"
49 #include "SamplerScript.h"
56 TraceClass::TraceClass(VTable
*cvtable
)
57 : ClassClosure(cvtable
)
59 createVanillaPrototype();
62 int TraceClass::getLevel(int target
)
64 int lvl
= 0 ; /*Debugger::TRACE_OFF;*/
66 AvmCore
*core
= this->core();
70 lvl
= core
->debugger()->astrace_callback
;
72 lvl
= core
->debugger()->astrace_console
;
79 Atom
TraceClass::setLevel(int lvl
, int target
)
82 AvmCore
*core
= this->core();
86 core
->debugger()->astrace_callback
= (Debugger::TraceLevel
) lvl
;
88 core
->debugger()->astrace_console
= (Debugger::TraceLevel
) lvl
;
96 Atom
TraceClass::setListener(FunctionObject
* f
)
99 AvmCore
*core
= this->core();
100 if (core
->debugger())
102 // Listeners MUST be functions or null
103 if ( core
->isNullOrUndefined(f
->atom()) )
107 else if (!AvmCore::istype(f
->atom(), core
->traits
.function_itraits
))
109 toplevel()->argumentErrorClass()->throwError( kInvalidArgumentError
, core
->toErrorString("Function"));
110 return undefinedAtom
;
113 //MethodClosure* mc = f->toplevel()->methodClosureClass->create(f->getCallMethodEnv(), f->atom());
114 core
->debugger()->trace_callback
= f
;
116 #endif /* DEBUGGER */
118 return undefinedAtom
;
121 FunctionObject
* TraceClass::getListener()
123 FunctionObject
* f
= 0;
125 AvmCore
*core
= this->core();
126 if (core
->debugger())
127 f
= core
->debugger()->trace_callback
;
128 #endif /* DEBUGGER */
132 using namespace MMgc
;
136 class SampleIterator
: public ScriptObject
139 SampleIterator(ScriptObject
* script
, VTable
*vt
) :
140 ScriptObject(vt
, NULL
),
143 Sampler
* const sampler
= script
->core()->get_sampler();
144 sampleBufferId
= sampler
->getSampleBufferId();
145 cursor
= sampler
->getSamples(count
);
148 int nextNameIndex(int index
)
155 Sampler
* const sampler
= script
->core()->get_sampler();
156 if (sampler
== NULL
|| sampleBufferId
!= sampler
->getSampleBufferId())
158 // If the sampler is stopped
159 // while we are iterating on items
160 // the iterator should be invalidated
161 // because the Sampler::sampleBufferId is incremented
162 // each time the sample buffer is cleared.
170 Atom
nextValue(int i
)
174 return undefinedAtom
;
177 Sampler
* const sampler
= script
->core()->get_sampler();
178 if (sampler
== NULL
|| sampleBufferId
!= sampler
->getSampleBufferId())
181 return undefinedAtom
;
186 sampler
->readSample(cursor
, s
);
188 ScriptObject
* sam
= SamplerScript::makeSample(script
, cf
, s
);
191 return undefinedAtom
;
199 // they are iterating over the names, bail
201 return undefinedAtom
;
205 uint64_t sampleBufferId
;
208 DRCWB(ScriptObject
*) script
;
210 DRCWB(ClassFactoryClass
*) cf
;
213 class SlotIterator
: public ScriptObject
216 SlotIterator(Traits
*t
, VTable
*vtable
)
217 : ScriptObject(vtable
, NULL
)
218 , currTraits(t
? t
->getTraitsBindings() : NULL
)
222 int nextNameIndex(int index
)
224 while (currTraits
!= NULL
)
226 while ((index
= currTraits
->next(index
)) != 0)
231 currTraits
= currTraits
->base
;
237 Atom
nextValue(int index
)
239 Multiname
mn(currTraits
->nsAt(index
), currTraits
->keyAt(index
), true);
240 QNameObject
*qname
= QNameObject::create(gc(), toplevel()->qnameClass(), mn
);
242 return qname
->atom();
247 // they are iterating over the names, bail
249 return undefinedAtom
;
253 DWB(TraitsBindingsp
) currTraits
;
259 static VTable
* _newVT(Toplevel
* toplevel
, PoolObject
* pool
, uint16_t sz
)
261 Traits
* t
= Traits::newTraits(pool
, NULL
, sz
, 0, 0, TRAITSTYPE_RT
);
262 t
->verifyBindings(toplevel
);
263 t
->resolveSignatures(toplevel
);
264 return toplevel
->core()->newVTable(t
, NULL
, toplevel
);
268 Atom
SamplerScript::_getSamples(ScriptObject
* self
, ClassClosure
* cf
)
271 AvmCore
* core
= self
->core();
272 Sampler
*s
= core
->get_sampler();
273 if (!s
|| !s
->sampling() || s
->sampleCount() == 0 || !trusted(self
))
274 return undefinedAtom
;
276 if (s
->sampleIteratorVTable
== NULL
)
277 s
->sampleIteratorVTable
= _newVT(self
->toplevel(), self
->traits()->pool
, sizeof(SampleIterator
));
278 SampleIterator
* iter
= new (self
->gc()) SampleIterator(self
, s
->sampleIteratorVTable
);
279 iter
->cf
= (ClassFactoryClass
*)cf
;
282 (void)self
; (void)cf
;
283 return undefinedAtom
;
287 double SamplerScript::getSampleCount(ScriptObject
* self
)
290 Sampler
* s
= self
->core()->get_sampler();
303 ClassClosure
*SamplerScript::getType(Toplevel
* ss_toplevel
, SamplerObjectType sot
, const void *ptr
)
307 switch (sotGetKind(sot
))
311 // toplevel can be null here if there was no CodeContext active
312 // when the sample was taken (ie, string was allocated from C++ code).
313 // in that case, use the TL from the SamplerScript itself... it isn't
314 // technically the right one to use, but is adequate for our purposes here
315 // (it will return a stringClass or namespaceClass that will be valid
317 tl
= sotGetToplevel(sot
);
318 if (!tl
) tl
= ss_toplevel
;
319 return tl
->stringClass();
323 tl
= sotGetToplevel(sot
);
324 if (!tl
) tl
= ss_toplevel
;
325 return tl
->namespaceClass();
333 VTable
* vt
= sotGetVTable(sot
);
335 AvmCore
* core
= tl
->core();
338 ScriptObject
* obj
= (ScriptObject
*)ptr
;
339 if (obj
&& AvmCore::istype(obj
->atom(), core
->traits
.class_itraits
))
341 type
= tl
->classClass();
343 else if (obj
&& AvmCore::istype(obj
->atom(), core
->traits
.function_itraits
))
345 type
= tl
->functionClass();
347 else if (obj
&& obj
->traits()->isActivationTraits())
349 type
= tl
->objectClass
;
354 type
= tl
->objectClass
;
356 // note that note all types will have an init method,
357 // so those types may get reported as "objectClass" rather
358 // than something more specific. However, it's not clear
359 // that the Sampler ever really cared about reporting those
360 // objects well in the first place (eg activation or catch objects),
361 // so it doesn't seem we're a lot worse off than before.
362 ScopeChain
* sc
= NULL
;
364 sc
= vt
->init
->scope();
366 if (sc
&& sc
->getSize() <= 1)
368 if(sc
->getSize() == 1)
369 type
= tl
->classClass();
373 Atom ccAtom
= sc
->getScope(sc
->getSize()-1);
374 if(AvmCore::isObject(ccAtom
))
376 type
= (ClassClosure
*) AvmCore::atomToScriptObject(ccAtom
);
377 if(!AvmCore::istype(type
->atom(), core
->traits
.class_itraits
))
379 // obj is a ClassClosure
380 type
= tl
->classClass();
385 AvmAssert(AvmCore::istype(type
->atom(), core
->traits
.class_itraits
));
391 bool SamplerScript::set_stack(ScriptObject
* self
, ClassFactoryClass
* cf
, const Sample
& sample
, SampleObject
* sam
)
393 if (sample
.stack
.depth
> 0)
395 Toplevel
* toplevel
= self
->toplevel();
396 AvmCore
* core
= toplevel
->core();
397 Sampler
* s
= core
->get_sampler();
399 StackFrameClass
* sfcc
= (StackFrameClass
*)cf
->get_StackFrameClass();
400 ArrayObject
* stack
= toplevel
->arrayClass()->newArray(sample
.stack
.depth
);
401 StackTrace::Element
* e
= (StackTrace::Element
*)sample
.stack
.trace
;
402 for(uint32_t i
=0; i
< sample
.stack
.depth
; i
++, e
++)
404 StackFrameObject
* sf
= (StackFrameObject
*)sfcc
->newInstance();
406 // at every allocation the sample buffer could overflow and the samples could be deleted
407 // the StackTrace::Element pointer is a raw pointer into that buffer so we need to check
408 // that its still around before dereferencing e
410 if (s
->getSamples(num
) == NULL
)
413 sf
->set_name(e
->name()); // NOT e->info()->name() because e->name() can be a fake name
415 sf
->set_file(e
->filename());
416 sf
->set_line(e
->linenum());
417 sf
->set_scriptID(static_cast<double>(e
->functionId()));
419 stack
->setUintProperty(i
, sf
->atom());
421 sam
->set_stack(stack
);
426 ScriptObject
* SamplerScript::makeSample(ScriptObject
* self
, ClassFactoryClass
* cf
, const Sample
& sample
)
428 Toplevel
* toplevel
= self
->toplevel();
429 AvmCore
* core
= toplevel
->core();
430 Sampler
* s
= core
->get_sampler();
434 switch (sample
.sampleType
)
436 case Sampler::RAW_SAMPLE
:
438 SampleObject
* sam
= (SampleObject
*)cf
->get_SampleClass()->newInstance();
439 sam
->set_time(static_cast<double>(sample
.micros
));
440 if (!set_stack(self
, cf
, sample
, sam
))
444 case Sampler::DELETED_OBJECT_SAMPLE
:
446 DeleteObjectSampleObject
* dsam
= (DeleteObjectSampleObject
*)cf
->get_DeleteObjectSampleClass()->newInstance();
447 dsam
->set_time(static_cast<double>(sample
.micros
));
448 dsam
->set_id(static_cast<double>(sample
.id
));
449 dsam
->set_size(static_cast<double>(sample
.size
));
452 case Sampler::NEW_OBJECT_SAMPLE
:
454 NewObjectSampleObject
* nsam
= (NewObjectSampleObject
*)cf
->get_NewObjectSampleClass()->newInstance();
455 nsam
->set_time(static_cast<double>(sample
.micros
));
456 nsam
->set_id(static_cast<double>(sample
.id
));
457 if (!set_stack(self
, cf
, sample
, nsam
))
459 if (sample
.ptr
!= NULL
)
460 nsam
->setRef((AvmPlusScriptableObject
*)sample
.ptr
);
461 nsam
->set_type(getType(toplevel
, sample
.sot
, sample
.ptr
));
462 nsam
->setSize(sample
.alloc_size
);
465 case Sampler::NEW_AUX_SAMPLE
:
467 NewObjectSampleObject
* nsam
= (NewObjectSampleObject
*)cf
->get_NewObjectSampleClass()->newInstance();
468 nsam
->set_time(static_cast<double>(sample
.micros
));
469 nsam
->set_id(static_cast<double>(sample
.id
));
470 if (!set_stack(self
, cf
, sample
, nsam
))
472 nsam
->setSize(sample
.alloc_size
);
483 Atom
SamplerScript::getMemberNames(ScriptObject
* self
, Atom o
, bool instanceNames
)
486 AvmCore
* core
= self
->core();
487 MMgc::GC
* gc
= core
->GetGC();
488 Sampler
* s
= core
->get_sampler();
489 if (!s
|| !trusted(self
))
490 return undefinedAtom
;
492 if (AvmCore::isObject(o
))
494 Traits
*t
= AvmCore::atomToScriptObject(o
)->traits();
495 if(AvmCore::istype(o
, CLASS_TYPE
) && instanceNames
&& t
->itraits
)
497 if (s
->slotIteratorVTable
== NULL
)
498 s
->slotIteratorVTable
= _newVT(self
->toplevel(), self
->traits()->pool
, sizeof(SlotIterator
));
499 return (new (gc
) SlotIterator(t
, s
->slotIteratorVTable
))->atom();
503 (void)o
; (void)instanceNames
;
505 return undefinedAtom
;
508 static double _get_size(Atom a
)
518 AvmPlusScriptableObject
*o
= (AvmPlusScriptableObject
*)(a
&~7);
520 return (double)o
->bytesUsed();
529 double SamplerScript::getSize(ScriptObject
* self
, Atom a
)
532 AvmCore
* core
= self
->core();
533 Sampler
* s
= core
->get_sampler();
544 void SamplerScript::startSampling(ScriptObject
* self
)
547 Sampler
* s
= self
->core()->get_sampler();
548 if (!s
|| !trusted(self
))
556 void SamplerScript::stopSampling(ScriptObject
* self
)
559 Sampler
* s
= self
->core()->get_sampler();
560 if (!s
|| !trusted(self
))
568 void SamplerScript::clearSamples(ScriptObject
* self
)
571 Sampler
* s
= self
->core()->get_sampler();
572 if (!s
|| !trusted(self
))
580 void SamplerScript::pauseSampling(ScriptObject
* self
)
583 Sampler
* s
= self
->core()->get_sampler();
584 if (!s
|| !trusted(self
))
592 void SamplerScript::sampleInternalAllocs(ScriptObject
* self
, bool b
)
595 Sampler
* s
= self
->core()->get_sampler();
596 if (!s
|| !trusted(self
))
598 s
->sampleInternalAllocs(b
);
605 void SamplerScript::_setSamplerCallback(ScriptObject
* self
, ScriptObject
*callback
)
608 Sampler
* s
= self
->core()->get_sampler();
609 if (!s
|| !trusted(self
))
611 s
->setCallback(callback
);
618 double SamplerScript::_getInvocationCount(ScriptObject
* self
, Atom a
, QNameObject
* qname
, uint32_t type
)
621 AvmCore
* core
= self
->core();
622 Sampler
* s
= core
->get_sampler();
623 if (!s
|| !trusted(self
))
628 qname
->getMultiname(multiname
);
630 ScriptObject
* object
= self
->toplevel()->global();
631 if(!AvmCore::isObject(a
))
633 // not sure if this will be true for standalone avmplus
634 AvmAssert(core
->codeContext() != NULL
);
635 DomainEnv
*domainEnv
= core
->codeContext()->domainEnv();
636 ScriptEnv
* script
= (ScriptEnv
*) core
->domainMgr()->findScriptEnvInDomainEnvByMultiname(domainEnv
, multiname
);
637 if (script
!= (ScriptEnv
*)BIND_NONE
)
639 if (script
== (ScriptEnv
*)BIND_AMBIGUOUS
)
640 self
->toplevel()->throwReferenceError(kAmbiguousBindingError
, &multiname
);
642 object
= script
->global
;
645 object
= script
->initGlobal();
646 script
->coerceEnter(script
->global
->atom());
652 object
= AvmCore::atomToScriptObject(a
);
654 if(AvmCore::istype(a
, CLASS_TYPE
) && !qname
) {
655 // return constructor count
656 ClassClosure
*cc
= (ClassClosure
*)object
;
657 if (cc
->vtable
->init
) // Vector related crash here, Tommy says: I didn't think a type could ever not have a constructor but I guess there's no reason it has to.
658 return (double)cc
->vtable
->init
->invocationCount();
662 if(!object
|| !qname
)
665 VTable
*v
= object
->vtable
;
669 MethodEnv
*env
= NULL
;
670 Binding b
= self
->toplevel()->getBinding(v
->traits
, &multiname
);
671 switch (AvmCore::bindingKind(b
))
676 // only look at slots for first pass, otherwise we're applying instance traits to the Class
677 if(v
== object
->vtable
) {
678 Atom method
= object
->getSlotAtom(AvmCore::bindingToSlotId(b
));
679 if(AvmCore::isObject(method
))
681 env
= AvmCore::atomToScriptObject(method
)->getCallMethodEnv();
688 int m
= AvmCore::bindingToMethodId(b
);
696 if(type
== GET
&& AvmCore::hasGetterBinding(b
))
697 env
= v
->methods
[AvmCore::bindingToGetterId(b
)];
698 else if(type
== SET
&& AvmCore::hasSetterBinding(b
))
699 env
= v
->methods
[AvmCore::bindingToSetterId(b
)];
704 Atom method
= object
->getStringProperty(multiname
.getName());
705 if(AvmCore::isObject(method
))
707 env
= AvmCore::atomToScriptObject(method
)->getCallMethodEnv();
720 return (double)env
->invocationCount();
731 bool SamplerScript::isGetterSetter(ScriptObject
* self
, Atom a
, QNameObject
*qname
)
734 AvmCore
* core
= self
->core();
735 Sampler
* s
= core
->get_sampler();
739 if(!AvmCore::isObject(a
) || !AvmCore::atomToScriptObject(a
))
740 self
->toplevel()->throwArgumentError(kInvalidArgumentError
, "object");
742 ScriptObject
*object
= AvmCore::atomToScriptObject(a
);
744 if(!object
|| !qname
)
745 self
->toplevel()->argumentErrorClass()->throwError(kInvalidArgumentError
);
748 qname
->getMultiname(multiname
);
750 VTable
*v
= object
->vtable
;
754 Binding b
= self
->toplevel()->getBinding(v
->traits
, &multiname
);
756 if(b
== BIND_NONE
&& v
->ivtable
)
762 return AvmCore::hasSetterBinding(b
) || AvmCore::hasGetterBinding(b
);
765 (void)a
; (void)qname
;
771 SampleObject::SampleObject(VTable
*vtable
, ScriptObject
*delegate
)
772 : ScriptObject(vtable
, delegate
)
776 NewObjectSampleObject::NewObjectSampleObject(VTable
*vtable
, ScriptObject
*delegate
)
777 : SampleObject(vtable
, delegate
), size(0)
780 DeleteObjectSampleObject::DeleteObjectSampleObject(VTable
*vtable
, ScriptObject
*delegate
)
781 : SampleObject(vtable
, delegate
)
784 Atom
NewObjectSampleObject::get_object()
787 Atom a
= obj
->toAtom();
788 AvmAssert((a
&~7) != 0);
791 return undefinedAtom
;
794 double NewObjectSampleObject::get_size()
796 double s
= (double)size
;
798 Atom a
= get_object();
804 SampleClass::SampleClass(VTable
*vtable
)
805 : ClassClosure(vtable
)
807 createVanillaPrototype();
810 NewObjectSampleClass::NewObjectSampleClass(VTable
*vtable
)
811 : SampleClass(vtable
)
815 DeleteObjectSampleClass::DeleteObjectSampleClass(VTable
* vtable
) : SampleClass(vtable
)
820 ArrayObject
* SamplerScript::getLexicalScopes(ScriptObject
*self
, FunctionObject
*function
)
823 AvmCore
* core
= self
->core();
824 Sampler
*s
= core
->get_sampler();
825 if (!s
|| !trusted(self
))
828 if(function
!= NULL
&& function
->getCallMethodEnv())
829 return function
->getCallMethodEnv()->getLexicalScopes();
840 Atom
SamplerScript::getSavedThis(ScriptObject
*self
, FunctionObject
*method
)
843 AvmCore
* core
= self
->core();
844 Sampler
*s
= core
->get_sampler();
845 if (!s
|| !trusted(self
))
846 return undefinedAtom
;
849 if (method
!= NULL
&& ((mc
= method
->toMethodClosure()) != NULL
))
850 return mc
->get_savedThis();
852 return undefinedAtom
;
856 return undefinedAtom
;
861 Stringp
SamplerScript::getMasterString(ScriptObject
*self
, Stringp str
)
864 AvmCore
* core
= self
->core();
865 Sampler
*s
= core
->get_sampler();
866 if (!s
|| !trusted(self
))
870 return str
->getMasterString();