Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
263 lines
10 KiB
C++
263 lines
10 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/. */
|
|
|
|
#ifndef __avmplus_ArrayObject__
|
|
#define __avmplus_ArrayObject__
|
|
|
|
|
|
namespace avmplus
|
|
{
|
|
/**
|
|
* an instance of class Array. constructed with "new Array" or
|
|
* an array literal [...]. We need this class to support Array's
|
|
* special "get" and "put" semantics and to maintain the virtual
|
|
* "length" property.
|
|
*/
|
|
class GC_AS3_EXACT(ArrayObject, ScriptObject)
|
|
{
|
|
friend class ArrayClass;
|
|
private:
|
|
// forcibly-inlined version used by various hot methods to ensure inlining;
|
|
// see definition for more info.
|
|
Atom getUintPropertyImpl(uint32_t index) const;
|
|
|
|
protected:
|
|
ArrayObject(VTable* ivtable, ScriptObject *delegate, uint32_t capacity=0, bool simple=false);
|
|
ArrayObject(VTable* ivtable, ScriptObject *delegate, Atom *argv, int argc, bool simple=false);
|
|
#ifdef VMCFG_AOT
|
|
template <typename ADT> ArrayObject(VTable* ivtable, ScriptObject *delegate, MethodEnv *env, ADT argDesc, uint32_t argc, va_list ap, bool simple=false);
|
|
#endif
|
|
|
|
public:
|
|
REALLY_INLINE static ArrayObject* create(MMgc::GC* gc, VTable* ivtable, ScriptObject* delegate, uint32_t capacity = 0)
|
|
{
|
|
return new (gc, MMgc::kExact, ivtable->getExtraSize()) ArrayObject(ivtable, delegate, capacity);
|
|
}
|
|
|
|
REALLY_INLINE static ArrayObject* create(MMgc::GC* gc, VTable* ivtable, ScriptObject* delegate, Atom *argv, int argc)
|
|
{
|
|
return new (gc, MMgc::kExact, ivtable->getExtraSize()) ArrayObject(ivtable, delegate, argv, argc);
|
|
}
|
|
|
|
private:
|
|
REALLY_INLINE static ArrayObject* createSimple(MMgc::GC* gc, VTable* ivtable, ScriptObject* delegate, uint32_t capacity = 0)
|
|
{
|
|
return new (gc, MMgc::kExact, ivtable->getExtraSize()) ArrayObject(ivtable, delegate, capacity, true);
|
|
}
|
|
|
|
REALLY_INLINE static ArrayObject* createSimple(MMgc::GC* gc, VTable* ivtable, ScriptObject* delegate, Atom *argv, int argc)
|
|
{
|
|
return new (gc, MMgc::kExact, ivtable->getExtraSize()) ArrayObject(ivtable, delegate, argv, argc, true);
|
|
}
|
|
|
|
#ifdef VMCFG_AOT
|
|
template <typename ADT> static ArrayObject* createSimple(MMgc::GC* gc, VTable* ivtable, ScriptObject *delegate, MethodEnv *env, ADT argDesc, uint32_t argc, va_list ap)
|
|
{
|
|
return new (gc, MMgc::kExact, ivtable->getExtraSize()) ArrayObject(ivtable, delegate, env, argDesc, argc, ap, true);
|
|
}
|
|
#endif
|
|
public:
|
|
|
|
~ArrayObject();
|
|
|
|
virtual ArrayObject* toArrayObject() { return this; }
|
|
|
|
// Non-virtual members for ActionScript method implementation
|
|
uint32_t get_length() const;
|
|
void set_length(uint32_t newLength);
|
|
|
|
// Virtual members so Array subclasses can treat length differently (in both C++ and AS3)
|
|
virtual uint32_t getLength() const;
|
|
virtual void setLength(uint32_t newLength);
|
|
|
|
// Virtual methods used (primarily) by ArrayClass generic methods;
|
|
// the default implementations are adequate but we can improve speed by
|
|
// overriding.
|
|
virtual uint32_t getLengthProperty();
|
|
virtual void setLengthProperty(uint32_t newLen);
|
|
|
|
virtual Atom getAtomProperty(Atom name) const;
|
|
virtual void setAtomProperty(Atom name, Atom value);
|
|
virtual bool deleteAtomProperty(Atom name);
|
|
virtual bool hasAtomProperty(Atom name) const;
|
|
|
|
// Faster versions that takes direct indices
|
|
virtual Atom getUintProperty(uint32_t index) const;
|
|
virtual void setUintProperty(uint32_t index, Atom value);
|
|
virtual bool delUintProperty(uint32_t index);
|
|
virtual bool hasUintProperty(uint32_t i) const;
|
|
|
|
virtual bool getAtomPropertyIsEnumerable(Atom name) const;
|
|
|
|
// NB: These are only for use by CodegenLIR, and by ArrayObject itself.
|
|
// They aren't declared private-with-friend-access because of the way
|
|
// they are initialized, but in an ideal world, they would be.
|
|
// Most code should call get/setUintProperty() instead.
|
|
Atom _getUintProperty(uint32_t index) const;
|
|
void _setUintProperty(uint32_t index, Atom value);
|
|
Atom _getIntProperty(int32_t index) const;
|
|
void _setIntProperty(int32_t index, Atom value);
|
|
Atom _getDoubleProperty(double index) const;
|
|
void _setDoubleProperty(double index, Atom value);
|
|
|
|
#ifdef VMCFG_AOT
|
|
Atom *getDenseCopy() const;
|
|
uint32_t getDenseLength() const;
|
|
#endif
|
|
|
|
// Iterator support - for in, for each
|
|
virtual Atom nextName(int index);
|
|
virtual Atom nextValue(int index);
|
|
virtual int nextNameIndex(int index);
|
|
|
|
// native methods
|
|
Atom AS3_pop(); // pop(...rest)
|
|
uint32_t AS3_push(Atom* args, int argc); // push(...args):uint
|
|
uint32_t AS3_unshift(Atom* args, int argc); // unshift(...args):
|
|
|
|
Atom pop();
|
|
uint32_t push(Atom *args, int argc);
|
|
uint32_t unshift(Atom *args, int argc);
|
|
|
|
#ifdef DEBUGGER
|
|
virtual uint64_t bytesUsed() const;
|
|
virtual void registerDependentObjects(IMemorySampler* memSampler);
|
|
#endif
|
|
|
|
#ifdef AVMPLUS_VERBOSE
|
|
public:
|
|
PrintWriter& print(PrintWriter& prw) const;
|
|
#endif
|
|
|
|
private:
|
|
Atom indexToName(uint32_t index) const;
|
|
|
|
void convertToSparse();
|
|
|
|
bool delDenseUintProperty(uint32_t index);
|
|
|
|
void verify() const;
|
|
|
|
uint32_t calcDenseUsed() const;
|
|
|
|
protected:
|
|
// Bug 687838: override prototype chain query operator.
|
|
virtual bool isOwnAtomPropertyHere(Atom name, Atom *recv) const;
|
|
private:
|
|
// If name is "length" or dense-index, sets *recv to this[name] and
|
|
// returns true; else returns false.
|
|
bool isAtomPropertyLengthOrInDenseArea(Atom name, Atom *recv) const;
|
|
protected:
|
|
// Helper methods used only by ArrayClass, as special-case
|
|
// optimizations for various "generic" optimizations that
|
|
// can be done on dense arrays. These optimizations used
|
|
// to be done in ArrayClass directly, but have been moved
|
|
// into ArrayObject so that all "special knowledge" about
|
|
// how dense arrays are implemented can be concentrated here
|
|
// rather than bleeding into other classes (even one as
|
|
// friendly to us as our class).
|
|
|
|
bool try_concat(ArrayObject* that);
|
|
bool try_reverse();
|
|
bool try_shift(Atom& result);
|
|
virtual ArrayObject* try_splice(uint32_t insertPoint, uint32_t insertCount, uint32_t deleteCount, const ArrayObject* that, uint32_t that_skip);
|
|
bool try_unshift(ArrayObject* that);
|
|
|
|
protected:
|
|
void unseal()
|
|
{
|
|
AvmAssert(m_denseStart == IS_SEALED);
|
|
m_denseStart = 0;
|
|
}
|
|
|
|
private:
|
|
|
|
// These values are chosen such that (index - denseStart)
|
|
// is always >= m_denseArray.length(), obviating the need
|
|
// to have a separate runtime check for "is-dense" or not.
|
|
static const uint32_t IS_SEALED = 0xfffffffe;
|
|
static const uint32_t IS_SPARSE = 0xffffffff;
|
|
bool isSparse() const;
|
|
bool isDense() const;
|
|
bool isDynamic() const;
|
|
|
|
private:
|
|
|
|
// ------------------------ DATA SECTION BEGIN
|
|
GC_DATA_BEGIN(ArrayObject)
|
|
|
|
#ifdef DEBUGGER
|
|
bool m_created;
|
|
mutable bool m_flushBeforeConstructionComplete;
|
|
#endif
|
|
|
|
AtomList GC_STRUCTURE(m_denseArray);
|
|
uint32_t m_denseStart;
|
|
uint32_t m_denseUsed;
|
|
uint32_t m_length;
|
|
|
|
// Simple Arrays are:
|
|
// - not-subclassed,
|
|
// - dense (as in isSparse() false),
|
|
// - start at index 0,
|
|
// - contiguous (have no holes).
|
|
|
|
// m_lengthIfSimple non-zero implies m_canBeSimple (see below) and
|
|
// that m_lengthIfSimple == m_denseArray length.
|
|
uint32_t m_lengthIfSimple;
|
|
|
|
// m_canBeSimple true implies m_lengthIfSimple == m_denseArray length;
|
|
// the two lengths may be zero.
|
|
// m_canBeSimple false implies m_lengthIfSimple == 0.
|
|
bool m_canBeSimple;
|
|
|
|
GC_DATA_END(ArrayObject)
|
|
|
|
private:
|
|
DECLARE_SLOTS_ArrayObject;
|
|
// ------------------------ DATA SECTION END
|
|
};
|
|
|
|
// Special subclass used for "SemiSealed" Array subclasses
|
|
// see https://bugzilla.mozilla.org/show_bug.cgi?id=654807
|
|
class SemiSealedArrayObject : public ArrayObject
|
|
{
|
|
protected:
|
|
REALLY_INLINE SemiSealedArrayObject(VTable* ivtable, ScriptObject* delegate)
|
|
: ArrayObject(ivtable, delegate)
|
|
{
|
|
AvmAssert(!traits()->needsHashtable());
|
|
unseal();
|
|
}
|
|
|
|
protected:
|
|
friend class ClassClosure;
|
|
static ScriptObject* FASTCALL createInstanceProc(ClassClosure* cls);
|
|
|
|
public:
|
|
virtual Atom getAtomProperty(Atom name) const;
|
|
virtual void setAtomProperty(Atom name, Atom value);
|
|
virtual bool deleteAtomProperty(Atom name);
|
|
virtual bool hasAtomProperty(Atom name) const;
|
|
|
|
// Faster versions that takes direct indices
|
|
virtual Atom getUintProperty(uint32_t index) const;
|
|
virtual void setUintProperty(uint32_t index, Atom value);
|
|
virtual bool delUintProperty(uint32_t index);
|
|
virtual bool hasUintProperty(uint32_t i) const;
|
|
|
|
virtual bool getAtomPropertyIsEnumerable(Atom name) const;
|
|
virtual void setAtomPropertyIsEnumerable(Atom name, bool enumerable);
|
|
|
|
virtual void setLength(uint32_t newLen);
|
|
|
|
protected:
|
|
virtual ArrayObject* try_splice(uint32_t insertPoint, uint32_t insertCount, uint32_t deleteCount, const ArrayObject* that, uint32_t that_skip);
|
|
};
|
|
}
|
|
|
|
#endif /* __avmplus_ArrayObject__ */
|