// 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 }
Stringp NumberClass::_convert(double n, int precision, int mode) { AvmCore* core = this->core(); if (mode == MathUtils::DTOSTR_PRECISION) { if (precision < 1 || precision > 21) { toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(1), core->toErrorString(21)); } } else { if (precision < 0 || precision > 20) { toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(0), core->toErrorString(20)); } } return MathUtils::convertDoubleToString(core, n, mode, precision); }
ClassClosure* DomainObject::getClass(Stringp name) { AvmCore *core = this->core(); if (name == NULL) { toplevel()->throwArgumentError(kNullArgumentError, core->toErrorString("name")); } // Search for a dot from the end. int dot = name->lastIndexOf(core->cachedChars[(int)'.']); // If there is a '.', this is a fully-qualified // class name in a package. Must turn it into // a namespace-qualified multiname. Namespace* ns; Stringp className; if (dot >= 0) { Stringp uri = core->internString(name->substring(0, dot)); ns = core->internNamespace(core->newNamespace(uri)); className = core->internString(name->substring(dot+1, name->length())); } else { ns = core->publicNamespace; className = core->internString(name); } Multiname multiname(ns, className); // OOO: In the distribution, we search core->codeContext()->domainEnv rather than // our own domainEnv, which is surely a bug? ScriptObject *container = finddef(multiname, domainEnv); if (!container) { toplevel()->throwTypeError(kClassNotFoundError, core->toErrorString(&multiname)); } Atom atom = toplevel()->getproperty(container->atom(), &multiname, container->vtable); if (!AvmCore::istype(atom, core->traits.class_itraits)) { toplevel()->throwTypeError(kClassNotFoundError, core->toErrorString(&multiname)); } return (ClassClosure*)AvmCore::atomToScriptObject(atom); }
void ProgramClass::_setExitListener(FunctionObject* f) { AvmCore *core = this->core(); // Listeners MUST be functions or null if ( core->isNullOrUndefined(f->atom()) ) { f = 0; } else if (!AvmCore::istype(f->atom(), core->traits.function_itraits)) { toplevel()->argumentErrorClass()->throwError( kInvalidArgumentError, core->toErrorString("Function")); } exit_callback = f; }
Atom DomainObject::loadBytes(ByteArrayObject *b) { AvmCore* core = this->core(); if (!b) toplevel()->throwTypeError(kNullArgumentError, core->toErrorString("bytes")); ShellCodeContext* codeContext = new (core->GetGC()) ShellCodeContext(); codeContext->m_domainEnv = domainEnv; // parse new bytecode size_t len = b->get_length(); ScriptBuffer code = core->newScriptBuffer(len); VMPI_memcpy(code.getBuffer(), &b->GetByteArray()[0], len); Toplevel *toplevel = domainToplevel; return core->handleActionBlock(code, 0, domainEnv, toplevel, NULL, codeContext); }
Stringp NumberClass::_numberToString(double dVal, int radix) { AvmCore* core = this->core(); if (radix == 10 || MathUtils::isInfinite(dVal) || MathUtils::isNaN(dVal)) return core->doubleToString(dVal); if (radix < 2 || radix > 36) toplevel()->throwRangeError(kInvalidRadixError, core->toErrorString(radix)); // convertDoubleToStringRadix will convert the integer part of dVal // to a string in the specified radix, and it will handle large numbers // beyond the range of int/uint. It will not handle the fractional // part. To properly handle that, MathUtils::convertDoubleToString // would have to handle any base. That's a lot of extra code and complexity for // something the ES3 spec says is implementation dependent // (i.e. we're not required to do it) return MathUtils::convertDoubleToStringRadix(core, dVal, radix); }
void TraceClass::setListener(ScriptObject* f) { #ifdef DEBUGGER AvmCore *core = this->core(); if (core->debugger()) { // Listeners MUST be functions or null if ( core->isNullOrUndefined(f->atom()) ) { f = 0; } else if (!AvmCore::istype(f->atom(), core->traits.function_itraits)) { toplevel()->argumentErrorClass()->throwError( kInvalidArgumentError, core->toErrorString("Function")); return; } //MethodClosure* mc = f->toplevel()->methodClosureClass->create(f->getCallMethodEnv(), f->atom()); core->debugger()->trace_callback = f; } #endif /* DEBUGGER */ (void)f; }