escargot/src/runtime/Object.cpp
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

309 lines
12 KiB
C++

#include "Escargot.h"
#include "Object.h"
#include "ExecutionContext.h"
#include "Context.h"
#include "ErrorObject.h"
namespace Escargot {
Object::Object(ExecutionState& state, size_t defaultSpace, bool initPlainArea)
: m_structure(state.context()->defaultStructureForObject())
, m_rareData(nullptr)
{
m_values.resizeWithUninitializedValues(defaultSpace);
if (initPlainArea) {
initPlainObject(state);
}
}
Object::Object(ExecutionState& state)
: Object(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER, true)
{
}
void Object::initPlainObject(ExecutionState& state)
{
m_values[0] = Value(state.context()->globalObject()->objectPrototype());
}
Object* Object::createBuiltinObjectPrototype(ExecutionState& state)
{
Object* obj = new Object(state, 1, false);
obj->m_structure = state.context()->defaultStructureForObject();
obj->m_values[0] = Value(Value::Null);
return obj;
}
Object* Object::createFunctionPrototypeObject(ExecutionState& state, FunctionObject* function)
{
Object* obj = new Object(state, 2, false);
obj->m_structure = state.context()->defaultStructureForFunctionPrototypeObject();
obj->m_values[0] = Value();
obj->m_values[1] = Value(function);
return obj;
}
Value Object::getPrototypeSlowCase(ExecutionState& state)
{
return getOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().__proto__)).value();
}
bool Object::setPrototypeSlowCase(ExecutionState& state, const Value& value)
{
return defineOwnProperty(state, ObjectPropertyName(state, state.context()->staticStrings().__proto__), ObjectPropertyDescriptorForDefineOwnProperty(value));
}
// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinarygetownproperty
Object::ObjectGetResult Object::getOwnProperty(ExecutionState& state, const ObjectPropertyName& propertyName) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
PropertyName P = propertyName.toPropertyName(state);
size_t idx = m_structure->findProperty(state, P);
if (LIKELY(idx != SIZE_MAX)) {
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (item.m_descriptor.isDataProperty()) {
if (LIKELY(!item.m_descriptor.isNativeAccessorProperty())) {
return Object::ObjectGetResult(m_values[idx], item.m_descriptor.isWritable(), item.m_descriptor.isEnumerable(), item.m_descriptor.isConfigurable());
} else {
ObjectPropertyNativeGetterSetterData* data = item.m_descriptor.nativeGetterSetterData();
return Object::ObjectGetResult(data->m_getter(state, this), item.m_descriptor.isWritable(), item.m_descriptor.isEnumerable(), item.m_descriptor.isConfigurable());
}
} else {
// TODO
// implement js getter, setter
RELEASE_ASSERT_NOT_REACHED();
}
}
return Object::ObjectGetResult();
}
bool Object::defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptorForDefineOwnProperty& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
if (isEverSetAsPrototypeObject()) {
// TODO
// implement bad time
RELEASE_ASSERT_NOT_REACHED();
}
PropertyName propertyName = P.toPropertyName(state);
size_t oldIdx = m_structure->findProperty(state, propertyName);
if (oldIdx == SIZE_MAX) {
if (checkPropertyAlreadyDefinedWithNonWritableInPrototype(state, P)) {
return false;
}
if (UNLIKELY(!isExtensible()))
return false;
m_structure = m_structure->addProperty(state, propertyName, desc.descriptor());
// TODO implement JS getter setter
RELEASE_ASSERT(desc.descriptor().isDataProperty());
m_values.pushBack(desc.value());
return true;
} else {
size_t idx = oldIdx;
const ObjectStructureItem& item = m_structure->readProperty(state, idx);
if (!item.m_descriptor.isWritable())
return false;
if (item.m_descriptor != desc.descriptor()) {
if (!item.m_descriptor.isConfigurable()) {
return false;
}
deleteOwnProperty(state, P);
defineOwnProperty(state, P, desc);
return true;
}
if (item.m_descriptor.isDataProperty()) {
if (LIKELY(!item.m_descriptor.isNativeAccessorProperty())) {
m_values[idx] = desc.value();
return true;
} else {
ObjectPropertyNativeGetterSetterData* data = item.m_descriptor.nativeGetterSetterData();
return data->m_setter(state, this, desc.value());
}
} else {
// TODO
// implement js getter, setter
RELEASE_ASSERT_NOT_REACHED();
}
return true;
}
}
void Object::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
ASSERT(getOwnProperty(state, P).hasValue());
ASSERT(getOwnProperty(state, P).isConfigurable());
deleteOwnProperty(state, m_structure->findProperty(state, P.toPropertyName(state)));
}
Object::ObjectGetResult Object::get(ExecutionState& state, const ObjectPropertyName& propertyName, Object* receiver)
{
Object* target = this;
while (true) {
auto result = target->getOwnProperty(state, propertyName);
if (result.hasValue()) {
return result;
}
Value __proto__ = target->getPrototype(state);
if (__proto__.isObject()) {
target = __proto__.asObject();
} else {
return Object::ObjectGetResult();
}
}
}
// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver
bool Object::set(ExecutionState& state, const ObjectPropertyName& propertyName, const Value& v, Object* receiver)
{
auto desc = getOwnProperty(state, propertyName);
if (!desc.hasValue()) {
Value target = this->getPrototype(state);
while (target.isObject()) {
Object* O = target.asObject();
auto desc = O->getOwnProperty(state, propertyName);
if (desc.hasValue()) {
return set(state, propertyName, v, receiver);
}
target = O->getPrototype(state);
}
ObjectPropertyDescriptorForDefineOwnProperty desc(v);
return defineOwnProperty(state, propertyName, desc);
} else {
// If IsDataDescriptor(ownDesc) is true, then
if (desc.isDataProperty()) {
// If ownDesc.[[Writable]] is false, return false.
if (!desc.isWritable()) {
return false;
}
// TODO If Type(Receiver) is not Object, return false.
// Let existingDescriptor be Receiver.[[GetOwnProperty]](P).
auto receiverDesc = receiver->getOwnProperty(state, propertyName);
// If existingDescriptor is not undefined, then
if (receiverDesc.hasValue()) {
// If IsAccessorDescriptor(existingDescriptor) is true, return false.
if (!receiverDesc.isDataProperty()) {
return false;
}
// If existingDescriptor.[[Writable]] is false, return false
if (!receiverDesc.isWritable()) {
return false;
}
// Let valueDesc be the PropertyDescriptor{[[Value]]: V}.
ObjectPropertyDescriptorForDefineOwnProperty desc(v);
return receiver->defineOwnProperty(state, propertyName, desc);
} else {
// Else Receiver does not currently have a property P,
// Return CreateDataProperty(Receiver, P, V).
ObjectPropertyDescriptorForDefineOwnProperty desc(v);
return defineOwnProperty(state, propertyName, desc);
}
} else {
// TODO
RELEASE_ASSERT_NOT_REACHED();
}
}
}
void Object::setThrowsException(ExecutionState& state, const ObjectPropertyName& P, const Value& v, Object* receiver)
{
if (UNLIKELY(!set(state, P, v, receiver))) {
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(state), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
}
void Object::setThrowsExceptionWhenStrictMode(ExecutionState& state, const ObjectPropertyName& P, const Value& v, Object* receiver)
{
if (UNLIKELY(!set(state, P, v, receiver)) && state.inStrictMode()) {
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(state), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
}
void Object::throwCannotDefineError(ExecutionState& state, const PropertyName& P)
{
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(), false, String::emptyString, errorMessage_DefineProperty_RedefineNotConfigurable);
}
void Object::throwCannotWriteError(ExecutionState& state, const PropertyName& P)
{
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
bool Object::checkPropertyAlreadyDefinedWithNonWritableInPrototype(ExecutionState& state, const ObjectPropertyName& P)
{
Value __proto__Value = getPrototype(state);
while (true) {
if (!__proto__Value.isObject()) {
break;
}
Object* targetObj = __proto__Value.asObject();
auto t = targetObj->getOwnProperty(state, P);
if (t.hasValue()) {
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.12.5
// If IsAccessorDescriptor(desc) is true, then
// Let setter be desc.[[Set]] which cannot be undefined.
// Call the [[Call]] internal method of setter providing O as the this value and providing V as the sole argument.
if (!t.isDataProperty()) {
// TODO
// implement js getter, setter
RELEASE_ASSERT_NOT_REACHED();
/*
if (!foundInPrototype) {
ESPropertyAccessorData* data = targetObj->accessorData(t);
if (data->isAccessorDescriptor()) {
if (data->getJSSetter()) {
ESValue receiverVal(this);
if (receiver)
receiverVal = *receiver;
ESValue args[] = {val};
ESFunctionObject::call(ESVMInstance::currentInstance(), data->getJSSetter(), receiverVal, args, 1, false);
return true;
}
return false;
}
if (data->getNativeSetter()) {
if (!targetObj->hiddenClass()->m_propertyInfo[t].writable()) {
return false;
}
foundInPrototype = true;
break;
} else {
return false;
}
}*/
} else {
if (!t.isWritable()) {
return true;
}
}
}
__proto__Value = targetObj->getPrototype(state);
}
return false;
}
void Object::deleteOwnProperty(ExecutionState& state, size_t idx)
{
if (isPlainObject()) {
const ObjectStructureItem& ownDesc = m_structure->readProperty(state, idx);
if (ownDesc.m_descriptor.isNativeAccessorProperty()) {
ensureObjectRareData();
// TODO
RELEASE_ASSERT_NOT_REACHED();
m_rareData->m_isPlainObject = false;
}
}
m_structure = m_structure->removeProperty(state, idx);
m_values.erase(idx);
}
}