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

[proxies] Teach ToPropertyDescriptor to deal with Proxies

BUG=v8:1543
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31962}
parent 2b6d07ab
...@@ -20,11 +20,11 @@ bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name, ...@@ -20,11 +20,11 @@ bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name,
Handle<Object>* value) { Handle<Object>* value) {
LookupIterator it(obj, name); LookupIterator it(obj, name);
// 4. Let hasEnumerable be HasProperty(Obj, "enumerable"). // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
Maybe<PropertyAttributes> maybe_attr = JSReceiver::GetPropertyAttributes(&it); Maybe<bool> has_property = JSReceiver::HasProperty(&it);
// 5. ReturnIfAbrupt(hasEnumerable). // 5. ReturnIfAbrupt(hasEnumerable).
if (!maybe_attr.IsJust()) return false; if (has_property.IsNothing()) return false;
// 6. If hasEnumerable is true, then // 6. If hasEnumerable is true, then
if (maybe_attr.FromJust() != ABSENT) { if (has_property.FromJust() == true) {
// 6a. Let enum be ToBoolean(Get(Obj, "enumerable")). // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
// 6b. ReturnIfAbrupt(enum). // 6b. ReturnIfAbrupt(enum).
if (!JSObject::GetProperty(&it).ToHandle(value)) return false; if (!JSObject::GetProperty(&it).ToHandle(value)) return false;
...@@ -160,109 +160,141 @@ bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate, ...@@ -160,109 +160,141 @@ bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
return true; return true;
} }
// TODO(jkummerow): Implement JSProxy support. // enumerable?
// Specifically, instead of taking the attributes != ABSENT shortcut, we Handle<Object> enumerable;
// have to implement proper HasProperty for proxies. // 4 through 6b.
if (!obj->IsJSProxy()) { if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(),
{ // enumerable? &enumerable)) {
Handle<Object> enumerable; return false;
// 4 through 6b. }
if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), // 6c. Set the [[Enumerable]] field of desc to enum.
&enumerable)) { if (!enumerable.is_null()) {
return false; desc->set_enumerable(enumerable->BooleanValue());
} }
// 6c. Set the [[Enumerable]] field of desc to enum.
if (!enumerable.is_null()) { // configurable?
desc->set_enumerable(enumerable->BooleanValue()); Handle<Object> configurable;
} // 7 through 9b.
} if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(),
{ // configurable? &configurable)) {
Handle<Object> configurable; return false;
// 7 through 9b. }
if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), // 9c. Set the [[Configurable]] field of desc to conf.
&configurable)) { if (!configurable.is_null()) {
return false; desc->set_configurable(configurable->BooleanValue());
} }
// 9c. Set the [[Configurable]] field of desc to conf.
if (!configurable.is_null()) { // value?
desc->set_configurable(configurable->BooleanValue()); Handle<Object> value;
} // 10 through 12b.
} if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), &value)) {
{ // value? return false;
Handle<Object> value; }
// 10 through 12b. // 12c. Set the [[Value]] field of desc to value.
if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), if (!value.is_null()) desc->set_value(value);
&value))
return false; // writable?
// 12c. Set the [[Value]] field of desc to value. Handle<Object> writable;
if (!value.is_null()) desc->set_value(value); // 13 through 15b.
} if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(),
{ // writable? &writable)) {
Handle<Object> writable; return false;
// 13 through 15b. }
if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), // 15c. Set the [[Writable]] field of desc to writable.
&writable)) { if (!writable.is_null()) desc->set_writable(writable->BooleanValue());
return false;
} // getter?
// 15c. Set the [[Writable]] field of desc to writable. Handle<Object> getter;
if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); // 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;
} }
{ // getter? // 18d. Set the [[Get]] field of desc to getter.
Handle<Object> getter; desc->set_get(getter);
// 16 through 18b. }
if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) // setter?
return false; Handle<Object> setter;
if (!getter.is_null()) { // 19 through 21b.
// 18c. If IsCallable(getter) is false and getter is not undefined, if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), &setter)) {
// throw a TypeError exception. return false;
if (!getter->IsCallable() && !getter->IsUndefined()) { }
isolate->Throw(*isolate->factory()->NewTypeError( if (!setter.is_null()) {
MessageTemplate::kObjectGetterCallable, getter)); // 21c. If IsCallable(setter) is false and setter is not undefined,
return false; // throw a TypeError exception.
} if (!setter->IsCallable() && !setter->IsUndefined()) {
// 18d. Set the [[Get]] field of desc to getter. isolate->Throw(*isolate->factory()->NewTypeError(
desc->set_get(getter); MessageTemplate::kObjectSetterCallable, setter));
} return false;
{ // 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 { // 21d. Set the [[Set]] field of desc to setter.
DCHECK(obj->IsJSProxy()); desc->set_set(setter);
// Having an UNIMPLEMENTED() here would upset ClusterFuzz, because }
// --harmony-proxies makes it possible to reach this branch.
isolate->Throw( // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
*isolate->factory()->NewTypeError(MessageTemplate::kUnsupported)); // 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; return false;
} }
// 23. Return desc. // 23. Return desc.
return true; return true;
} }
// ES6 6.2.4.6
// static
void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate,
PropertyDescriptor* desc) {
// 1. ReturnIfAbrupt(Desc).
// 2. Assert: Desc is a Property Descriptor.
// 3. Let like be Record{
// [[Value]]: undefined, [[Writable]]: false,
// [[Get]]: undefined, [[Set]]: undefined,
// [[Enumerable]]: false, [[Configurable]]: false}.
// 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true,
// then:
if (!IsAccessorDescriptor(desc)) {
// 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
// like.[[Value]].
if (!desc->has_value()) {
desc->set_value(isolate->factory()->undefined_value());
}
// 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]]
// to like.[[Writable]].
if (!desc->has_writable()) desc->set_writable(false);
} else {
// 5. Else,
// 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to
// like.[[Get]].
if (!desc->has_get()) {
desc->set_get(isolate->factory()->undefined_value());
}
// 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to
// like.[[Set]].
if (!desc->has_set()) {
desc->set_set(isolate->factory()->undefined_value());
}
}
// 6. If Desc does not have an [[Enumerable]] field, set
// Desc.[[Enumerable]] to like.[[Enumerable]].
if (!desc->has_enumerable()) desc->set_enumerable(false);
// 7. If Desc does not have a [[Configurable]] field, set
// Desc.[[Configurable]] to like.[[Configurable]].
if (!desc->has_configurable()) desc->set_configurable(false);
// 8. Return Desc.
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -41,6 +41,17 @@ class PropertyDescriptor { ...@@ -41,6 +41,17 @@ class PropertyDescriptor {
return !IsAccessorDescriptor(desc) && !IsDataDescriptor(desc); return !IsAccessorDescriptor(desc) && !IsDataDescriptor(desc);
} }
// ES6 6.2.4.4
Handle<Object> ToObject(Isolate* isolate);
// ES6 6.2.4.5
static bool ToPropertyDescriptor(Isolate* isolate, Handle<Object> obj,
PropertyDescriptor* desc);
// ES6 6.2.4.6
static void CompletePropertyDescriptor(Isolate* isolate,
PropertyDescriptor* desc);
bool is_empty() const { bool is_empty() const {
return !has_enumerable() && !has_configurable() && !has_writable() && return !has_enumerable() && !has_configurable() && !has_writable() &&
!has_value() && !has_get() && !has_set(); !has_value() && !has_get() && !has_set();
...@@ -89,11 +100,6 @@ class PropertyDescriptor { ...@@ -89,11 +100,6 @@ class PropertyDescriptor {
(has_writable() && !writable() ? READ_ONLY : NONE)); (has_writable() && !writable() ? READ_ONLY : NONE));
} }
Handle<Object> ToObject(Isolate* isolate);
static bool ToPropertyDescriptor(Isolate* isolate, Handle<Object> obj,
PropertyDescriptor* desc);
private: private:
bool enumerable_ : 1; bool enumerable_ : 1;
bool has_enumerable_ : 1; bool has_enumerable_ : 1;
......
...@@ -251,6 +251,9 @@ MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, ...@@ -251,6 +251,9 @@ MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
// if args[1] is an accessor on args[0] // if args[1] is an accessor on args[0]
// [true, GetFunction, SetFunction, Enumerable, Configurable] // [true, GetFunction, SetFunction, Enumerable, Configurable]
RUNTIME_FUNCTION(Runtime_GetOwnProperty) { RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
// TODO(jkummerow): Support Proxies.
// TODO(jkummerow): Use JSReceiver::GetOwnPropertyDescriptor() and
// PropertyDescriptor::ToObject().
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
...@@ -656,6 +659,8 @@ RUNTIME_FUNCTION(Runtime_HasOwnProperty) { ...@@ -656,6 +659,8 @@ RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
// Fast case: either the key is a real named property or it is not // Fast case: either the key is a real named property or it is not
// an array index and there are no interceptors or hidden // an array index and there are no interceptors or hidden
// prototypes. // prototypes.
// TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
// handle all cases directly (without this custom fast path).
Maybe<bool> maybe = Nothing<bool>(); Maybe<bool> maybe = Nothing<bool>();
if (key_is_array_index) { if (key_is_array_index) {
maybe = JSObject::HasOwnElement(js_obj, index); maybe = JSObject::HasOwnElement(js_obj, index);
...@@ -757,6 +762,8 @@ RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { ...@@ -757,6 +762,8 @@ RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
// Return the names of the own named properties. // Return the names of the own named properties.
// args[0]: object // args[0]: object
// args[1]: PropertyAttributes as int // args[1]: PropertyAttributes as int
// TODO(cbruni/jkummerow): Use JSReceiver::GetKeys() internally, merge with
// Runtime_GetOwnElementNames.
RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 2);
......
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