Stringp ClassClosure::implToString() const { AvmCore* core = this->core(); Traits* t = this->traits()->itraits; Stringp s = core->concatStrings(core->newConstantStringLatin1("[class "), t->name()); return core->concatStrings(s, core->newConstantStringLatin1("]")); }
// 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 }
/*static*/ CdirentObject* CDirentClass::readdir(ScriptObject* self, CDIRObject* dirp) { Toplevel* toplevel = self->toplevel(); if( !dirp ) { toplevel->throwArgumentError(kNullArgumentError, "dirp"); } dirent *entry = VMPI_readdir( dirp->read() ); if( entry ) { ShellToplevel* shelltop = (ShellToplevel*)self->toplevel(); CdirentClass *direc = shelltop->getShellClasses()->get_direntClass(); CdirentObject *direo = direc->constructObject(); direo->write( entry ); AvmCore *core = self->core(); direo->set_d_ino( entry->d_ino ); direo->set_d_name( core->newStringUTF8( entry->d_name ) ); return direo; } return NULL; }
ArrayObject* HTTPFormClass::convertForm(std::vector<FormEntry>& vec) { AvmCore *core = this->core(); ArrayObject *out = this->toplevel()->arrayClass->newArray(); for (std::vector<FormEntry>::iterator it=vec.begin(); it!=vec.end(); it++) { ArrayObject* arr; Stringp key = core->internStringUTF8((*it).name.data(), (*it).name.length()); Stringp value = core->internStringUTF8((*it).value.data(), (*it).value.length()); //we have it, append if (out->hasStringProperty(key)) { arr = (ArrayObject*) core->atomToScriptObject(out->getStringProperty(key)); arr->setUintProperty(arr->get_length(), value->atom()); } //create array else { arr = this->toplevel()->arrayClass->newArray(); arr->setUintProperty(0, value->atom()); out->setStringProperty(key, arr->atom()); } } return out; }
Stringp ScriptObject::implToString() const { AvmCore* core = this->core(); Traits* t = this->traits(); Stringp s = core->concatStrings(core->newConstantStringLatin1("[object "), t->name()); return core->concatStrings(s, core->newConstantStringLatin1("]")); }
Atom VectorBaseObject::filter(ScriptObject *callback, Atom thisObject) { AvmCore* core = this->core(); VectorBaseObject *r = newVector(); if (!callback) return r->atom(); ScriptObject *d = this; uint32 len = m_length; // If thisObject is null, the call function will substitute the global object Atom args[4] = { thisObject, nullObjectAtom, nullObjectAtom, this->atom() }; for (uint32 i = 0, k = 0; i < len; i++) { args[1] = d->getUintProperty (i); // element args[2] = core->uintToAtom (i); // index Atom result = callback->call(3, args); if (result == trueAtom) { r->setUintProperty (k++, args[1]); } } return r->atom(); }
ArrayObject * ProgramClass::_getEnviron() { Toplevel *toplevel = this->toplevel(); AvmCore *core = this->core(); ArrayObject *array = toplevel->arrayClass()->newArray(); #if AVMSYSTEM_WIN32 wchar **cur = VMPI_GetEnviron16(); int i = 0; while( cur[i] ) { Stringp value = core->newStringUTF16(cur[i]); StUTF8String valueUTF8(value); array->setUintProperty( i, core->newStringUTF8( valueUTF8.c_str() )->atom() ); i++; } #else char **cur = VMPI_GetEnviron(); int i = 0; while( cur[i] ) { array->setUintProperty( i, core->newStringUTF8( cur[i] )->atom() ); i++; } #endif return array; }
Atom VectorBaseObject::filter(ScriptObject *callback, Atom thisObject) { AvmCore* core = this->core(); VectorBaseObject *r = newVector(); if (!callback) return r->atom(); ScriptObject *d = this; uint32 len = m_length; for (uint32 i = 0, k = 0; i < len; i++) { // If thisObject is null, the call function will substitute the global object // args are modified in place by callee Atom element = d->getUintProperty(i); Atom args[4] = { thisObject, element, core->uintToAtom(i), // index this->atom() }; Atom result = callback->call(3, args); if (result == trueAtom) r->setUintProperty(k++, element); } return r->atom(); }
// this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] Atom RegExpClass::construct(int argc, Atom* argv) { AvmCore* core = this->core(); Stringp pattern; Atom patternAtom = (argc>0) ? argv[1] : undefinedAtom; Atom optionsAtom = (argc>1) ? argv[2] : undefinedAtom; if (AvmCore::istype(patternAtom, traits()->itraits)) { // Pattern is a RegExp object if (optionsAtom != undefinedAtom) { // ECMA 15.10.4.1 says to throw an error if flags specified toplevel()->throwTypeError(kRegExpFlagsArgumentError); } // Return a clone of the RegExp object RegExpObject* regExpObject = (RegExpObject*)AvmCore::atomToScriptObject(patternAtom); return (new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(regExpObject))->atom(); } else { if (patternAtom != undefinedAtom) { pattern = core->string(argv[1]); } else { // cn: disable this, breaking ecma3 tests. was: todo look into this. it's what SpiderMonkey does. pattern = core->kEmptyString; //core->newConstantStringLatin1("(?:)"); } } Stringp options = NULL; if (optionsAtom != undefinedAtom) { options = core->string(optionsAtom); } RegExpObject* inst = new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(this, pattern, options); return inst->atom(); }
bool SamplerScript::set_stack(ScriptObject* self, ClassFactoryClass* cf, const Sample& sample, SampleObject* sam) { if (sample.stack.depth > 0) { Toplevel* toplevel = self->toplevel(); AvmCore* core = toplevel->core(); Sampler* s = core->get_sampler(); StackFrameClass* sfcc = (StackFrameClass*)cf->get_StackFrameClass(); ArrayObject* stack = toplevel->arrayClass()->newArray(sample.stack.depth); StackTrace::Element* e = (StackTrace::Element*)sample.stack.trace; for(uint32_t i=0; i < sample.stack.depth; i++, e++) { StackFrameObject* sf = sfcc->constructObject(); // at every allocation the sample buffer could overflow and the samples could be deleted // the StackTrace::Element pointer is a raw pointer into that buffer so we need to check // that its still around before dereferencing e uint32_t num; if (s->getSamples(num) == NULL) return false; sf->setconst_name(e->name()); // NOT e->info()->name() because e->name() can be a fake name sf->setconst_file(e->filename()); sf->setconst_line(e->linenum()); sf->setconst_scriptID(static_cast<double>(e->functionId())); stack->setUintProperty(i, sf->atom()); } sam->setconst_stack(stack); } return true; }
void SystemClass::trace(ArrayObject* a) { if (!a) toplevel()->throwArgumentError(kNullArgumentError, "array"); AvmCore* core = this->core(); PrintWriter& console = core->console; for (int i=0, n = a->getLength(); i < n; i++) { if (i > 0) console << ' '; Stringp s = core->string(a->getUintProperty(i)); for (int j = 0; j < s->length(); j++) { wchar c = (*s)[j]; // '\r' gets converted into '\n' // '\n' is left alone // '\r\n' is left alone if (c == '\r') { if (((j+1) < s->length()) && (*s)[j+1] == '\n') { console << '\r'; j++; } console << '\n'; } else { console << c; } } } console << '\n'; }
/** 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; }
/** 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; }
uint32_t ScriptObject::getLengthProperty() { Toplevel* toplevel = this->toplevel(); AvmCore* core = toplevel->core(); Multiname mname(core->getAnyPublicNamespace(), core->klength); Atom lenAtm = toplevel->getproperty(this->atom(), &mname, this->vtable); return AvmCore::toUInt32(lenAtm); }
void ScriptObject::setLengthProperty(uint32_t newLen) { Toplevel* toplevel = this->toplevel(); AvmCore* core = toplevel->core(); Multiname mname(core->getAnyPublicNamespace(), core->klength); Atom lenAtm = core->uintToAtom(newLen); toplevel->setproperty(this->atom(), &mname, lenAtm, this->vtable); }
ScriptObject* SamplerScript::makeSample(ScriptObject* self, ClassFactoryClass* cf, const Sample& sample) { Toplevel* toplevel = self->toplevel(); AvmCore* core = toplevel->core(); Sampler* s = core->get_sampler(); if (!s) return NULL; switch (sample.sampleType) { case Sampler::RAW_SAMPLE: { SampleClass* cls = (SampleClass*)cf->get_SampleClass(); SampleObject* sam = cls->constructObject(); sam->setconst_time(static_cast<double>(sample.micros)); if (!set_stack(self, cf, sample, sam)) return NULL; return sam; } case Sampler::DELETED_OBJECT_SAMPLE: { DeleteObjectSampleClass* cls = (DeleteObjectSampleClass*)cf->get_DeleteObjectSampleClass(); DeleteObjectSampleObject* dsam = cls->constructObject(); dsam->setconst_time(static_cast<double>(sample.micros)); dsam->setconst_id(static_cast<double>(sample.id)); dsam->setconst_size(static_cast<double>(sample.size)); return dsam; } case Sampler::NEW_OBJECT_SAMPLE: { NewObjectSampleClass* cls = (NewObjectSampleClass*)cf->get_NewObjectSampleClass(); NewObjectSampleObject* nsam = cls->constructObject(); nsam->setconst_time(static_cast<double>(sample.micros)); nsam->setconst_id(static_cast<double>(sample.id)); if (!set_stack(self, cf, sample, nsam)) return NULL; if (sample.ptr != NULL ) nsam->setRef((AvmPlusScriptableObject*)sample.ptr); nsam->setconst_type(getType(toplevel, sample.sot, sample.ptr)); nsam->setSize(sample.alloc_size); return nsam; } case Sampler::NEW_AUX_SAMPLE: { NewObjectSampleClass* cls = (NewObjectSampleClass*)cf->get_NewObjectSampleClass(); NewObjectSampleObject* nsam = cls->constructObject(); nsam->setconst_time(static_cast<double>(sample.micros)); nsam->setconst_id(static_cast<double>(sample.id)); if (!set_stack(self, cf, sample, nsam)) return NULL; nsam->setSize(sample.alloc_size); return nsam; } } AvmAssert(0); return NULL; }
AvmPlusScriptableObject::AvmPlusScriptableObject(Atom typeOrVTable) { AvmCore *core = this->core(); if(core->sampling()) { core->sampler()->recordAllocationInfo(this, (uintptr)typeOrVTable); } }
/*static*/ ChostentObject* CNetdbClass::gethostbyname(ScriptObject* self, Stringp name) { AvmCore *core = self->core(); Toplevel* toplevel = self->toplevel(); if( !name ) { toplevel->throwArgumentError(kNullArgumentError, "name"); } struct hostent *he; StUTF8String nameUTF8(name); he = VMPI_gethostbyname( nameUTF8.c_str() ); if( he ) { ShellToplevel* shelltop = (ShellToplevel*)self->toplevel(); ChostentClass *hc = shelltop->getShellClasses()->get_hostentClass(); ChostentObject *ho = hc->constructObject(); ho->set_h_name( core->newStringUTF8( he->h_name ) ); ArrayObject *aliases = toplevel->arrayClass()->newArray(); int count = 0; int i; for( i=0; he->h_aliases[i] != NULL; ++i ) { aliases->setUintProperty( count++, core->newStringUTF8( he->h_aliases[i] )->atom() ); } ho->set_h_aliases( aliases ); ho->set_h_addrtype( he->h_addrtype ); ho->set_h_length( he->h_length ); ArrayObject *addrlist = toplevel->arrayClass()->newArray(); count = 0; for( i=0; he->h_addr_list[i] != NULL; ++i ) { struct in_addr in; memcpy(&in.s_addr, he->h_addr_list[i], sizeof (in.s_addr)); CIn_AddrClass *ac = shelltop->getShellClasses()->get_in_addrClass(); CIn_AddrObject *ao = ac->constructObject(); ao->set_s_addr( in.s_addr ); addrlist->setUintProperty( count++, ao->toAtom() ); //addrlist->setUintProperty( count++, core->newStringUTF8( inet_ntoa(in) )->atom() ); } ho->set_h_addr_list( addrlist ); return ho; } return NULL; }
Atom ScriptObject::getUintProperty(uint32_t i) const { // N.B.: a key present in ScriptObject must be interned string; // thus uninterned implies absent (cf. bugzilla 556023). AvmCore* core = this->core(); if (!(i&MAX_INTEGER_MASK)) { if (!traits()->needsHashtable()) { Stringp interned; bool present = core->isInternedUint(i, &interned); if (present) { Atom name = interned->atom(); return getAtomPropertyFromProtoChain(name, delegate, traits()); } else { return undefinedAtom; } } else { // dynamic lookup on this object Atom name = core->uintToAtom (i); const ScriptObject *o = this; do { // ensure prototype is dynamic if (!o->vtable->traits->getHashtableOffset()) continue; Atom const value = o->getTable()->getNonEmpty(name); if (!InlineHashtable::isEmpty(value)) return value; } while ((o = o->delegate) != NULL); return undefinedAtom; } } else { Stringp interned; bool present; present = core->isInternedUint(i, &interned); if (present) { return getAtomProperty(interned->atom()); } else { return undefinedAtom; } } }
void CallStackNode::reset() { AvmCore* core = m_core; // save it since exit() resets to null if (core) { exit(); core->sampleCheck(); } }
Stringp FileClass::read(Stringp filename) { Toplevel* toplevel = this->toplevel(); AvmCore* core = this->core(); if (!filename) { toplevel->throwArgumentError(kNullArgumentError, "filename"); } StUTF8String filenameUTF8(filename); File* fp = Platform::GetInstance()->createFile(); if(!fp || !fp->open(filenameUTF8.c_str(), File::OPEN_READ)) { if(fp) { Platform::GetInstance()->destroyFile(fp); } toplevel->throwError(kFileOpenError, filename); } int64_t fileSize = fp->size(); if(fileSize >= (int64_t)INT32_T_MAX) //File APIs cannot handle files > 2GB { toplevel->throwRangeError(kOutOfRangeError, filename); } int len = (int)fileSize; MMgc::GC::AllocaAutoPtr _c; union { uint8_t* c; wchar* c_w; }; c = (uint8_t*)VMPI_alloca(core, _c, len+1); len = (int)fp->read(c, len); //need to force since the string creation functions expect an int c[len] = 0; fp->close(); Platform::GetInstance()->destroyFile(fp); if (len >= 3) { // UTF8 BOM if ((c[0] == 0xef) && (c[1] == 0xbb) && (c[2] == 0xbf)) { return core->newStringUTF8((const char*)c + 3, len - 3); } else if ((c[0] == 0xfe) && (c[1] == 0xff)) { //UTF-16 big endian c += 2; len = (len - 2) >> 1; return core->newStringEndianUTF16(/*littleEndian*/false, c_w, len); } else if ((c[0] == 0xff) && (c[1] == 0xfe))
Stringp HTTPFormClass::getFilename(Stringp key) { AvmCore *core = this->core(); string sKey(((StUTF8String) key).c_str()); for (std::vector<FormFile>::iterator it=sapi->files.begin(); it!=sapi->files.end(); it++) if (sKey == (*it).name) return core->newStringUTF8((*it).filename.data(), (*it).filename.length()); return NULL; }
FunctionObject* TraceClass::getListener() { FunctionObject* f = 0; #ifdef DEBUGGER AvmCore *core = this->core(); if (core->debugger()) f = core->debugger()->trace_callback; #endif /* DEBUGGER */ return f; }
ArrayObject* StringClass::_split(Stringp in, Atom delimAtom, uint32 limit) { AvmCore* core = this->core(); if (limit == 0) return toplevel()->arrayClass->newArray(); if (in->length() == 0) { ArrayObject* out = toplevel()->arrayClass->newArray(); out->setUintProperty(0,in->atom()); return out; } // handle RegExp case if (AvmCore::istype(delimAtom, core->traits.regexp_itraits)) { RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(delimAtom); return reObj->split(in, limit); } ArrayObject *out = toplevel()->arrayClass->newArray(); Stringp delim = core->string(delimAtom); int ilen = in->length(); int dlen = delim->length(); int count = 0; if (dlen <= 0) { // delim is empty string, split on each char for (int i = 0; i < ilen && (unsigned)i < limit; i++) { Stringp sub = in->substr(i, 1); out->setUintProperty(count++, sub->atom()); } return out; } int32_t start = 0; while (start <= in->length()) { if ((limit != 0xFFFFFFFFUL) && (count >= (int) limit)) break; int32_t bgn = in->indexOf(delim, start); if (bgn < 0) // not found, use the string remainder bgn = in->length(); Stringp sub = in->substring(start, bgn); out->setUintProperty(count++, sub->atom()); start = bgn + delim->length(); } return out; }
Stringp FileClass::read(Stringp filename) { Toplevel* toplevel = this->toplevel(); AvmCore* core = this->core(); if (!filename) { toplevel->throwArgumentError(kNullArgumentError, "filename"); } StUTF8String filenameUTF8(filename); File* fp = Platform::GetInstance()->createFile(); if(!fp || !fp->open(filenameUTF8.c_str(), File::OPEN_READ)) { if(fp) { Platform::GetInstance()->destroyFile(fp); } toplevel->throwError(kFileOpenError, filename); } int64_t fileSize = fp->size(); if(fileSize >= (int64_t)INT32_T_MAX) //File APIs cannot handle files > 2GB { toplevel->throwRangeError(kOutOfRangeError, filename); } int len = (int)fileSize; // Avoid VMPI_alloca - the buffer can be large and the memory is non-pointer-containing, // but the GC will scan it conservatively. uint8_t* c = (uint8_t*)core->gc->Alloc(len+1); len = (int)fp->read(c, len); //need to force since the string creation functions expect an int c[len] = 0; fp->close(); Platform::GetInstance()->destroyFile(fp); Stringp ret = NULL; if (len >= 3) { // UTF8 BOM if ((c[0] == 0xef) && (c[1] == 0xbb) && (c[2] == 0xbf)) { ret = core->newStringUTF8((const char*)c + 3, len - 3); } else if ((c[0] == 0xfe) && (c[1] == 0xff)) { //UTF-16 big endian c += 2; len = (len - 2) >> 1; ret = core->newStringEndianUTF16(/*littleEndian*/false, (wchar*)(void*)c, len); } else if ((c[0] == 0xff) && (c[1] == 0xfe))
ArrayObject* HTTPFormClass::listFileKeys() { AvmCore *core = this->core(); ArrayObject *out = this->toplevel()->arrayClass->newArray(); for (std::vector<FormFile>::iterator it=sapi->files.begin(); it!=sapi->files.end(); it++) { out->setUintProperty(out->get_length(), core->newStringUTF8((*it).name.data(), (*it).name.length())->atom()); } return out; }
QNameClass::QNameClass(VTable* cvtable) : ClassClosure(cvtable) { AvmAssert(traits()->getSizeOfInstance() == sizeof(QNameClass)); createVanillaPrototype(); AvmCore* core = this->core(); kUri = core->internConstantStringLatin1("uri")->atom(); kLocalName = core->internConstantStringLatin1("localName")->atom(); }
// E4X 13.3.1, page 66 // this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] Atom QNameClass::call(int argc, Atom* argv) { if (argc == 1) { AvmCore* core = this->core(); if (core->isObject(argv[1]) && AvmCore::istype(argv[1], core->traits.qName_itraits)) return argv[1]; } return construct (argc, argv); }
void FASTCALL CallStackNode::reset() { AvmCore* core = m_core; // save it since exit() resets to null if (core) { AvmAssert(core != NULL); core->callStack = m_next; m_next = NULL; m_core = NULL; // so the dtor doesn't pop again core->sampleCheck(); } }
ArrayObject * ProgramClass::_getArgv() { Toplevel *toplevel = this->toplevel(); AvmCore *core = this->core(); ArrayObject *array = toplevel->arrayClass()->newArray(); for( int i=0; i<user_argc; i++ ) { array->setUintProperty(i, core->newStringUTF8(user_argv[i])->atom()); } return array; }