Files
avmplus/core/DomainEnv.cpp
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

137 lines
5.2 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 "avmplus.h"
namespace avmplus
{
DomainEnv::DomainEnv(AvmCore* core, Domain* domain, DomainEnv* base, uint32_t baseCount)
: m_scriptEnvMap(ScriptEnvMap::create(core->GetGC()))
, m_domain(domain)
, m_globalMemoryScratch(mmfx_new0(Scratch))
, m_globalMemoryBase(m_globalMemoryScratch->scratch)
, m_globalMemorySize(GLOBAL_MEMORY_MIN_SIZE)
, m_baseCount(baseCount)
{
WB(core->GetGC(), this, &this->m_bases[0], this);
for (uint32_t i = 1; i < baseCount; ++i)
{
WB(core->GetGC(), this, &this->m_bases[i], base->m_bases[i-1]);
}
#ifdef _DEBUG
GCList<Domain> dl(core->GetGC(), 0);
for (Domain* di = m_domain; di != NULL; di = di->base())
dl.add(di);
GCList<DomainEnv> el(core->GetGC(), 0);
for (DomainEnv* di = this; di != NULL; di = di->base())
el.add(di);
AvmAssert(dl.length() == el.length());
for (uint32_t i = 0, n = el.length(); i < n; ++i)
{
Domain* d = dl[i];
DomainEnv* e = el[i];
AvmAssert(e->domain() == d);
}
#endif
}
DomainEnv* DomainEnv::newDomainEnv(AvmCore* core, Domain* domain, DomainEnv* base)
{
uint32_t baseCount = (base ? base->m_baseCount : 0) + 1;
// Note that we deliberately overallocate by one here (the proper
// amount is baseCount-1) so that we always have one, zeroed-out
// entry at the end. This allows us to always use "m_bases[1]"
// to get our immediate base, even if our base is NULL, thus
// avoiding a check in the implementation of base().
uint32_t extra = baseCount * sizeof(DomainEnv*);
DomainEnv* domainEnv = new (core->GetGC(), MMgc::kExact, extra) DomainEnv(core, domain, base, baseCount);
core->m_domainEnvs.add(domainEnv);
return domainEnv;
}
DomainEnv::~DomainEnv()
{
mmfx_delete(m_globalMemoryScratch);
}
Toplevel* DomainEnv::toplevel() const
{
if(m_toplevel) return m_toplevel;
if(base()) return base()->toplevel();
AvmAssert(0);
return NULL;
}
bool DomainEnv::set_globalMemory(ByteArrayObject* providerObject)
{
if (!providerObject)
{
// null obj -- use scratch
if (m_globalMemoryProviderObject) // unsubscribe from current if any
globalMemoryUnsubscribe(m_globalMemoryProviderObject);
// remember NULL obj
m_globalMemoryProviderObject = NULL;
// point at scratch mem
notifyGlobalMemoryChanged(m_globalMemoryScratch->scratch, GLOBAL_MEMORY_MIN_SIZE);
}
else if (!globalMemorySubscribe(providerObject))
{
// failed... do nothing
return false;
}
else
{
// success on globalMemorySubscribe would have led to notifyGlobalMemoryChanged
// success... unsubscribe from original, but only if not the same as new provider
if (m_globalMemoryProviderObject && m_globalMemoryProviderObject != providerObject)
globalMemoryUnsubscribe(m_globalMemoryProviderObject);
// remember the new one
m_globalMemoryProviderObject = providerObject;
}
return true;
}
// memory changed so go through and update all reference to both the base
// and the size of the global memory
void DomainEnv::notifyGlobalMemoryChanged(uint8_t* newBase, uint32_t newSize)
{
AvmAssert(newBase != NULL); // real base address
AvmAssert(newSize >= GLOBAL_MEMORY_MIN_SIZE); // big enough
m_globalMemoryBase = newBase;
// We require that MOps addresses be non-negative int32 values.
// Furthermore, the bounds checks may fail to detect an out-of-bounds
// access if the global memory size is not itself a non-negative int32.
// See bug 723401. Since the size of a byte array may expand as
// side-effect of other operations according to a policy not under direct
// control of the user, it is not appropriate to signal an error here.
// We simply silently ignore any excess allocation.
// TODO: While we cannot do much about automatic resizing, an attempt
// to explicitly set the size too large should throw an exception before
// arriving here.
m_globalMemorySize = (newSize > 0x7fffffff) ? 0x7fffffff : newSize;
TELEMETRY_UINT32(toplevel()->core()->getTelemetry(), ".mem.bytearray.alchemy",m_globalMemorySize/1024);
}
bool DomainEnv::globalMemorySubscribe(ByteArrayObject* providerObject)
{
return providerObject->GetByteArray().addSubscriber(this);
}
bool DomainEnv::globalMemoryUnsubscribe(ByteArrayObject* providerObject)
{
return providerObject->GetByteArray().removeSubscriber(this);
}
}