Commit c706c0fa authored by jkummerow's avatar jkummerow Committed by Commit bot

Add C++ implementation of Object.defineProperties

Not used yet, so this CL shouldn't change behavior.

Review URL: https://codereview.chromium.org/1368753003

Cr-Commit-Position: refs/heads/master@{#31241}
parent 6a10a9af
......@@ -1130,6 +1130,8 @@ source_set("v8_base") {
"src/profiler/strings-storage.h",
"src/profiler/unbound-queue-inl.h",
"src/profiler/unbound-queue.h",
"src/property-descriptor.cc",
"src/property-descriptor.h",
"src/property-details.h",
"src/property.cc",
"src/property.h",
......
This diff is collapsed.
This diff is collapsed.
......@@ -860,6 +860,7 @@ class LookupIterator;
class ObjectHashTable;
class ObjectVisitor;
class PropertyCell;
class PropertyDescriptor;
class SafepointEntry;
class SharedFunctionInfo;
class StringStream;
......@@ -1790,6 +1791,9 @@ enum AccessorComponent {
enum KeyFilter { SKIP_SYMBOLS, INCLUDE_SYMBOLS };
enum ShouldThrow { THROW_ON_ERROR, DONT_THROW };
// JSReceiver includes types on which properties can be defined, i.e.,
// JSObject and JSProxy.
class JSReceiver: public HeapObject {
......@@ -1826,6 +1830,35 @@ class JSReceiver: public HeapObject {
Handle<JSReceiver> object, uint32_t index,
LanguageMode language_mode = SLOPPY);
MUST_USE_RESULT static Object* DefineProperty(Isolate* isolate,
Handle<Object> object,
Handle<Object> name,
Handle<Object> attributes);
MUST_USE_RESULT static Object* DefineProperties(Isolate* isolate,
Handle<Object> object,
Handle<Object> properties);
// "virtual" dispatcher to the correct [[DefineOwnProperty]] implementation.
static bool DefineOwnProperty(Isolate* isolate, Handle<JSObject> object,
Handle<Object> key, PropertyDescriptor* desc,
ShouldThrow should_throw);
static bool OrdinaryDefineOwnProperty(Isolate* isolate,
Handle<JSObject> object,
Handle<Object> key,
PropertyDescriptor* desc,
ShouldThrow should_throw);
static bool OrdinaryDefineOwnProperty(LookupIterator* it,
PropertyDescriptor* desc,
ShouldThrow should_throw);
static bool GetOwnPropertyDescriptor(Isolate* isolate,
Handle<JSObject> object,
Handle<Object> key,
PropertyDescriptor* desc);
static bool GetOwnPropertyDescriptor(LookupIterator* it,
PropertyDescriptor* desc);
// Tests for the fast common case for property enumeration.
bool IsSimpleEnum();
......@@ -2072,6 +2105,10 @@ class JSObject: public JSReceiver {
Handle<Object> getter,
Handle<Object> setter,
PropertyAttributes attributes);
static MaybeHandle<Object> DefineAccessor(LookupIterator* it,
Handle<Object> getter,
Handle<Object> setter,
PropertyAttributes attributes);
// Defines an AccessorInfo property on the given object.
MUST_USE_RESULT static MaybeHandle<Object> SetAccessor(
......@@ -10035,6 +10072,14 @@ class JSArray: public JSObject {
static inline void SetContent(Handle<JSArray> array,
Handle<FixedArrayBase> storage);
static bool DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
Handle<Object> name, PropertyDescriptor* desc,
ShouldThrow should_throw);
static bool ArraySetLength(Isolate* isolate, Handle<JSArray> a,
PropertyDescriptor* desc,
ShouldThrow should_throw);
DECLARE_CAST(JSArray)
// Dispatched behavior.
......
// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/property-descriptor.h"
#include "src/factory.h"
#include "src/isolate-inl.h"
#include "src/lookup.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
// Helper function for ToPropertyDescriptor. Comments describe steps for
// "enumerable", other properties are handled the same way.
// Returns false if an exception was thrown.
bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name,
Handle<Object>* value) {
LookupIterator it(obj, name);
// 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
Maybe<PropertyAttributes> maybe_attr = JSReceiver::GetPropertyAttributes(&it);
// 5. ReturnIfAbrupt(hasEnumerable).
if (!maybe_attr.IsJust()) return false;
// 6. If hasEnumerable is true, then
if (maybe_attr.FromJust() != ABSENT) {
// 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
// 6b. ReturnIfAbrupt(enum).
if (!JSObject::GetProperty(&it).ToHandle(value)) return false;
}
return true;
}
// Helper function for ToPropertyDescriptor. Handles the case of "simple"
// objects: nothing on the prototype chain, just own fast data properties.
// Must not have observable side effects, because the slow path will restart
// the entire conversion!
bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<Object> obj,
PropertyDescriptor* desc) {
if (!obj->IsJSObject()) return false;
Map* map = Handle<JSObject>::cast(obj)->map();
if (map->instance_type() != JS_OBJECT_TYPE) return false;
if (map->is_access_check_needed()) return false;
if (map->prototype() != *isolate->initial_object_prototype()) return false;
if (JSObject::cast(map->prototype())->map() !=
isolate->native_context()->object_function_prototype_map()) {
return false;
}
// TODO(jkummerow): support dictionary properties?
if (map->is_dictionary_map()) return false;
Handle<DescriptorArray> descs =
Handle<DescriptorArray>(map->instance_descriptors());
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
Name* key = descs->GetKey(i);
Handle<Object> value;
switch (details.type()) {
case DATA:
value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
details.representation(),
FieldIndex::ForDescriptor(map, i));
break;
case DATA_CONSTANT:
value = handle(descs->GetConstant(i), isolate);
break;
case ACCESSOR:
case ACCESSOR_CONSTANT:
// Bail out to slow path.
return false;
}
Heap* heap = isolate->heap();
if (key == heap->enumerable_string()) {
desc->set_enumerable(value->BooleanValue());
} else if (key == heap->configurable_string()) {
desc->set_configurable(value->BooleanValue());
} else if (key == heap->value_string()) {
desc->set_value(value);
} else if (key == heap->writable_string()) {
desc->set_writable(value->BooleanValue());
} else if (key == heap->get_string()) {
// Bail out to slow path to throw an exception if necessary.
if (!value->IsCallable()) return false;
desc->set_get(value);
} else if (key == heap->set_string()) {
// Bail out to slow path to throw an exception if necessary.
if (!value->IsCallable()) return false;
desc->set_set(value);
}
}
if ((desc->has_get() || desc->has_set()) &&
(desc->has_value() || desc->has_writable())) {
// Bail out to slow path to throw an exception.
return false;
}
return true;
}
// ES6 6.2.4.5
// Returns false in case of exception.
// static
bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
Handle<Object> obj,
PropertyDescriptor* desc) {
// 1. ReturnIfAbrupt(Obj).
// 2. If Type(Obj) is not Object, throw a TypeError exception.
if (!obj->IsSpecObject()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kPropertyDescObject, obj));
return false;
}
// 3. Let desc be a new Property Descriptor that initially has no fields.
DCHECK(desc->is_empty());
if (ToPropertyDescriptorFastPath(isolate, obj, desc)) {
return true;
}
// TODO(jkummerow): Implement JSProxy support.
// Specifically, instead of taking the attributes != ABSENT shortcut, we
// have to implement proper HasProperty for proxies.
if (!obj->IsJSProxy()) {
{ // enumerable?
Handle<Object> enumerable;
// 4 through 6b.
if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(),
&enumerable)) {
return false;
}
// 6c. Set the [[Enumerable]] field of desc to enum.
if (!enumerable.is_null()) {
desc->set_enumerable(enumerable->BooleanValue());
}
}
{ // configurable?
Handle<Object> configurable;
// 7 through 9b.
if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(),
&configurable)) {
return false;
}
// 9c. Set the [[Configurable]] field of desc to conf.
if (!configurable.is_null()) {
desc->set_configurable(configurable->BooleanValue());
}
}
{ // value?
Handle<Object> value;
// 10 through 12b.
if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(),
&value))
return false;
// 12c. Set the [[Value]] field of desc to value.
if (!value.is_null()) desc->set_value(value);
}
{ // writable?
Handle<Object> writable;
// 13 through 15b.
if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(),
&writable)) {
return false;
}
// 15c. Set the [[Writable]] field of desc to writable.
if (!writable.is_null()) desc->set_writable(writable->BooleanValue());
}
{ // getter?
Handle<Object> getter;
// 16 through 18b.
if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter))
return false;
if (!getter.is_null()) {
// 18c. If IsCallable(getter) is false and getter is not undefined,
// throw a TypeError exception.
if (!getter->IsCallable() && !getter->IsUndefined()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kObjectGetterCallable, getter));
return false;
}
// 18d. Set the [[Get]] field of desc to getter.
desc->set_get(getter);
}
{ // setter?
Handle<Object> setter;
// 19 through 21b.
if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(),
&setter))
return false;
if (!setter.is_null()) {
// 21c. If IsCallable(setter) is false and setter is not undefined,
// throw a TypeError exception.
if (!setter->IsCallable() && !setter->IsUndefined()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kObjectSetterCallable, setter));
return false;
}
// 21d. Set the [[Set]] field of desc to setter.
desc->set_set(setter);
}
}
// 22. If either desc.[[Get]] or desc.[[Set]] is present, then
// 22a. If either desc.[[Value]] or desc.[[Writable]] is present,
// throw a TypeError exception.
if ((desc->has_get() || desc->has_set()) &&
(desc->has_value() || desc->has_writable())) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kValueAndAccessor, obj));
return false;
}
}
} else {
DCHECK(obj->IsJSProxy());
UNIMPLEMENTED();
}
// 23. Return desc.
return true;
}
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_PROPERTY_DESCRIPTOR_H_
#define V8_PROPERTY_DESCRIPTOR_H_
#include "src/handles.h"
#include "src/property-details.h"
namespace v8 {
namespace internal {
class Isolate;
class Object;
class PropertyDescriptor {
public:
PropertyDescriptor()
: enumerable_(false),
has_enumerable_(false),
configurable_(false),
has_configurable_(false),
writable_(false),
has_writable_(false) {}
// ES6 6.2.4.1
static bool IsAccessorDescriptor(PropertyDescriptor* desc) {
return desc->has_get() || desc->has_set();
}
// ES6 6.2.4.2
static bool IsDataDescriptor(PropertyDescriptor* desc) {
return desc->has_value() || desc->has_writable();
}
// ES6 6.2.4.3
static bool IsGenericDescriptor(PropertyDescriptor* desc) {
return !IsAccessorDescriptor(desc) && !IsDataDescriptor(desc);
}
bool is_empty() const {
return !has_enumerable() && !has_configurable() && !has_writable() &&
!has_value() && !has_get() && !has_set();
}
bool enumerable() const { return enumerable_; }
void set_enumerable(bool enumerable) {
enumerable_ = enumerable;
has_enumerable_ = true;
}
bool has_enumerable() const { return has_enumerable_; }
bool configurable() const { return configurable_; }
void set_configurable(bool configurable) {
configurable_ = configurable;
has_configurable_ = true;
}
bool has_configurable() const { return has_configurable_; }
Handle<Object> value() const { return value_; }
void set_value(Handle<Object> value) { value_ = value; }
bool has_value() const { return !value_.is_null(); }
bool writable() const { return writable_; }
void set_writable(bool writable) {
writable_ = writable;
has_writable_ = true;
}
bool has_writable() const { return has_writable_; }
Handle<Object> get() const { return get_; }
void set_get(Handle<Object> get) { get_ = get; }
bool has_get() const { return !get_.is_null(); }
Handle<Object> set() const { return set_; }
void set_set(Handle<Object> set) { set_ = set; }
bool has_set() const { return !set_.is_null(); }
Handle<Object> name() const { return name_; }
void set_name(Handle<Object> name) { name_ = name; }
PropertyAttributes ToAttributes() {
return static_cast<PropertyAttributes>(
(has_enumerable() && !enumerable() ? DONT_ENUM : NONE) |
(has_configurable() && !configurable() ? DONT_DELETE : NONE) |
(has_writable() && !writable() ? READ_ONLY : NONE));
}
static bool ToPropertyDescriptor(Isolate* isolate, Handle<Object> obj,
PropertyDescriptor* desc);
private:
bool enumerable_ : 1;
bool has_enumerable_ : 1;
bool configurable_ : 1;
bool has_configurable_ : 1;
bool writable_ : 1;
bool has_writable_ : 1;
Handle<Object> value_;
Handle<Object> get_;
Handle<Object> set_;
Handle<Object> name_;
// Some compilers (Xcode 5.1, ARM GCC 4.9) insist on having a copy
// constructor for std::vector<PropertyDescriptor>, so we can't
// DISALLOW_COPY_AND_ASSIGN(PropertyDescriptor); here.
};
} // namespace internal
} // namespace v8
#endif // V8_PROPERTY_DESCRIPTOR_H_
......@@ -1627,5 +1627,22 @@ RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) {
}
RUNTIME_FUNCTION(Runtime_ObjectDefineProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(Object, o, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, name, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, attributes, 2);
return JSReceiver::DefineProperty(isolate, o, name, attributes);
}
RUNTIME_FUNCTION(Runtime_ObjectDefineProperties) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, o, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, properties, 1);
return JSReceiver::DefineProperties(isolate, o, properties);
}
} // namespace internal
} // namespace v8
......@@ -498,7 +498,9 @@ namespace internal {
F(InstanceOf, 2, 1) \
F(HasInPrototypeChain, 2, 1) \
F(CreateIterResultObject, 2, 1) \
F(IsAccessCheckNeeded, 1, 1)
F(IsAccessCheckNeeded, 1, 1) \
F(ObjectDefineProperties, 2, 1) \
F(ObjectDefineProperty, 3, 1)
#define FOR_EACH_INTRINSIC_OBSERVE(F) \
......
......@@ -896,6 +896,8 @@
'../../src/profiler/strings-storage.h',
'../../src/profiler/unbound-queue-inl.h',
'../../src/profiler/unbound-queue.h',
'../../src/property-descriptor.cc',
'../../src/property-descriptor.h',
'../../src/property-details.h',
'../../src/property.cc',
'../../src/property.h',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment