escargot/src/runtime/Object.h
seonghyun kim f2e8463092 1. redesign Object api
2. implement ObjectPropertyName type

Signed-off-by: seonghyun kim <sh8281.kim@samsung.com>
2016-12-07 22:10:23 +09:00

410 lines
12 KiB
C++

#ifndef __EscargotObject__
#define __EscargotObject__
#include "runtime/PointerValue.h"
#include "util/Vector.h"
#include "runtime/SmallValue.h"
#include "runtime/ObjectStructure.h"
namespace Escargot {
class FunctionObject;
class ErrorObject;
struct ObjectRareData {
bool m_isExtensible;
bool m_isPlainObject; // tells it has __proto__ at first index
bool m_isEverSetAsPrototypeObject;
ObjectRareData()
{
m_isExtensible = true;
m_isPlainObject = true;
m_isEverSetAsPrototypeObject = false;
}
};
class ObjectPropertyName {
MAKE_STACK_ALLOCATED()
public:
ObjectPropertyName(ExecutionState& state, const Value& v)
{
if (v.isUInt32()) {
m_isUIntType = true;
m_value.m_uint = v.asUInt32();
} else {
m_isUIntType = false;
m_value.m_name = PropertyName(state, v.toString(state));
}
}
ObjectPropertyName(const AtomicString& v)
{
m_isUIntType = false;
m_value.m_name = v;
}
ObjectPropertyName(ExecutionState& state, const PropertyName& v)
{
m_isUIntType = false;
m_value.m_name = v;
}
bool isUIntType() const
{
return m_isUIntType;
}
const PropertyName& propertyName() const
{
ASSERT(!isUIntType());
return m_value.m_name;
}
const uint32_t& uintValue() const
{
ASSERT(isUIntType());
return m_value.m_uint;
}
PropertyName toPropertyName(ExecutionState& state) const
{
if (isUIntType()) {
return PropertyName(state, String::fromDouble(uintValue()));
}
return propertyName();
}
String* string(ExecutionState& state) const
{
return toPropertyName(state).string();
}
protected:
bool m_isUIntType;
union ObjectPropertyNameData {
ObjectPropertyNameData() { m_uint = 0; }
PropertyName m_name;
uint32_t m_uint;
} m_value;
};
#define ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER 1
#define ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
class Object : public PointerValue {
friend class Context;
friend class GlobalObject;
friend class ByteCodeInterpreter;
static Object* createBuiltinObjectPrototype(ExecutionState& state);
public:
Object(ExecutionState& state);
static Object* createFunctionPrototypeObject(ExecutionState& state, FunctionObject* function);
virtual Type type()
{
return ObjectType;
}
virtual bool isObject()
{
return true;
}
virtual bool isErrorObject()
{
return false;
}
ErrorObject* asErrorObject()
{
ASSERT(isErrorObject());
return (ErrorObject*)this;
}
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ordinary-object-internal-methods-and-internal-slots-isextensible
bool isExtensible()
{
return m_rareData == nullptr ? true : m_rareData->m_isExtensible;
}
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ordinary-object-internal-methods-and-internal-slots-preventextensions
void preventExtensions()
{
ensureObjectRareData();
m_rareData->m_isExtensible = true;
}
Value getPrototype(ExecutionState& state)
{
if (LIKELY(isPlainObject())) {
return m_values[0];
} else {
return getPrototypeSlowCase(state);
}
}
void setPrototype(ExecutionState& state, const Value& value)
{
if (LIKELY(isPlainObject())) {
m_values[0] = value;
} else {
setPrototypeSlowCase(state, value);
}
}
class ObjectPropertyDescriptorForDefineOwnProperty {
public:
// for plain data property
ObjectPropertyDescriptorForDefineOwnProperty(const Value& value, ObjectPropertyDescriptor::PresentAttribute attribute = ObjectPropertyDescriptor::AllPresent)
: m_descriptor(ObjectPropertyDescriptor::createDataDescriptor(attribute))
, m_value(value)
{
}
// TODO
// for native acc. data property
// for js acc. property
const Value& value() const
{
ASSERT(m_descriptor.isDataProperty());
return m_value;
}
const ObjectPropertyDescriptor& descriptor() const
{
return m_descriptor;
}
protected:
MAKE_STACK_ALLOCATED();
ObjectPropertyDescriptor m_descriptor;
Value m_value;
};
class ObjectGetResult {
public:
// TODO implement js getter case
ObjectGetResult()
: m_hasValue(false)
, m_isWritable(false)
, m_isEnumerable(false)
, m_isConfigurable(false)
, m_isDataProperty(false)
, m_value(Value())
{
}
ObjectGetResult(const Value& v, bool isWritable, bool isEnumerable, bool isConfigurable)
: m_hasValue(true)
, m_isWritable(isWritable)
, m_isEnumerable(isEnumerable)
, m_isConfigurable(isConfigurable)
, m_isDataProperty(true)
, m_value(v)
{
}
Value value() const
{
return m_value;
}
bool hasValue() const
{
return m_hasValue;
}
bool isWritable() const
{
ASSERT(hasValue());
return m_isWritable;
}
bool isEnumerable() const
{
ASSERT(hasValue());
return m_isEnumerable;
}
bool isConfigurable() const
{
ASSERT(hasValue());
return m_isConfigurable;
}
bool isDataProperty() const
{
ASSERT(hasValue());
return m_isDataProperty;
}
protected:
bool m_hasValue : 1;
bool m_isWritable : 1;
bool m_isEnumerable : 1;
bool m_isConfigurable : 1;
bool m_isDataProperty : 1;
Value m_value;
};
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptorForDefineOwnProperty& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& propertyName)
{
return getOwnProperty(state, propertyName).hasValue();
}
ObjectGetResult get(ExecutionState& state, const ObjectPropertyName& P, Object* receiver);
ObjectGetResult get(ExecutionState& state, const ObjectPropertyName& P)
{
return get(state, P, this);
}
void setThrowsException(ExecutionState& state, const ObjectPropertyName& P, const Value& v, Object* receiver);
void setThrowsExceptionWhenStrictMode(ExecutionState& state, const ObjectPropertyName& P, const Value& v, Object* receiver);
void defineOwnPropertyThrowsException(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptorForDefineOwnProperty& desc)
{
if (!defineOwnProperty(state, P, desc)) {
throwCannotDefineError(state, P.toPropertyName(state));
}
}
void defineOwnPropertyThrowsExceptionWhenStrictMode(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptorForDefineOwnProperty& desc)
{
if (!defineOwnProperty(state, P, desc) && state.inStrictMode()) {
throwCannotDefineError(state, P.toPropertyName(state));
}
}
void markThisObjectDontNeedStructureTransitionTable(ExecutionState& state)
{
ASSERT(structure()->inTransitionMode());
m_structure = m_structure->escapeTransitionMode(state);
}
protected:
Object(ExecutionState& state, size_t defaultSpace, bool initPlainArea);
void initPlainObject(ExecutionState& state);
ObjectStructure* m_structure;
ObjectRareData* m_rareData;
Vector<SmallValue, gc_allocator_ignore_off_page<SmallValue>> m_values;
ObjectStructure* structure() const
{
return m_structure;
}
bool checkPropertyAlreadyDefinedWithNonWritableInPrototype(ExecutionState& state, const ObjectPropertyName& P);
void ensureObjectRareData()
{
if (m_rareData == nullptr) {
m_rareData = new ObjectRareData();
}
}
Value uncheckedGetOwnDataProperty(ExecutionState& state, size_t idx)
{
ASSERT(m_structure->readProperty(state, idx).m_descriptor.isDataProperty());
return m_values[idx];
}
void uncheckedSetOwnDataProperty(ExecutionState& state, size_t idx, const Value& newValue)
{
ASSERT(m_structure->readProperty(state, idx).m_descriptor.isDataProperty());
m_values[idx] = newValue;
}
Value getOwnDataPropertyUtilForObject(ExecutionState& state, size_t idx)
{
return getOwnDataPropertyUtilForObject(state, idx, this);
}
Value getOwnDataPropertyUtilForObject(ExecutionState& state, size_t idx, Object* receiver)
{
ASSERT(m_structure->readProperty(state, idx).m_descriptor.isDataProperty());
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (LIKELY(item.m_descriptor.isPlainDataProperty())) {
return m_values[idx];
} else {
return item.m_descriptor.nativeGetterSetterData()->m_getter(state, this);
}
}
bool setOwnDataPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& newValue)
{
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (LIKELY(item.m_descriptor.isWritable())) {
if (LIKELY(item.m_descriptor.isPlainDataProperty())) {
m_values[idx] = newValue;
return true;
} else {
return item.m_descriptor.nativeGetterSetterData()->m_setter(state, this, newValue);
}
} else {
return false;
}
}
Value getOwnPropertyUtilForObject(ExecutionState& state, size_t idx, Object* receiver)
{
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (item.m_descriptor.isDataProperty()) {
return getOwnDataPropertyUtilForObject(state, idx, receiver);
} else {
RELEASE_ASSERT_NOT_REACHED();
}
}
bool setOwnPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& newValue)
{
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (item.m_descriptor.isDataProperty()) {
return setOwnDataPropertyUtilForObject(state, idx, newValue);
} else {
RELEASE_ASSERT_NOT_REACHED();
}
}
void setOwnPropertyThrowsExceptionWhenStrictMode(ExecutionState& state, size_t idx, const Value& newValue)
{
if (UNLIKELY(!setOwnPropertyUtilForObject(state, idx, newValue))) {
throwCannotWriteError(state, m_structure->readProperty(state, idx).m_propertyName);
}
}
void throwCannotDefineError(ExecutionState& state, const PropertyName& P);
void throwCannotWriteError(ExecutionState& state, const PropertyName& P);
bool isPlainObject() const
{
if (LIKELY(m_rareData == nullptr)) {
return true;
} else {
return m_rareData->m_isPlainObject;
}
}
bool isEverSetAsPrototypeObject() const
{
if (LIKELY(m_rareData == nullptr)) {
return false;
} else {
return m_rareData->m_isEverSetAsPrototypeObject;
}
}
void markAsPrototypeObject()
{
ensureObjectRareData();
m_rareData->m_isEverSetAsPrototypeObject = true;
}
void deleteOwnProperty(ExecutionState& state, size_t idx);
Value getPrototypeSlowCase(ExecutionState& state);
bool setPrototypeSlowCase(ExecutionState& state, const Value& value);
bool set(ExecutionState& state, const ObjectPropertyName& P, const Value& v, Object* receiver);
};
}
#endif