mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
2. implement ObjectPropertyName type Signed-off-by: seonghyun kim <sh8281.kim@samsung.com>
309 lines
12 KiB
C++
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);
|
|
}
|
|
|
|
}
|