// 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 }
void ObjectClass::initPrototype() { // patch global.__proto__ = Object.prototype Toplevel* toplevel = this->toplevel(); toplevel->setDelegate( prototype ); // global.__proto__ = Object.prototype this->setDelegate( toplevel->classClass->prototype ); // Object.__proto__ = Class.prototype }
/*static*/ int CSysStatClass::fstat(ScriptObject* self, int fildes, CStatusObject* buf) { Toplevel* toplevel = self->toplevel(); if (!buf) { toplevel->throwArgumentError(kNullArgumentError, "buf"); } struct stat statbuf; int result = VMPI_fstat( fildes, &statbuf ); if( result != -1 ) { buf->set_st_dev( statbuf.st_dev ); buf->set_st_ino( statbuf.st_ino ); buf->set_st_mode( statbuf.st_mode ); buf->set_st_nlink( statbuf.st_nlink ); buf->set_st_uid( statbuf.st_uid ); buf->set_st_gid( statbuf.st_gid ); buf->set_st_rdev( statbuf.st_rdev ); buf->set_st_size( (double) statbuf.st_size ); buf->set_st_atime( (double) statbuf.st_atime ); buf->set_st_mtime( (double) statbuf.st_mtime ); buf->set_st_ctime( (double) statbuf.st_ctime ); } return result; }
/*static*/ CprotoentObject* CNetdbClass::getprotoent(ScriptObject* self) { struct protoent *pp; pp = VMPI_getprotoent(); if( pp ) { ShellToplevel* shelltop = (ShellToplevel*)self->toplevel(); CprotoentClass *pc = shelltop->getShellClasses()->get_protoentClass(); CprotoentObject *po = pc->constructObject(); po->set_p_name( self->core()->newStringUTF8( pp->p_name ) ); po->set_p_proto( pp->p_proto ); Toplevel* toplevel = self->toplevel(); ArrayObject *aliases = toplevel->arrayClass()->newArray(); int count = 0; int i; for( i=0; pp->p_aliases[i] != NULL; ++i ) { aliases->setUintProperty( count++, self->core()->newStringUTF8( pp->p_aliases[i] )->atom()); } po->set_p_aliases( aliases ); return po; } return NULL; }
Atom Stubs::do_abc_getpropnsx(MethodFrame* f, const Multiname* name, Atom ns, Atom index, Atom object) { Multiname tempname; initnamensx(env(f), name, ns, index, &tempname); Toplevel* t = toplevel(f); return t->getproperty(object, &tempname, toVTable(t, object)); }
/*static*/ int CStdlibClass::setenv(ScriptObject* self, Stringp name, Stringp value, bool overwrite) { Toplevel* toplevel = self->toplevel(); if( !name ) { toplevel->throwArgumentError(kNullArgumentError, "name"); } if( !value ) { toplevel->throwArgumentError(kNullArgumentError, "value"); } int writeover = 0; if( overwrite ) { writeover = 1; } #if AVMSYSTEM_WIN32 StUTF16String nameUTF16(name); StUTF16String valueUTF16(value); return VMPI_setenv16( nameUTF16.c_str(), valueUTF16.c_str(), writeover ); #else StUTF8String nameUTF8(name); StUTF8String valueUTF8(value); return VMPI_setenv( nameUTF8.c_str(), valueUTF8.c_str(), writeover ); #endif }
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; }
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; }
/*static*/ int CStdlibClass::putenv(ScriptObject* self, Stringp name) { Toplevel* toplevel = self->toplevel(); if( !name ) { toplevel->throwArgumentError(kNullArgumentError, "name"); } #if AVMSYSTEM_WIN32 StUTF16String nameUTF16(name); wchar * str = VMPI_strdup16( nameUTF16.c_str() ); int result = VMPI_putenv16( str ); #else StUTF8String nameUTF8(name); char * str = VMPI_strdup( nameUTF8.c_str() ); int result = VMPI_putenv( str ); #endif /* note: do not free() after strdup() or the string ref will be lost so yeah it create a small memory leak need to investigate if AVM2 intern string can solve this or maybe create a special string pool to save such ref that we could clean before the VM exit */ //VMPI_free(str); return result; }
void Stubs::do_abc_setpropnsx(MethodFrame* f, const Multiname* name, Atom ns, Atom index, Atom object, Atom value) { Multiname tempname; initnamensx(env(f), name, ns, index, &tempname); Toplevel* t = toplevel(f); t->setproperty(object, &tempname, value, toVTable(t, object)); }
/*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; }
Atom Stubs::do_abc_callpropx(MethodFrame* f, const Multiname* name, Atom index, int argc, Atom* args) { Multiname tempname; initnamex(core(f), name, index, &tempname); Toplevel* t = toplevel(f); return t->callproperty(args[0], &tempname, argc - 1, args, toVTable(t, args[0])); }
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; }
// this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] Atom ScriptObject::callProperty(const Multiname* multiname, int argc, Atom* argv) { Toplevel* toplevel = this->toplevel(); Atom method = getMultinameProperty(multiname); if (!AvmCore::isObject(method)) toplevel->throwTypeError(kCallOfNonFunctionError, core()->toErrorString(multiname)); argv[0] = atom(); // replace receiver return toplevel->op_call(method, argc, argv); }
/*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; }
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))
// this = argv[0] // arg1 = argv[1] // argN = argv[argc] Atom ClassClosure::call(int argc, Atom* argv) { Toplevel* toplevel = this->toplevel(); // explicit coercion of a class object. if (argc != 1) { toplevel->throwArgumentError(kCoerceArgumentCountError, toplevel->core()->toErrorString(argc)); } return toplevel->coerce(argv[1], (Traits*)ivtable()->traits); }
/*static*/ int CSysSelectClass::select(ScriptObject* self, int nfds, Cfd_setObject* readfds, Cfd_setObject* writefds, Cfd_setObject* errorfds, CtimevalObject* timeout) { Toplevel* toplevel = self->toplevel(); if( !timeout ) { toplevel->throwArgumentError(kNullArgumentError, "timeout"); } struct timeval tv; tv = timeout->toStruct(); int result = -1; if( !readfds && !writefds && !errorfds ) { result = VMPI_select( nfds, NULL, NULL, NULL, &tv ); } else if( !writefds && !errorfds ) { result = VMPI_select( nfds, &readfds->fds, NULL, NULL, &tv ); } else if( !errorfds ) { result = VMPI_select( nfds, &readfds->fds, &writefds->fds, NULL, &tv ); } else if( !writefds ) { result = VMPI_select( nfds, &readfds->fds, NULL, &errorfds->fds, &tv ); } else if( !readfds ) { result = VMPI_select( nfds, NULL, &writefds->fds, &errorfds->fds, &tv ); } else if( !readfds && !writefds ) { result = VMPI_select( nfds, NULL, NULL, &errorfds->fds, &tv ); } else if( !readfds && !errorfds ) { result = VMPI_select( nfds, NULL, &writefds->fds, NULL, &tv ); } else { result = VMPI_select( nfds, &readfds->fds, &writefds->fds, &errorfds->fds, &tv ); } if( result != -1 ) { timeout->fromStruct( tv ); } return result; }
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))
/*static*/ int CDirentClass::dirfd(ScriptObject* self, CDIRObject* dirp) { Toplevel* toplevel = self->toplevel(); if( !dirp ) { toplevel->throwArgumentError(kNullArgumentError, "dirp"); } return VMPI_dirfd( dirp->read() ); }
/*static*/ void CDirentClass::seekdir(ScriptObject* self, CDIRObject* dirp, double loc) { Toplevel* toplevel = self->toplevel(); if( !dirp ) { toplevel->throwArgumentError(kNullArgumentError, "dirp"); } VMPI_seekdir( dirp->read(), (off_t) loc ); }
/*static*/ double CDirentClass::telldir(ScriptObject* self, CDIRObject* dirp) { Toplevel* toplevel = self->toplevel(); if( !dirp ) { toplevel->throwArgumentError(kNullArgumentError, "dirp"); } return (double)VMPI_telldir( dirp->read() ); }
/*static*/ void CDirentClass::rewinddir(ScriptObject* self, CDIRObject* dirp) { Toplevel* toplevel = self->toplevel(); if( !dirp ) { toplevel->throwArgumentError(kNullArgumentError, "dirp"); } VMPI_rewinddir( dirp->read() ); }
/*static*/ void CSysSelectClass::_avm_FD_ZERO(ScriptObject* self, Cfd_setObject* fdsetp) { Toplevel* toplevel = self->toplevel(); if( !fdsetp ) { toplevel->throwArgumentError(kNullArgumentError, "fdsetp"); } VMPI_FD_ZERO( &fdsetp->fds ); }
void Stubs::do_abc_setpropx(MethodFrame* f, const Multiname* name, Atom index, Atom object, Atom value) { if (!AvmCore::isDictionaryLookup(index, object)) { Multiname tempname; initnamex(core(f), name, index, &tempname); Toplevel* t = toplevel(f); t->setproperty(object, &tempname, value, toVTable(t, object)); } else { // dictionary[index] = value AvmCore::atomToScriptObject(object)->setAtomProperty(index, value); } }
/*static*/ int CStdlibClass::mblen(ScriptObject* self, Stringp s, int i) { Toplevel* toplevel = self->toplevel(); if( !s ) { toplevel->throwArgumentError(kNullArgumentError, "s"); } StUTF8String sUTF8(s); return VMPI_mblen( sUTF8.c_str(), i ); }
/*static*/ int CStdlibClass::mkstemp(ScriptObject* self, Stringp templ) { Toplevel* toplevel = self->toplevel(); if( !templ ) { toplevel->throwArgumentError(kNullArgumentError, "template"); } StUTF8String templateUTF8(templ); return VMPI_mkstemp( (char*)templateUTF8.c_str() ); }
/*static*/ double CStdlibClass::atol(ScriptObject* self, Stringp str) { Toplevel* toplevel = self->toplevel(); if (!str) { toplevel->throwArgumentError(kNullArgumentError, "str"); } StUTF8String strUTF8(str); return VMPI_atol( strUTF8.c_str() ); }