Files
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

679 lines
23 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"
#ifdef VMCFG_EVAL
#include "eval.h"
namespace avmplus
{
namespace RTC
{
using namespace ActionBlockConstants;
template<class T> static uint32_t computeSize(Seq<T>* xs)
{
uint32_t size = 0;
for ( ; xs != NULL ; xs = xs->tl )
size += xs->hd->size();
return size;
}
template<class T> static uint8_t* serializeSeq(uint8_t* b, Seq<T>* xs)
{
for ( ; xs != NULL ; xs = xs->tl )
b = xs->hd->serialize(b);
return b;
}
template<class T> static uint32_t length(Seq<T>* xs)
{
uint32_t n = 0;
for ( ; xs != NULL ; xs = xs->tl )
n++;
return n;
}
static uint8_t* emitBytes(uint8_t* buf, ByteBuffer * const src)
{
uint32_t nbytes = src->size();
src->serialize(buf);
return buf + nbytes;
}
// Never called, but gcc gets very annoyed if a class with virtual methods does not
// have a virtual destructor.
ABCChunk::~ABCChunk()
{
}
ABCFile::ABCFile(Compiler* compiler)
#ifdef VMCFG_FLOAT
: major_version(47)
, minor_version(16)
#else
: major_version(46)
, minor_version(16)
#endif
, NO_VALUE(~0U)
, compiler(compiler)
, allocator(compiler->allocator)
, intCount(1) // entry 0 not present
, uintCount(1) // entry 0 not present
, doubleCount(1) // entry 0 not present
, floatCount(1) // entry 0 not present
, float4Count(1) // entry 0 not present
, stringCount(1) // entry 0 not present
, namespaceCount(1) // entry 0 not present
, nssetCount(1) // entry 0 not present
, multinameCount(1) // entry 0 not present
, methodCount(0)
, metadataCount(0)
, instanceCount(0)
, classCount(0)
, scriptCount(0)
, nonemptyMethodBodyCount(0)
, intBuf(allocator, 16)
, uintBuf(allocator, 16)
, doubleBuf(allocator, 32)
, floatBuf(allocator, 32)
, float4Buf(allocator, 32)
, stringBuf(allocator)
, namespaceBuf(allocator, 16)
, nssetBuf(allocator, 16)
, multinameBuf(allocator, 16)
, namespaces(allocator)
, namespaceSets(allocator)
, multinames(allocator)
, methods(allocator)
, metadatas(allocator)
, instances(allocator)
, classes(allocator)
, scripts(allocator)
, bodies(allocator)
{
}
uint32_t ABCFile::addInt(int32_t i)
{
intBuf.emitS32(i);
return intCount++;
}
uint32_t ABCFile::addUInt(uint32_t u)
{
uintBuf.emitU32(u);
return uintCount++;
}
uint32_t ABCFile::addDouble(double d)
{
doubleBuf.emitDouble(d);
return doubleCount++;
}
#ifdef VMCFG_FLOAT
uint32_t ABCFile::addFloat(float f)
{
floatBuf.emitFloat(f);
return floatCount++;
}
uint32_t ABCFile::addFloat4(const float4_t& f4)
{
float4Buf.emitFloat4(f4);
return float4Count++;
}
#endif
uint32_t ABCFile::addString(Str* s)
{
if (s->ident == ~0U) {
s->ident = stringCount++;
uint32_t len = utf8length(s);
stringBuf.emitU30(len);
stringBuf.emitUtf8(len, s);
}
return s->ident;
}
uint32_t ABCFile::addString(const char* s)
{
return addString(compiler->intern(s));
}
uint32_t ABCFile::addNamespace(uint8_t kind, uint32_t name)
{
uint32_t i;
Seq<ABCNamespaceInfo*>* nss;
for ( nss = namespaces.get(), i=1 ; nss != NULL ; nss = nss->tl, i++ )
if (nss->hd->kind == kind && nss->hd->name == name)
return i;
namespaceBuf.emitU8(kind);
namespaceBuf.emitU30(name);
namespaces.addAtEnd(ALLOC(ABCNamespaceInfo, (kind, name)));
return namespaceCount++;
}
uint32_t ABCFile::addNsset(Seq<uint32_t>* nss)
{
uint32_t length = 0;
uint32_t i, j;
Seq<uint32_t>* tmp;
for ( tmp=nss ; tmp != NULL ; tmp=tmp->tl)
length++;
Seq<ABCNamespaceSetInfo*>* nsss;
for ( nsss = namespaceSets.get(), i=1 ; nsss != NULL ; nsss = nsss->tl, i++ ) {
if (length == nsss->hd->length) {
for ( tmp=nss, j=0 ; j < length ; tmp=tmp->tl, j++ )
if (nsss->hd->ns[j] != tmp->hd)
goto loop_end;
return i;
}
}
loop_end:
ABCNamespaceSetInfo* info = new (allocator->alloc(sizeof(ABCNamespaceSetInfo) + (length-1)*sizeof(uint32_t))) ABCNamespaceSetInfo(length);
nssetBuf.emitU30(length);
for ( tmp=nss, j=0 ; tmp != NULL ; tmp=tmp->tl ) {
info->ns[j] = tmp->hd;
nssetBuf.emitU30(tmp->hd);
}
return nssetCount++;
}
uint32_t ABCFile::multinameLookup(uint8_t kind, uint32_t ns_or_nsset, uint32_t name)
{
Seq<ABCMultinameInfo*>* mns;
uint32_t i;
for ( mns = multinames.get(), i=1 ; mns != NULL ; mns = mns->tl, i++ )
if (mns->hd->kind == kind && mns->hd->ns_or_nsset == ns_or_nsset && mns->hd->name == name)
return i;
multinameBuf.emitU8(kind);
switch (kind) {
case CONSTANT_QnameA:
case CONSTANT_Qname:
multinameBuf.emitU30(ns_or_nsset);
multinameBuf.emitU30(name);
break;
case CONSTANT_RTQnameA:
case CONSTANT_RTQname:
multinameBuf.emitU30(name);
break;
case CONSTANT_RTQnameLA:
case CONSTANT_RTQnameL:
break;
case CONSTANT_MultinameA:
case CONSTANT_Multiname:
multinameBuf.emitU30(name);
multinameBuf.emitU30(ns_or_nsset);
break;
case CONSTANT_MultinameLA:
case CONSTANT_MultinameL:
multinameBuf.emitU30(ns_or_nsset);
break;
case CONSTANT_TypeName:
multinameBuf.emitU30(ns_or_nsset); // really the parameterizedType, eg, __AS3__.vec::Vector
multinameBuf.emitU30(1); // Must be 1
multinameBuf.emitU30(name); // really the parameterType
break;
default:
compiler->internalError(0, "Invalid multiname kind");
}
multinames.addAtEnd(ALLOC(ABCMultinameInfo, (kind, ns_or_nsset, name)));
return multinameCount++;
}
ABCMultinameInfo* ABCFile::getMultiname(uint32_t index)
{
Seq<ABCMultinameInfo*>* mns;
for ( mns = multinames.get() ; index > 1 ; mns = mns->tl, index-- )
;
return mns->hd;
}
bool ABCFile::hasRTNS(uint32_t index)
{
switch (getMultiname(index)->kind) {
case CONSTANT_RTQname:
case CONSTANT_RTQnameA:
case CONSTANT_RTQnameL:
case CONSTANT_RTQnameLA:
return true;
default:
return false;
}
}
bool ABCFile::hasRTName(uint32_t index)
{
switch (getMultiname(index)->kind) {
case CONSTANT_RTQnameL:
case CONSTANT_RTQnameLA:
case CONSTANT_MultinameL:
case CONSTANT_MultinameLA:
return true;
default:
return false;
}
}
uint32_t ABCFile::size()
{
AvmAssert(scriptCount != 0);
AvmAssert(methodCount != 0);
AvmAssert(classCount == instanceCount);
uint32_t method_size = computeSize(methods.get());
uint32_t metadata_size = computeSize(metadatas.get());
uint32_t instance_size = computeSize(instances.get());
uint32_t class_size = computeSize(classes.get());
uint32_t script_size = computeSize(scripts.get());
uint32_t body_size = computeSize(bodies.get());
reported_size = (4 +
lenU30(intCount) + intBuf.size() +
lenU30(uintCount) + uintBuf.size() +
lenU30(doubleCount) + doubleBuf.size() +
#ifdef VMCFG_FLOAT
lenU30(floatCount) + floatBuf.size() +
lenU30(float4Count) + float4Buf.size() +
#endif
lenU30(stringCount) + stringBuf.size() +
lenU30(namespaceCount) + namespaceBuf.size() +
lenU30(nssetCount) + nssetBuf.size() +
lenU30(multinameCount) + multinameBuf.size() +
lenU30(methodCount) + method_size +
lenU30(metadataCount) + metadata_size +
lenU30(instanceCount) + instance_size + class_size +
lenU30(scriptCount) + script_size +
lenU30(nonemptyMethodBodyCount) + body_size);
return reported_size;
}
uint8_t* ABCFile::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU16(b, minor_version);
b = emitU16(b, major_version);
b = emitU30(b, intCount);
b = emitBytes(b, &intBuf);
b = emitU30(b, uintCount);
b = emitBytes(b, &uintBuf);
b = emitU30(b, doubleCount);
b = emitBytes(b, &doubleBuf);
#ifdef VMCFG_FLOAT
b = emitU30(b, floatCount);
b = emitBytes(b, &floatBuf);
b = emitU30(b, float4Count);
b = emitBytes(b, &float4Buf);
#endif
b = emitU30(b, stringCount);
b = emitBytes(b, &stringBuf);
b = emitU30(b, namespaceCount);
b = emitBytes(b, &namespaceBuf);
b = emitU30(b, nssetCount);
b = emitBytes(b, &nssetBuf);
b = emitU30(b, multinameCount);
b = emitBytes(b, &multinameBuf);
b = emitU30(b, methodCount);
b = serializeSeq(b, methods.get());
b = emitU30(b, metadataCount);
b = serializeSeq(b, metadatas.get());
b = emitU30(b, instanceCount);
b = serializeSeq(b, instances.get());
b = serializeSeq(b, classes.get());
b = emitU30(b, scriptCount);
b = serializeSeq(b, scripts.get());
b = emitU30(b, nonemptyMethodBodyCount);
b = serializeSeq(b, bodies.get());
AvmAssert( b == b0 + reported_size );
return b;
}
ABCTraitsTable::ABCTraitsTable(Compiler* compiler)
: traitsCount(0)
, traits(compiler->allocator)
{
}
uint32_t ABCTraitsTable::size()
{
reported_size = lenU30(traitsCount) + computeSize(traits.get());
return reported_size;
}
uint8_t* ABCTraitsTable::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU30(b, traitsCount);
b = serializeSeq(b, traits.get());
AvmAssert( b == b0 + reported_size );
return b;
}
uint32_t ABCTrait::size()
{
// no provision for metadata
reported_size = (lenU30(name) +
1 /* kind */ +
dataSize());
return reported_size;
}
uint8_t *ABCTrait::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU30(b, name);
AvmAssert(kind < 8);
*b++ = (uint8_t)kind;
b = serializeData(b);
AvmAssert( b == b0 + reported_size );
return b;
}
uint32_t ABCSlotTrait::dataSize()
{
uint32_t slot_id = 0, vindex = 0;
return (lenU30(slot_id) +
lenU30(type_name) +
lenU30(vindex) +
(vindex != 0 ? 1 : 0));
}
uint8_t* ABCSlotTrait::serializeData(uint8_t *b)
{
uint32_t slot_id = 0, vindex = 0, vkind = 0;
b = emitU30(b, slot_id);
b = emitU30(b, type_name);
b = emitU30(b, vindex);
if (vindex != 0)
*b++ = (uint8_t)vkind;
return b;
}
uint32_t ABCMethodTrait::dataSize()
{
uint32_t disp_id = 0;
return (lenU30(disp_id) + lenU30(method_info));
}
uint8_t* ABCMethodTrait::serializeData(uint8_t* b)
{
uint32_t disp_id = 0;
b = emitU30(b, disp_id);
b = emitU30(b, method_info);
return b;
}
uint32_t ABCClassTrait::dataSize()
{
return (lenU30(slot_id) + lenU30(index));
}
uint8_t* ABCClassTrait::serializeData(uint8_t* b)
{
b = emitU30(b, slot_id);
b = emitU30(b, index);
return b;
}
ABCScriptInfo::ABCScriptInfo(Compiler* compiler, ABCMethodInfo* init_method, ABCTraitsTable* traits)
: index(compiler->abc.addScript(this))
, init_method(init_method)
, traits(traits)
{
}
uint32_t ABCScriptInfo::size()
{
reported_size = (lenU30(init_method->index) + traits->size());
return reported_size;
}
uint8_t *ABCScriptInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU30(b, init_method->index);
b = traits->serialize(b);
AvmAssert( b == b0 + reported_size );
return b;
}
ABCMethodBodyInfo::ABCMethodBodyInfo(Compiler* compiler, ABCMethodInfo* method_info, ABCTraitsTable* traits, uint32_t first_temp, bool is_empty)
: cogen(compiler, &compiler->abc, traits, this, first_temp)
, exceptions(compiler)
, method_info(method_info)
, traits(traits)
, is_empty(is_empty)
{
compiler->abc.addMethodBody(this);
}
uint32_t ABCMethodBodyInfo::size()
{
if (is_empty)
reported_size = 0;
else
reported_size = (lenU30(method_info->index) +
lenU30(cogen.getMaxStack()) +
lenU30(cogen.getLocalCount()) +
lenU30(0) /* init_scope_depth */ +
lenU30(cogen.getMaxScope()) +
lenU30(cogen.getCodeLength()) +
cogen.getCodeLength() +
exceptions.size() +
(traits ? traits->size() : lenU30(0)));
return reported_size;
}
uint8_t* ABCMethodBodyInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
if (!is_empty) {
b = emitU30(b, method_info->index);
b = emitU30(b, cogen.getMaxStack());
b = emitU30(b, cogen.getLocalCount());
b = emitU30(b, 0); /* init_scope_depth */
b = emitU30(b, cogen.getMaxScope());
b = emitU30(b, cogen.getCodeLength());
b = cogen.serializeCodeBytes(b);
b = exceptions.serialize(b);
b = (traits ? traits->serialize(b) : emitU30(b, 0));
}
AvmAssert( b == b0 + reported_size );
return b;
}
ABCMethodInfo::ABCMethodInfo(Compiler* compiler,
uint32_t name,
uint32_t param_count,
Seq<uint32_t>* param_types,
uint32_t option_count,
Seq<DefaultValue*>* default_values,
uint32_t return_type)
: index(compiler->abc.addMethod(this))
, name(name)
, param_count(param_count)
, param_types(param_types)
, option_count(option_count)
, default_values(default_values)
, return_type(return_type)
, flags(~0U)
{
}
uint32_t ABCMethodInfo::size()
{
AvmAssert(flags != ~0U);
uint32_t param_size = 0;
for ( Seq<uint32_t>* param_types = this->param_types ; param_types != NULL ; param_types = param_types->tl )
param_size += lenU30(param_types->hd);
uint32_t option_size = option_count > 0 ? lenU30(option_count) : 0;
for ( Seq<DefaultValue*>* default_values = this->default_values ; default_values != NULL ; default_values = default_values->tl ) {
option_size += lenU30(default_values->hd->index);
option_size += 1;
}
reported_size = (lenU30(param_count) +
lenU30(return_type) +
param_size +
lenU30(name) +
1 /* flags */ +
option_size +
0 /* param_names */);
return reported_size;
}
uint8_t* ABCMethodInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
AvmAssert(flags != ~0U);
if (option_count > 0)
flags |= abcMethod_HAS_OPTIONAL;
else
flags &= ~abcMethod_HAS_OPTIONAL;
b = emitU30(b, param_count);
b = emitU30(b, return_type);
for ( Seq<uint32_t>* param_types = this->param_types ; param_types != NULL ; param_types = param_types->tl )
b = emitU30(b, param_types->hd);
b = emitU30(b, name);
*b++ = (uint8_t)flags;
if (option_count > 0) {
b = emitU30(b, option_count);
for ( Seq<DefaultValue*>* default_values = this->default_values ; default_values != NULL ; default_values = default_values->tl ) {
b = emitU30(b, default_values->hd->index);
*b++ = (uint8_t)default_values->hd->tag;
}
}
AvmAssert( b == b0 + reported_size );
return b;
}
ABCExceptionTable::ABCExceptionTable(Compiler* compiler)
: exceptionCount(0)
, exceptions(compiler->allocator)
{
}
uint32_t ABCExceptionTable::size()
{
reported_size = lenU30(exceptionCount);
for ( Seq<ABCExceptionInfo*>* exceptions = this->exceptions.get() ; exceptions != NULL ; exceptions = exceptions->tl )
reported_size += exceptions->hd->size();
return reported_size;
}
uint8_t* ABCExceptionTable::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU30(b, exceptionCount);
for ( Seq<ABCExceptionInfo*>* exceptions = this->exceptions.get() ; exceptions != NULL ; exceptions = exceptions->tl )
b = exceptions->hd->serialize(b);
AvmAssert( b == b0 + reported_size );
return b;
}
ABCExceptionInfo::ABCExceptionInfo(uint32_t from, uint32_t to, uint32_t target, uint32_t exception_type, uint32_t var_name)
: from(from)
, to(to)
, target(target)
, exception_type(exception_type)
, var_name(var_name)
{
}
uint32_t ABCExceptionInfo::size()
{
reported_size = (lenU30(from) +
lenU30(to) +
lenU30(target) +
lenU30(exception_type) +
lenU30(var_name));
return reported_size;
}
uint8_t* ABCExceptionInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b; )
b = emitU30(b, from);
b = emitU30(b, to);
b = emitU30(b, target);
b = emitU30(b, exception_type);
b = emitU30(b, var_name);
AvmAssert( b == b0 + reported_size );
return b;
}
uint32_t ABCInstanceInfo::size()
{
reported_size = (lenU30(name) +
lenU30(super_name) +
1 /* flags */ +
((flags & CONSTANT_ClassProtectedNs) ? lenU30(protectedNS) : 0) +
lenU30(interface_count) +
lenU30(iinit) +
traits->size());
for ( uint32_t i=0 ; i < interface_count ; i++ )
reported_size += lenU30(interfaces[i]);
return reported_size;
}
uint8_t* ABCInstanceInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b );
AvmAssert( iinit != 0 || (flags & CONSTANT_ClassInterface) != 0);
b = emitU30(b, name);
b = emitU30(b, super_name);
*b++ = (uint8_t)flags;
if (flags & CONSTANT_ClassProtectedNs)
b = emitU30(b, protectedNS);
b = emitU30(b, interface_count);
for ( uint32_t i=0, limit=interface_count ; i < limit ; i++ ) {
AvmAssert(interfaces[i] != 0);
b = emitU30(b, interfaces[i]);
}
b = emitU30(b, iinit);
b = traits->serialize(b);
AvmAssert( b == b0 + reported_size );
return b;
}
uint32_t ABCClassInfo::size()
{
reported_size = lenU30(cinit) + traits->size();
return reported_size;
}
uint8_t* ABCClassInfo::serialize(uint8_t* b)
{
DEBUG_ONLY( uint8_t* b0 = b );
b = emitU30(b, cinit);
b = traits->serialize(b);
AvmAssert( b == b0 + reported_size );
return b;
}
}
}
#endif // VMCFG_EVAL