Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
181 lines
6.4 KiB
C++
181 lines
6.4 KiB
C++
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
#include "avmshell.h"
|
|
|
|
#ifndef AVMSHELL_BUILD
|
|
#error "This file is only for use with avmshell"
|
|
#endif
|
|
|
|
namespace avmplus
|
|
{
|
|
using namespace avmshell;
|
|
|
|
DomainObject::DomainObject(VTable *vtable, ScriptObject *delegate)
|
|
: ScriptObject(vtable, delegate)
|
|
, domainEnv(delegate->core()->codeContext()->domainEnv())
|
|
, domainToplevel(delegate->toplevel())
|
|
{
|
|
}
|
|
|
|
void DomainObject::init(DomainObject* parentDomain)
|
|
{
|
|
ShellCore* core = (ShellCore*) this->core();
|
|
|
|
DomainEnv* baseDomainEnv = parentDomain ?
|
|
(DomainEnv*)parentDomain->domainEnv :
|
|
(DomainEnv*)NULL;
|
|
Domain* baseDomain = baseDomainEnv ?
|
|
baseDomainEnv->domain() :
|
|
NULL;
|
|
|
|
domainToplevel = parentDomain ?
|
|
(Toplevel*)parentDomain->domainToplevel :
|
|
core->createShellToplevel();
|
|
|
|
Domain* domain = Domain::newDomain(core, baseDomain);
|
|
domainEnv = DomainEnv::newDomainEnv(core, domain, parentDomain ? (DomainEnv*)parentDomain->domainEnv : (DomainEnv*)NULL);
|
|
}
|
|
|
|
Atom DomainObject::loadBytes(ByteArrayObject* b, uint32_t swfVersion)
|
|
{
|
|
AvmCore* core = this->core();
|
|
if (!b)
|
|
toplevel()->throwTypeError(kNullArgumentError, core->toErrorString("bytes"));
|
|
|
|
// 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;
|
|
ApiVersion apiVersion = core->getApiVersionFromCallStack();
|
|
|
|
// parse constants and attributes.
|
|
PoolObject* pool = core->parseActionBlock(code,
|
|
/*start*/0,
|
|
toplevel,
|
|
domainEnv->domain(),
|
|
/*ninit*/NULL,
|
|
apiVersion);
|
|
|
|
|
|
// by default, use the same bugCompatibility as the builtins use
|
|
const BugCompatibility* bugCompatibility = toplevel->abcEnv()->codeContext()->bugCompatibility();
|
|
if (swfVersion != 0)
|
|
{
|
|
// ...unless specified otherwise.
|
|
for (int j = 0; j < BugCompatibility::VersionCount; ++j)
|
|
{
|
|
if (BugCompatibility::kNames[j] == swfVersion)
|
|
{
|
|
bugCompatibility = core->createBugCompatibility((BugCompatibility::Version)j);
|
|
goto done;
|
|
}
|
|
}
|
|
// if we get here, didn't find a valid name
|
|
toplevel->throwTypeError(kInvalidArgumentError, core->toErrorString("swfVersion"));
|
|
}
|
|
done:
|
|
|
|
ShellCodeContext* codeContext = new (core->GetGC()) ShellCodeContext(domainEnv, bugCompatibility);
|
|
return core->handleActionPool(pool, toplevel, codeContext);
|
|
}
|
|
|
|
ScriptObject* DomainObject::finddef(const Multiname& multiname,
|
|
DomainEnv* domainEnv)
|
|
{
|
|
Toplevel* toplevel = this->toplevel();
|
|
|
|
ScriptEnv* script = core()->domainMgr()->findScriptEnvInDomainEnvByMultiname(domainEnv, multiname);
|
|
if (script == (ScriptEnv*)BIND_AMBIGUOUS)
|
|
toplevel->throwReferenceError(kAmbiguousBindingError, multiname);
|
|
|
|
if (script == (ScriptEnv*)BIND_NONE)
|
|
toplevel->throwReferenceError(kUndefinedVarError, multiname);
|
|
|
|
if (script->global == NULL)
|
|
{
|
|
script->initGlobal();
|
|
script->coerceEnter(script->global->atom());
|
|
}
|
|
|
|
return script->global;
|
|
}
|
|
|
|
ClassClosure* DomainObject::getClass(Stringp name)
|
|
{
|
|
Toplevel* toplevel = this->toplevel();
|
|
AvmCore* core = toplevel->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, Namespace::NS_Public, core->getApiVersionFromCallStack()));
|
|
className = core->internString(name->substring(dot+1, name->length()));
|
|
} else {
|
|
ns = core->findPublicNamespace();
|
|
className = core->internString(name);
|
|
}
|
|
|
|
Multiname multiname(ns, className);
|
|
|
|
ScriptObject *container = finddef(multiname, domainEnv);
|
|
if (!container) {
|
|
toplevel->throwTypeError(kClassNotFoundError, core->toErrorString(&multiname));
|
|
}
|
|
Atom atom = toplevel->getproperty(container->atom(),
|
|
&multiname,
|
|
container->vtable);
|
|
|
|
// Note: this used to throw "kClassNotFoundError" if the class wasn't
|
|
// found; now it throws "kCheckTypeFailedError" (by way of coerceToType).
|
|
// This probably doesn't matter since this is a shell-only class, and it
|
|
// gives us a testcase for coerceToType.
|
|
return toplevel->builtinClasses()->get_ClassClass()->coerceToType(atom);
|
|
}
|
|
|
|
DomainClass::DomainClass(VTable *cvtable)
|
|
: ClassClosure(cvtable)
|
|
{
|
|
createVanillaPrototype();
|
|
}
|
|
|
|
DomainObject* DomainClass::get_currentDomain()
|
|
{
|
|
return (DomainObject*) newInstance();
|
|
}
|
|
|
|
int DomainClass::get_MIN_DOMAIN_MEMORY_LENGTH()
|
|
{
|
|
return DomainEnv::GLOBAL_MEMORY_MIN_SIZE;
|
|
}
|
|
|
|
ByteArrayObject* DomainObject::get_domainMemory() const
|
|
{
|
|
return (ByteArrayObject*)domainEnv->get_globalMemory();
|
|
}
|
|
|
|
void DomainObject::set_domainMemory(ByteArrayObject* mem)
|
|
{
|
|
if(!domainEnv->set_globalMemory(mem))
|
|
toplevel()->throwError(kEndOfFileError);
|
|
}
|
|
}
|