Bug 636438 - fix exact tracing for Dictionary (r=lhansen)
[tamarin-stm.git] / core / ScriptObject.cpp
blobe8fb119f2d22b4fcd0de71869456a6e6652ee2f7
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 ***** */
40 #include "avmplus.h"
41 //#define DOPROF
42 //#include "../vprof/vprof.h"
44 namespace avmplus
46 ScriptObject::ScriptObject(VTable* _vtable, ScriptObject* _delegate) :
47 #ifdef DEBUGGER
48 AvmPlusScriptableObject(sotObject(_vtable)),
49 #endif // DEBUGGER
50 vtable(_vtable),
51 // note that it's substantially more efficient to initialize this in the ctor
52 // list vs. a later explicit call to setDelegate, as we don't have to check for marking
53 // nor decrement an existing value...
54 delegate(_delegate)
56 AvmAssert(vtable->traits->isResolved());
58 // Ensure that our object is large enough to hold its extra traits data.
59 AvmAssert(MMgc::GC::Size(this) >= vtable->traits->getTotalSize());
62 ScriptObject::ScriptObject(VTable* _vtable, ScriptObject* _delegate, int capacity) :
63 #ifdef DEBUGGER
64 AvmPlusScriptableObject(sotObject(_vtable)),
65 #endif // DEBUGGER
66 vtable(_vtable),
67 // note that it's substantially more efficient to initialize this in the ctor
68 // list vs. a later explicit call to setDelegate, as we don't have to check for marking
69 // nor decrement an existing value...
70 delegate(_delegate)
72 AvmAssert(vtable->traits->isResolved());
74 // Ensure that our object is large enough to hold its extra traits data.
75 AvmAssert(MMgc::GC::Size(this) >= vtable->traits->getTotalSize());
77 //if capacity not specified then initialize the hashtable lazily
78 if (vtable->traits->needsHashtable() && capacity)
80 initHashtable(capacity);
84 ScriptObject::~ScriptObject()
86 //setDelegate(NULL); -- no longer necessary
87 vtable->traits->destroyInstance(this);
90 /* The storage for a ScriptObject or a subclass SO of ScriptObject is
91 * laid out as follows.
93 * - first the bits of the C++ class; if there are pointers here
94 * then they must be traced explicitly by the appropriate class's
95 * gcTrace method
96 * - then the bits for the ActionScript slots
97 * - optionally an InlineHashtable for dynamic properties
99 * The in-line slots are native and their representation is described
100 * by the Traits object (vtable->traits). They are not named, but named
101 * lookup is possible by going to the Traits object, which contains
102 * a name->slot map.
104 * The InlineHashtable always stores Atoms.
106 bool ScriptObject::gcTrace(MMgc::GC* gc, size_t cursor)
108 (void)cursor;
109 gc->TraceLocation(&vtable);
110 gc->TraceLocation(&delegate);
111 traits()->traceSlots(gc, this);
112 if (traits()->needsHashtable())
114 // Avoid initializing the hash table here
115 InlineHashtable* iht = getTableNoInit();
116 iht->gcTrace(gc);
119 return false;
122 void ScriptObject::initHashtable(int capacity /*=InlineHashtable::kDefaultCapacity*/)
124 AvmAssert(vtable->traits->isDictionary() == 0); //should not be called DictionaryObject uses HeapHashtable
126 MMGC_MEM_TYPE(this);
127 union {
128 uint8_t* p;
129 InlineHashtable* iht;
131 p = (uint8_t*)this + vtable->traits->getHashtableOffset();
132 iht->initializeWithDontEnumSupport(this->gc(), capacity);
135 InlineHashtable* ScriptObject::getTable() const
137 AvmAssert(vtable->traits->getHashtableOffset() != 0);
138 union {
139 uint8_t* p;
140 InlineHashtable* iht;
141 HeapHashtable** hht;
143 p = (uint8_t*)this + vtable->traits->getHashtableOffset();
144 if(!vtable->traits->isDictionary())
146 if (iht->needsInitialize())
147 const_cast<ScriptObject*>(this)->initHashtable();
148 return iht;
150 else
152 //DictionaryObjects store pointer to HeapHashtable at
153 //the hashtable offset
154 return (*hht)->get_ht();
159 * traverse the delegate chain looking for a value.
160 * [ed] it's okay to look only at the HT's in the delegate chain because
161 * delegate values may only be instances of Object. They cannot be objects
162 * with slots. We don't need to look at traits at each step.
163 * todo - enforce this rule
164 * @param name
165 * @return
167 Atom ScriptObject::getAtomProperty(Atom name) const
169 if (!traits()->needsHashtable())
171 return getAtomPropertyFromProtoChain(name, delegate, traits());
173 else
175 Stringp s = core()->atomToString(name);
176 AvmAssert(s->isInterned());
177 Atom ival = s->getIntAtom();
178 if (ival)
180 name = ival;
183 // dynamic lookup on this object
184 const ScriptObject *o = this;
187 // ensure prototype is dynamic
188 if (!o->vtable->traits->getHashtableOffset())
189 continue;
190 Atom const value = o->getTable()->getNonEmpty(name);
191 if (!InlineHashtable::isEmpty(value))
192 return value;
194 while ((o = o->delegate) != NULL);
195 return undefinedAtom;
199 Atom ScriptObject::getAtomPropertyFromProtoChain(Atom name, ScriptObject* o, Traits *origObjTraits) const
201 // todo will delegate always be non-null here?
202 if (o != NULL)
204 Atom searchname = name;
205 Stringp s = core()->atomToString(name);
206 AvmAssert(s->isInterned());
207 Atom ival = s->getIntAtom();
208 if (ival)
210 searchname = ival;
214 // ensure prototype is dynamic
215 if (!o->vtable->traits->getHashtableOffset())
216 continue;
217 Atom const value = o->getTable()->getNonEmpty(searchname);
218 if (!InlineHashtable::isEmpty(value))
219 return value;
221 while ((o = o->delegate) != NULL);
223 // NOTE use default public since name is not used
224 Multiname multiname(core()->getAnyPublicNamespace(), AvmCore::atomToString(name));
225 toplevel()->throwReferenceError(kReadSealedError, &multiname, origObjTraits);
226 // unreached
227 return undefinedAtom;
230 bool ScriptObject::hasMultinameProperty(const Multiname* multiname) const
232 if (traits()->needsHashtable() && multiname->isValidDynamicName())
234 return hasAtomProperty(multiname->getName()->atom());
236 else
238 // ISSUE should this walk the proto chain?
239 return false;
243 bool ScriptObject::hasAtomProperty(Atom name) const
245 if (traits()->needsHashtable())
247 Stringp s = core()->atomToString(name);
248 AvmAssert(s->isInterned());
249 Atom ival = s->getIntAtom();
250 if (ival)
252 name = ival;
255 return getTable()->contains(name);
257 else
259 // ISSUE should this walk the proto chain?
260 return false;
264 void ScriptObject::throwWriteSealedError(const Multiname& name)
266 toplevel()->throwReferenceError(kWriteSealedError, name, traits());
269 void ScriptObject::throwWriteSealedError(Atom name)
271 AvmCore* core = this->core();
272 throwWriteSealedError(Multiname(core->getAnyPublicNamespace(), core->intern(name)));
275 void ScriptObject::throwCantInstantiateError()
277 Multiname qname(traits()->ns(), traits()->name());
278 toplevel()->argumentErrorClass()->throwError(kCantInstantiateError, core()->toErrorString(&qname));
281 void ScriptObject::setAtomProperty(Atom name, Atom value)
283 if (traits()->needsHashtable())
285 Stringp s = core()->atomToString(name);
286 AvmAssert(s->isInterned());
287 Atom ival = s->getIntAtom();
288 if (ival)
290 name = ival;
293 MMGC_MEM_TYPE(this);
294 getTable()->add (name, value);
295 MMGC_MEM_TYPE(NULL);
297 else
299 throwWriteSealedError(name);
303 void ScriptObject::setMultinameProperty(const Multiname* name, Atom value)
305 if (traits()->needsHashtable() && name->isValidDynamicName())
307 setStringProperty(name->getName(), value);
309 else
311 throwWriteSealedError(*name);
315 bool ScriptObject::getAtomPropertyIsEnumerable(Atom name) const
317 if (traits()->needsHashtable())
319 Stringp s = core()->atomToString(name);
320 AvmAssert(s->isInterned());
321 Atom ival = s->getIntAtom();
322 if (ival)
324 name = ival;
327 return getTable()->getAtomPropertyIsEnumerable(name);
329 else
331 // ISSUE should this walk the proto chain?
332 return false;
336 void ScriptObject::setAtomPropertyIsEnumerable(Atom name, bool enumerable)
338 if (traits()->needsHashtable())
340 Stringp s = core()->atomToString(name);
341 AvmAssert(s->isInterned());
342 Atom ival = s->getIntAtom();
343 if (ival)
345 name = ival;
348 getTable()->setAtomPropertyIsEnumerable(name, enumerable);
350 else
352 throwWriteSealedError(name);
356 bool ScriptObject::deleteAtomProperty(Atom name)
358 if (traits()->needsHashtable())
360 Stringp s = core()->atomToString(name);
361 AvmAssert(s->isInterned());
362 Atom ival = s->getIntAtom();
363 if (ival)
365 name = ival;
368 getTable()->remove(name);
369 return true;
371 else
373 return false;
377 bool ScriptObject::deleteMultinameProperty(const Multiname* name)
379 if (traits()->needsHashtable() && name->isValidDynamicName())
381 return deleteStringProperty(name->getName());
383 else
385 return false;
389 Atom ScriptObject::getUintProperty(uint32_t i) const
391 // N.B.: a key present in ScriptObject must be interned string;
392 // thus uninterned implies absent (cf. bugzilla 556023).
394 AvmCore* core = this->core();
396 if (!(i&MAX_INTEGER_MASK))
398 if (!traits()->needsHashtable())
400 Stringp interned;
401 bool present = core->isInternedUint(i, &interned);
402 if (present)
404 Atom name = interned->atom();
405 return getAtomPropertyFromProtoChain(name, delegate,
406 traits());
408 else
410 return undefinedAtom;
413 else
415 // dynamic lookup on this object
416 Atom name = core->uintToAtom (i);
417 const ScriptObject *o = this;
420 // ensure prototype is dynamic
421 if (!o->vtable->traits->getHashtableOffset())
422 continue;
423 Atom const value = o->getTable()->getNonEmpty(name);
424 if (!InlineHashtable::isEmpty(value))
425 return value;
427 while ((o = o->delegate) != NULL);
428 return undefinedAtom;
431 else
433 Stringp interned;
434 bool present;
435 present = core->isInternedUint(i, &interned);
436 if (present)
438 return getAtomProperty(interned->atom());
440 else
442 return undefinedAtom;
447 void ScriptObject::setUintProperty(uint32_t i, Atom value)
449 AvmCore* core = this->core();
450 if (!(i&MAX_INTEGER_MASK))
452 Atom name = core->uintToAtom (i);
453 if (traits()->needsHashtable())
455 MMGC_MEM_TYPE(this);
456 getTable()->add(name, value);
457 MMGC_MEM_TYPE(NULL);
459 else
461 throwWriteSealedError(core->internUint32(i)->atom());
464 else
466 setAtomProperty(core->internUint32(i)->atom(), value);
470 bool ScriptObject::delUintProperty(uint32_t i)
472 AvmCore* core = this->core();
473 if (!(i&MAX_INTEGER_MASK))
475 Atom name = core->uintToAtom (i);
476 if (traits()->needsHashtable())
478 getTable()->remove(name);
479 return true;
481 else
483 return false;
486 else
488 return deleteAtomProperty(core->internUint32(i)->atom());
492 bool ScriptObject::hasUintProperty(uint32_t i) const
494 AvmCore* core = this->core();
495 if (!(i&MAX_INTEGER_MASK))
497 Atom name = core->uintToAtom (i);
498 if (traits()->needsHashtable())
500 return getTable()->contains(name);
502 else
504 // ISSUE should this walk the proto chain?
505 return false;
508 else
510 return hasAtomProperty(core->internUint32(i)->atom());
514 Atom ScriptObject::getMultinameProperty(const Multiname* multiname) const
516 if (multiname->isValidDynamicName())
518 return getStringProperty(multiname->getName());
520 else
522 Toplevel* toplevel = this->toplevel();
524 if (multiname->isNsset())
525 toplevel->throwReferenceError(kReadSealedErrorNs, multiname, traits());
526 else
527 toplevel->throwReferenceError(kReadSealedError, multiname, traits());
528 return undefinedAtom;
532 // this = argv[0] (ignored)
533 // arg1 = argv[1]
534 // argN = argv[argc]
535 Atom ScriptObject::callProperty(const Multiname* multiname, int argc, Atom* argv)
537 Toplevel* toplevel = this->toplevel();
538 Atom method = getMultinameProperty(multiname);
539 if (!AvmCore::isObject(method))
540 toplevel->throwTypeError(kCallOfNonFunctionError, core()->toErrorString(multiname));
541 argv[0] = atom(); // replace receiver
542 return toplevel->op_call(method, argc, argv);
545 Atom ScriptObject::constructProperty(const Multiname* multiname, int argc, Atom* argv)
547 Atom ctor = getMultinameProperty(multiname);
548 argv[0] = atom(); // replace receiver
549 return toplevel()->op_construct(ctor, argc, argv);
552 Atom ScriptObject::getDescendants(const Multiname* /*name*/) const
554 toplevel()->throwTypeError(kDescendentsError, core()->toErrorString(traits()));
555 return undefinedAtom;// not reached
558 bool ScriptObject::isGlobalObject() const
560 return traits()->posType() == TRAITSTYPE_SCRIPT;
563 #ifdef AVMPLUS_VERBOSE
564 PrintWriter& ScriptObject::print(PrintWriter& prw) const
566 (traits()->name() != NULL) ? prw << traits()
567 : prw << "{}";
568 return prw << "@" << asAtomHex(atom());
570 #endif
572 Atom ScriptObject::defaultValue()
574 AvmCore *core = this->core();
575 Toplevel* toplevel = this->toplevel();
577 Atom atomv_out[1];
579 // call this.valueOf()
580 // NOTE use callers versioned public to get correct valueOf
581 Multiname tempname(core->findPublicNamespace(), core->kvalueOf);
582 atomv_out[0] = atom();
583 Atom result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable);
585 // if result is primitive, return it
586 if (atomKind(result) != kObjectType)
587 return result;
589 // otherwise call this.toString()
590 tempname.setName(core->ktoString);
591 atomv_out[0] = atom();
592 result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable);
594 // if result is primitive, return it
595 if (atomKind(result) != kObjectType)
596 return result;
598 // could not convert to primitive.
599 toplevel->throwTypeError(kConvertToPrimitiveError, core->toErrorString(traits()));
600 return undefinedAtom;
603 // Execute the ToString algorithm as described in ECMA-262 Section 9.8.
604 // This is ToString(ToPrimitive(input argument, hint String))
605 // ToPrimitive(input argument, hint String) calls [[DefaultValue]]
606 // described in ECMA-262 8.6.2.6. The [[DefaultValue]] algorithm
607 // with hint String is inlined here.
608 Stringp ScriptObject::toString()
610 AvmCore *core = this->core();
611 Toplevel* toplevel = this->toplevel();
613 Atom atomv_out[1];
615 // call this.toString()
616 // NOTE use callers versioned public to get correct toString
617 Multiname tempname(core->findPublicNamespace(), core->ktoString);
618 atomv_out[0] = atom();
619 Atom result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable);
621 // if result is primitive, return its ToString
622 if (atomKind(result) != kObjectType)
623 return core->string(result);
625 // otherwise call this.valueOf()
626 tempname.setName(core->kvalueOf);
627 atomv_out[0] = atom();
628 result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable);
630 // if result is primitive, return it
631 if (atomKind(result) != kObjectType)
632 return core->string(result);
634 // could not convert to primitive.
635 toplevel->throwTypeError(kConvertToPrimitiveError, core->toErrorString(traits()));
636 return NULL; // unreachable
639 // this = argv[0] (ignored)
640 // arg1 = argv[1]
641 // argN = argv[argc]
642 Atom ScriptObject::call(int /*argc*/, Atom* /*argv*/)
644 // TypeError in ECMA to execute a non-function
645 // NOTE use default public since name is not used
646 Multiname name(core()->getAnyPublicNamespace(), core()->kvalue);
647 toplevel()->throwTypeError(kCallOfNonFunctionError, core()->toErrorString(&name));
648 return undefinedAtom;
651 // this = argv[0] (ignored)
652 // arg1 = argv[1]
653 // argN = argv[argc]
654 Atom ScriptObject::construct(int /*argc*/, Atom* /*argv*/)
656 // TypeError in ECMA to execute a non-function
657 toplevel()->throwTypeError(kConstructOfNonFunctionError);
658 return undefinedAtom;
661 Atom ScriptObject::applyTypeArgs(int /*argc*/, Atom* /*argv*/)
663 toplevel()->throwTypeError(kTypeAppOfNonParamType);
664 return undefinedAtom;
667 Atom ScriptObject::getSlotAtom(uint32_t slot)
669 Traits* traits = this->traits();
670 const TraitsBindingsp td = traits->getTraitsBindings();
671 // repeated if-else is actually more performant than a switch statement in this case.
672 // SST_atom is most common case, put it first
673 void* p;
674 const SlotStorageType sst = td->calcSlotAddrAndSST(slot, (void*)this, p);
675 if (sst == SST_atom)
677 return *((const Atom*)p);
679 else if (sst == SST_double)
681 return traits->core->doubleToAtom(*((const double*)p));
683 else if (sst == SST_int32)
685 return traits->core->intToAtom(*((const int32_t*)p));
687 else if (sst == SST_uint32)
689 return traits->core->uintToAtom(*((const int32_t*)p));
691 else if (sst == SST_bool32)
693 return (*((const int32_t*)p)<<3)|kBooleanType;
695 else if (sst == SST_string)
697 return (*((const Stringp*)p))->atom(); // may be null|kStringType, that's ok
699 else if (sst == SST_namespace)
701 return (*((const Namespacep*)p))->atom(); // may be null|kNamespaceType, no problemo
703 else // if (sst == SST_scriptobject)
705 AvmAssert(sst == SST_scriptobject);
706 return (*((const ScriptObject**)p))->atom(); // may be null|kObjectType, copacetic
710 ScriptObject* ScriptObject::getSlotObject(uint32_t slot)
712 Traits* traits = this->traits();
713 const TraitsBindingsp td = traits->getTraitsBindings();
714 void* p;
715 const SlotStorageType sst = td->calcSlotAddrAndSST(slot, (void*)this, p);
717 // based on profiling of Flex apps, it's *much* more common for the slot in this case
718 // to have a type (vs "atom"), so check for that first...
719 if (sst == SST_scriptobject)
721 return *((ScriptObject**)p);
723 else if (sst == SST_atom)
725 Atom const a = *((const Atom*)p);
727 // don't call AvmCore::isObject(); it checks for null, which we don't care about here
728 if (atomKind(a) == kObjectType)
729 return (ScriptObject*)atomPtr(a);
731 // else fall thru and return null
734 return NULL;
737 // note: coerceAndSetSlotAtom now includes a simplified and streamlined version
738 // of Toplevel::coerce. If you modify that code, you might need to modify this code.
739 void ScriptObject::coerceAndSetSlotAtom(uint32_t slot, Atom value)
741 Traits* traits = this->traits();
742 const TraitsBindingsp td = traits->getTraitsBindings();
743 void* p;
744 const SlotStorageType sst = td->calcSlotAddrAndSST(slot, (void*)this, p);
745 // repeated if-else is actually more performant than a switch statement in this case.
746 // SST_atom is most common case, put it first
747 if (sst == SST_atom)
749 // no call to coerce() needed, since anything will fit here... with one exception:
750 // BUILTIN_object needs to convert undefined->null (though BUILTIN_any does not).
751 // it's cheaper to do that here than call out to coerce().
752 AvmAssert(td->getSlotTraits(slot) == NULL || td->getSlotTraits(slot)->builtinType == BUILTIN_object);
753 if (value == undefinedAtom && td->getSlotTraits(slot) != NULL)
754 value = nullObjectAtom;
755 WBATOM(traits->core->GetGC(), this, (Atom*)p, value);
757 else if (sst == SST_double)
759 *((double*)p) = AvmCore::number(value);
761 else if (sst == SST_int32)
763 *((int32_t*)p) = AvmCore::integer(value);
765 else if (sst == SST_uint32)
767 *((uint32_t*)p) = AvmCore::toUInt32(value);
769 else if (sst == SST_bool32)
771 *((int32_t*)p) = AvmCore::boolean(value);
773 else
775 // null/undefined -> NULL for all of these
776 if (AvmCore::isNullOrUndefined(value))
778 value = (Atom)0; // don't bother setting tag bits
780 else if (sst == SST_string)
782 value = (Atom)traits->core->string(value); // don't bother setting tag bits
784 else if (sst == SST_namespace)
786 // Namespace is final, so we don't have to do the hard work
787 if (atomKind(value) != kNamespaceType)
788 goto failure;
790 else // if (sst == SST_scriptobject)
792 AvmAssert(sst == SST_scriptobject);
793 if (atomKind(value) != kObjectType || !AvmCore::atomToScriptObject(value)->traits()->subtypeof(td->getSlotTraits(slot)))
794 goto failure;
796 WBRC(traits->core->GetGC(), this, p, atomPtr(value));
798 return;
800 failure:
801 toplevel()->throwTypeError(kCheckTypeFailedError, traits->core->atomToErrorString(value), traits->core->toErrorString(td->getSlotTraits(slot)));
802 return;
805 Atom ScriptObject::nextName(int index)
807 AvmAssert(traits()->needsHashtable());
808 AvmAssert(index > 0);
810 InlineHashtable* ht = getTable();
811 Atom m = ht->keyAt(index);
812 return AvmCore::isNullOrUndefined(m) ? nullStringAtom : m;
815 Atom ScriptObject::nextValue(int index)
817 AvmAssert(traits()->needsHashtable());
818 AvmAssert(index > 0);
820 InlineHashtable* ht = getTable();
821 Atom m = ht->keyAt(index);
822 if (AvmCore::isNullOrUndefined(m))
823 return nullStringAtom;
824 return ht->valueAt(index);
827 int ScriptObject::nextNameIndex(int index)
829 AvmAssert(index >= 0);
831 if (!traits()->needsHashtable())
832 return 0;
834 return getTable()->next(index);
837 #ifdef DEBUGGER
838 uint64_t ScriptObject::bytesUsed() const
840 uint64_t bytesUsed = traits()->getTotalSize();
841 if(traits()->needsHashtable())
843 if (traits()->isDictionary())
845 union {
846 uint8_t* p;
847 HeapHashtable** hht;
849 p = (uint8_t*)this + traits()->getHashtableOffset();
850 bytesUsed += (*hht)->bytesUsed();
852 else
854 bytesUsed += getTable()->bytesUsed();
857 return bytesUsed;
859 #endif
861 Stringp ScriptObject::implToString() const
863 AvmCore* core = this->core();
864 Traits* t = this->traits();
865 Stringp s = core->concatStrings(core->newConstantStringLatin1("[object "), t->name());
866 return core->concatStrings(s, core->newConstantStringLatin1("]"));
869 uint32_t ScriptObject::getLengthProperty()
871 Toplevel* toplevel = this->toplevel();
872 AvmCore* core = toplevel->core();
873 Multiname mname(core->getAnyPublicNamespace(), core->klength);
874 Atom lenAtm = toplevel->getproperty(this->atom(), &mname, this->vtable);
875 return AvmCore::toUInt32(lenAtm);
878 void ScriptObject::setLengthProperty(uint32_t newLen)
880 Toplevel* toplevel = this->toplevel();
881 AvmCore* core = toplevel->core();
882 Multiname mname(core->getAnyPublicNamespace(), core->klength);
883 Atom lenAtm = core->uintToAtom(newLen);
884 toplevel->setproperty(this->atom(), &mname, lenAtm, this->vtable);