// Execute the ToString algorithm as described in ECMA-262 Section 9.8. // This is ToString(ToPrimitive(input argument, hint String)) // ToPrimitive(input argument, hint String) calls [[DefaultValue]] // described in ECMA-262 8.6.2.6. The [[DefaultValue]] algorithm // with hint String is inlined here. Stringp ScriptObject::toString() { AvmCore *core = this->core(); Toplevel* toplevel = this->toplevel(); Atom atomv_out[1]; // call this.toString() // NOTE use callers versioned public to get correct toString Multiname tempname(core->findPublicNamespace(), core->ktoString); atomv_out[0] = atom(); Atom result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable); // if result is primitive, return its ToString if (atomKind(result) != kObjectType) return core->string(result); // otherwise call this.valueOf() tempname.setName(core->kvalueOf); atomv_out[0] = atom(); result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable); // if result is primitive, return it if (atomKind(result) != kObjectType) return core->string(result); // could not convert to primitive. toplevel->throwTypeError(kConvertToPrimitiveError, core->toErrorString(traits())); return NULL; // unreachable }
ScriptObject* ScriptObject::getSlotObject(uint32_t slot) { Traits* traits = this->traits(); const TraitsBindingsp td = traits->getTraitsBindings(); void* p; const SlotStorageType sst = td->calcSlotAddrAndSST(slot, (void*)this, p); // based on profiling of Flex apps, it's *much* more common for the slot in this case // to have a type (vs "atom"), so check for that first... if (sst == SST_scriptobject) { return *((ScriptObject**)p); } else if (sst == SST_atom) { Atom const a = *((const Atom*)p); // don't call AvmCore::isObject(); it checks for null, which we don't care about here if (atomKind(a) == kObjectType) return (ScriptObject*)atomPtr(a); // else fall thru and return null } return NULL; }
/** 15.2.4.5 Object.prototype.hasOwnProperty (V) When the hasOwnProperty method is called with argument V, the following steps are taken: 1. Let O be this object. 2. Call ToString(V). 3. If O doesnt have a property with the name given by Result(2), return false. 4. Return true. NOTE Unlike [[HasProperty]] (section 8.6.2.4), this method does not consider objects in the prototype chain. */ bool ObjectClass::_hasOwnProperty(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; Traitsp t = NULL; switch (atomKind(thisAtom)) { case kObjectType: { // ISSUE should this look in traits and dynamic vars, or just dynamic vars. ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); if (obj->hasStringProperty(name)) return true; t = obj->traits(); break; } case kNamespaceType: case kStringType: case kBooleanType: case kDoubleType: case kIntegerType: t = toplevel()->toTraits(thisAtom); break; default: return false; } return t->getTraitsBindings()->findBinding(name, core->publicNamespace) != BIND_NONE; }
/** 15.2.4.5 Object.prototype.hasOwnProperty (V) When the hasOwnProperty method is called with argument V, the following steps are taken: 1. Let O be this object. 2. Call ToString(V). 3. If O doesn't have a property with the name given by Result(2), return false. 4. Return true. NOTE Unlike [[HasProperty]] (section 8.6.2.4), this method does not consider objects in the prototype chain. */ bool ObjectClass::_hasOwnProperty(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; Traitsp t = NULL; switch (atomKind(thisAtom)) { case kObjectType: { // ISSUE should this look in traits and dynamic vars, or just dynamic vars. ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); // TODO // The change below is important as otherwise we will throw error in a call to hasAtomProperty for ByteArrayObject. // This gets us back to the behaviour which we had in Marlin. // A bugzilla bug [ 562224 ] has been created to address this issue more cleanly in near future return obj->traits()->getTraitsBindings()->findBinding(name, core->findPublicNamespace()) != BIND_NONE || obj->hasStringProperty(name); } case kNamespaceType: case kStringType: case kBooleanType: case kDoubleType: case kIntptrType: t = toplevel()->toTraits(thisAtom); break; default: return false; } // NOTE use caller's public namespace return t->getTraitsBindings()->findBinding(name, core->findPublicNamespace()) != BIND_NONE; }
bool ObjectClass::_propertyIsEnumerable(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; if (atomKind(thisAtom) == kObjectType) { ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); return obj->getStringPropertyIsEnumerable(name); } else if (atomKind(thisAtom) == kNamespaceType) { // Special case: // E4X 13.2.5.1, 13.2.5.2 specifies that prefix and uri // are not DontEnum. return name == core->kuri || name == core->kprefix; } else { return false; } }
void ObjectClass::_setPropertyIsEnumerable(Atom thisAtom, Stringp name, bool enumerable) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; if (atomKind(thisAtom) == kObjectType) { ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); obj->setStringPropertyIsEnumerable(name, enumerable); } else { // cannot create properties on a sealed object. // NOTE just use the unmarked version Multiname multiname(core->getAnyPublicNamespace(), name); // NOTE use default public toplevel()->throwReferenceError(kWriteSealedError, &multiname, traits()); } }
/** * @return a pointer to an object Atom whose members are * the active locals for this frame. */ bool DebugStackFrame::locals(Atom*& ar, int& count) { bool worked = true; if (trace->framep() && trace->info()) { int firstLocal, pastLastLocal; localBounds(&firstLocal, &pastLastLocal); count = pastLastLocal - firstLocal; AvmAssert(count >= 0); if ((count > 0) && debugger) { // frame looks like [this][param0...paramN][local0...localN] ar = (Atom*) debugger->core->GetGC()->Calloc(count, sizeof(Atom), GC::kContainsPointers|GC::kZero); MethodInfo* info = trace->info(); info->boxLocals(trace->framep(), firstLocal, trace->types(), ar, 0, count); // If NEED_REST or NEED_ARGUMENTS is set, and the jit is being used, then the first // local is actually not an atom at all -- it is an ArrayObject*. So, we need to // convert it to an atom. (If the interpreter is being used instead of the jit, then // it is stored as an atom.) if (info->needRestOrArguments()) { int atomType = atomKind(ar[0]); if (atomType == 0) // 0 is not a legal atom type, so ar[0] is not an atom { ScriptObject* obj = (ScriptObject*)ar[0]; ar[0] = obj->atom(); } } } } else { worked = false; count = 0; } return worked; }
bool LocalConnectionObject::SendMethod(const char*name,const char*strDomain,const char*method,ArrayObject*args) { AvmCore*c=core(); ScriptObject*pClient=m_pClient; if(pClient==NULL) pClient=this; //pClient->callProperty( //callProperty Stringp s=c->internStringLatin1(method); if(!pClient->hasAtomProperty(s->atom())) return false; Atom atom=pClient->getAtomProperty(s->atom()); args->setIntProperty(0,atom); if(atomKind(atom)==kObjectType) { ScriptObject*pCall=c->atomToScriptObject(atom); if(pCall) { //pCall->call(args->get_length()-1,args->GetAtoms()); pCall->call(args->getDenseLength()-1,args->GetAtoms()); return true; } } return true; }
void CallStackNode::enumerateScopeChainAtoms(IScopeChainEnumerator& scb) { // First, get the "dynamic" portion of the scope chain, that is, the // part that is modified on-the-fly within the function. This includes // activation objects for try/catch blocks and "with" clauses. if (m_info) { MethodSignaturep const ms = m_info->getMethodSignature(); for (int i = (ms->max_scope() + ms->local_count() - 1), n = ms->local_count(); i >= n; --i) { Atom const scope = m_info->boxOneLocal(m_framep, i, m_traits); AvmAssert(atomKind(scope) != kUnusedAtomTag); // go ahead and call addScope, even if null or undefined. scb.addScope(scope); } } // Next, get the "static" portion of the scope chain, that is, the // part that is defined as part of the definition of the function. This // includes the locals of any functions that enclose this one, and the "this" // object, if any. ScopeChain* scopeChain = m_env ? m_env->scope() : NULL; if (scopeChain) { int scopeChainLength = scopeChain->getSize(); for (int i = scopeChainLength - 1; i >= 0; --i) { Atom scope = scopeChain->getScope(i); if (AvmCore::isObject(scope)) { scb.addScope(scope); } } } }
RecordedType ProfiledState::getRecordedType(Atom value) { Atom atom_kind = atomKind(value); switch (atom_kind) { case kDoubleType: return kDOUBLE; case kIntptrType: return kINTEGER; case kStringType: return kSTRING; case kBooleanType: return kBOOLEAN; case kObjectType: { ScriptObject* object = AvmCore::atomToScriptObject(value); if (object == NULL) return kOBJECT; // undefined object if (object->toArrayObject() != NULL) return kARRAY; return kOBJECT; } case kUnusedAtomTag: return kUNINITIALIZED; case kNamespaceType: return kUNSUPPORTED; case kSpecialBibopType: return kUNSUPPORTED; default: printf("Unknown atom type %d\n", (int) atom_kind); AvmAssert (false); } AvmAssert (false); return kUNINITIALIZED; }
bool Exception::isValid() { return atomKind(atom) == kObjectType; }
// interactive Atom Debugger::autoAtomKindAt(DebugFrame* frame, int autoIndex, AutoVarKind kind) { if (!frame) return unreachableAtom; else return atomKind(autoAtomAt(frame, autoIndex, kind)); }
// note: coerceAndSetSlotAtom now includes a simplified and streamlined version // of Toplevel::coerce. If you modify that code, you might need to modify this code. void ScriptObject::coerceAndSetSlotAtom(uint32_t slot, Atom value) { Traits* traits = this->traits(); const TraitsBindingsp td = traits->getTraitsBindings(); void* p; const SlotStorageType sst = td->calcSlotAddrAndSST(slot, (void*)this, p); // repeated if-else is actually more performant than a switch statement in this case. // SST_atom is most common case, put it first if (sst == SST_atom) { // no call to coerce() needed, since anything will fit here... with one exception: // BUILTIN_object needs to convert undefined->null (though BUILTIN_any does not). // it's cheaper to do that here than call out to coerce(). AvmAssert(td->getSlotTraits(slot) == NULL || td->getSlotTraits(slot)->builtinType == BUILTIN_object); if (value == undefinedAtom && td->getSlotTraits(slot) != NULL) value = nullObjectAtom; WBATOM(traits->core->GetGC(), this, (Atom*)p, value); } else if (sst == SST_double) { *((double*)p) = AvmCore::number(value); } else if (sst == SST_int32) { *((int32_t*)p) = AvmCore::integer(value); } else if (sst == SST_uint32) { *((uint32_t*)p) = AvmCore::toUInt32(value); } else if (sst == SST_bool32) { *((int32_t*)p) = AvmCore::boolean(value); } else { // null/undefined -> NULL for all of these if (AvmCore::isNullOrUndefined(value)) { value = (Atom)0; // don't bother setting tag bits } else if (sst == SST_string) { value = (Atom)traits->core->string(value); // don't bother setting tag bits } else if (sst == SST_namespace) { // Namespace is final, so we don't have to do the hard work if (atomKind(value) != kNamespaceType) goto failure; } else // if (sst == SST_scriptobject) { AvmAssert(sst == SST_scriptobject); if (atomKind(value) != kObjectType || !AvmCore::atomToScriptObject(value)->traits()->subtypeof(td->getSlotTraits(slot))) goto failure; } WBRC(traits->core->GetGC(), this, p, atomPtr(value)); } return; failure: toplevel()->throwTypeError(kCheckTypeFailedError, traits->core->atomToErrorString(value), traits->core->toErrorString(td->getSlotTraits(slot))); return; }