| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 5649a56464bb69300c1b031dd5c5cf4a45fbf53e..c7a806f0fb70f7254284d80b6d6515069e5eb9d4 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1764,14 +1764,11 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
|
| // found. Use set property to handle all these cases.
|
| return SetProperty(&result, name, value, attributes, strict_mode);
|
| }
|
| - bool found = false;
|
| + bool done = false;
|
| MaybeObject* result_object;
|
| - result_object = SetPropertyWithCallbackSetterInPrototypes(name,
|
| - value,
|
| - attributes,
|
| - &found,
|
| - strict_mode);
|
| - if (found) return result_object;
|
| + result_object =
|
| + SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
|
| + if (done) return result_object;
|
| // Add a new real property.
|
| return AddProperty(name, value, attributes, strict_mode);
|
| }
|
| @@ -2051,26 +2048,6 @@ MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
|
| }
|
|
|
|
|
| -void JSObject::LookupCallbackSetterInPrototypes(String* name,
|
| - LookupResult* result) {
|
| - Heap* heap = GetHeap();
|
| - for (Object* pt = GetPrototype();
|
| - pt != heap->null_value();
|
| - pt = pt->GetPrototype()) {
|
| - if (pt->IsJSProxy()) {
|
| - return result->HandlerResult(JSProxy::cast(pt));
|
| - }
|
| - JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
|
| - if (result->IsProperty()) {
|
| - if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
|
| - // Found non-callback or read-only callback, stop looking.
|
| - break;
|
| - }
|
| - }
|
| - result->NotFound();
|
| -}
|
| -
|
| -
|
| MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
|
| uint32_t index,
|
| Object* value,
|
| @@ -2087,8 +2064,8 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
|
| *found = true; // Force abort
|
| return maybe;
|
| }
|
| - return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
|
| - name, value, NONE, strict_mode, found);
|
| + return JSProxy::cast(pt)->SetPropertyViaPrototypesWithHandler(
|
| + this, name, value, NONE, strict_mode, found);
|
| }
|
| if (!JSObject::cast(pt)->HasDictionaryElements()) {
|
| continue;
|
| @@ -2112,45 +2089,59 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
|
| return heap->the_hole_value();
|
| }
|
|
|
| -MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
|
| +MaybeObject* JSObject::SetPropertyViaPrototypes(
|
| String* name,
|
| Object* value,
|
| PropertyAttributes attributes,
|
| - bool* found,
|
| - StrictModeFlag strict_mode) {
|
| + StrictModeFlag strict_mode,
|
| + bool* done) {
|
| Heap* heap = GetHeap();
|
| + Isolate* isolate = heap->isolate();
|
| +
|
| + *done = false;
|
| // We could not find a local property so let's check whether there is an
|
| - // accessor that wants to handle the property.
|
| - LookupResult accessor_result(heap->isolate());
|
| - LookupCallbackSetterInPrototypes(name, &accessor_result);
|
| - if (accessor_result.IsFound()) {
|
| - *found = true;
|
| - if (accessor_result.type() == CALLBACKS) {
|
| - return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
|
| - name,
|
| - value,
|
| - accessor_result.holder(),
|
| - strict_mode);
|
| - } else if (accessor_result.type() == HANDLER) {
|
| - // There is a proxy in the prototype chain. Invoke its
|
| - // getPropertyDescriptor trap.
|
| - bool found = false;
|
| - // SetPropertyWithHandlerIfDefiningSetter can cause GC,
|
| - // make sure to use the handlified references after calling
|
| - // the function.
|
| - Handle<JSObject> self(this);
|
| - Handle<String> hname(name);
|
| - Handle<Object> hvalue(value);
|
| - MaybeObject* result =
|
| - accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
|
| - name, value, attributes, strict_mode, &found);
|
| - if (found) return result;
|
| - // The proxy does not define the property as an accessor.
|
| - // Consequently, it has no effect on setting the receiver.
|
| - return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
|
| + // accessor that wants to handle the property, or whether the property is
|
| + // read-only on the prototype chain.
|
| + LookupResult result(isolate);
|
| + LookupRealNamedPropertyInPrototypes(name, &result);
|
| + if (result.IsFound()) {
|
| + switch (result.type()) {
|
| + case NORMAL:
|
| + case FIELD:
|
| + case CONSTANT_FUNCTION:
|
| + *done = result.IsReadOnly();
|
| + break;
|
| + case INTERCEPTOR: {
|
| + PropertyAttributes attr =
|
| + result.holder()->GetPropertyAttributeWithInterceptor(
|
| + this, name, true);
|
| + *done = !!(attr & READ_ONLY);
|
| + break;
|
| + }
|
| + case CALLBACKS: {
|
| + *done = true;
|
| + return SetPropertyWithCallback(result.GetCallbackObject(),
|
| + name, value, result.holder(), strict_mode);
|
| + }
|
| + case HANDLER: {
|
| + return result.proxy()->SetPropertyViaPrototypesWithHandler(
|
| + this, name, value, attributes, strict_mode, done);
|
| + }
|
| + case MAP_TRANSITION:
|
| + case CONSTANT_TRANSITION:
|
| + case NULL_DESCRIPTOR:
|
| + case ELEMENTS_TRANSITION:
|
| + break;
|
| }
|
| }
|
| - *found = false;
|
| +
|
| + // If we get here with *done true, we have encountered a read-only property.
|
| + if (*done) {
|
| + if (strict_mode == kNonStrictMode) return value;
|
| + Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)};
|
| + return isolate->Throw(*isolate->factory()->NewTypeError(
|
| + "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
|
| + }
|
| return heap->the_hole_value();
|
| }
|
|
|
| @@ -2541,9 +2532,12 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
|
| Heap* heap = GetHeap();
|
| for (Object* pt = GetPrototype();
|
| pt != heap->null_value();
|
| - pt = JSObject::cast(pt)->GetPrototype()) {
|
| + pt = pt->GetPrototype()) {
|
| + if (pt->IsJSProxy()) {
|
| + return result->HandlerResult(JSProxy::cast(pt));
|
| + }
|
| JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
|
| - if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
|
| + if (result->IsProperty()) return;
|
| }
|
| result->NotFound();
|
| }
|
| @@ -2557,7 +2551,7 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
|
| bool check_prototype,
|
| StrictModeFlag strict_mode) {
|
| if (check_prototype && !result->IsProperty()) {
|
| - LookupCallbackSetterInPrototypes(name, result);
|
| + LookupRealNamedPropertyInPrototypes(name, result);
|
| }
|
|
|
| if (result->IsProperty()) {
|
| @@ -2630,7 +2624,7 @@ bool JSProxy::HasPropertyWithHandler(String* name_raw) {
|
| Handle<Object> args[] = { name };
|
| Handle<Object> result = CallTrap(
|
| "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
|
| - if (isolate->has_pending_exception()) return Failure::Exception();
|
| + if (isolate->has_pending_exception()) return false;
|
|
|
| return result->ToBoolean()->IsTrue();
|
| }
|
| @@ -2655,77 +2649,92 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
|
| }
|
|
|
|
|
| -MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
|
| +MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler(
|
| + JSObject* receiver_raw,
|
| String* name_raw,
|
| Object* value_raw,
|
| PropertyAttributes attributes,
|
| StrictModeFlag strict_mode,
|
| - bool* found) {
|
| - *found = true; // except where defined otherwise...
|
| - Isolate* isolate = GetHeap()->isolate();
|
| + bool* done) {
|
| + Isolate* isolate = GetIsolate();
|
| Handle<JSProxy> proxy(this);
|
| - Handle<Object> handler(this->handler()); // Trap might morph proxy.
|
| + Handle<JSObject> receiver(receiver_raw);
|
| Handle<String> name(name_raw);
|
| Handle<Object> value(value_raw);
|
| + Handle<Object> handler(this->handler()); // Trap might morph proxy.
|
| +
|
| + *done = true; // except where redefined...
|
| Handle<Object> args[] = { name };
|
| Handle<Object> result = proxy->CallTrap(
|
| "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
|
| if (isolate->has_pending_exception()) return Failure::Exception();
|
|
|
| - if (!result->IsUndefined()) {
|
| - // The proxy handler cares about this property.
|
| - // Check whether it is virtualized as an accessor.
|
| - // Emulate [[GetProperty]] semantics for proxies.
|
| - bool has_pending_exception;
|
| - Handle<Object> argv[] = { result };
|
| - Handle<Object> desc =
|
| - Execution::Call(isolate->to_complete_property_descriptor(), result,
|
| - ARRAY_SIZE(argv), argv, &has_pending_exception);
|
| - if (has_pending_exception) return Failure::Exception();
|
| -
|
| - Handle<String> conf_name =
|
| - isolate->factory()->LookupAsciiSymbol("configurable_");
|
| - Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
|
| - ASSERT(!isolate->has_pending_exception());
|
| - if (configurable->IsFalse()) {
|
| - Handle<String> trap =
|
| - isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
|
| - Handle<Object> args[] = { handler, trap, name };
|
| - Handle<Object> error = isolate->factory()->NewTypeError(
|
| - "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
|
| - return isolate->Throw(*error);
|
| - }
|
| - ASSERT(configurable->IsTrue());
|
| + if (result->IsUndefined()) {
|
| + *done = false;
|
| + return GetHeap()->the_hole_value();
|
| + }
|
| +
|
| + // Emulate [[GetProperty]] semantics for proxies.
|
| + bool has_pending_exception;
|
| + Handle<Object> argv[] = { result };
|
| + Handle<Object> desc =
|
| + Execution::Call(isolate->to_complete_property_descriptor(), result,
|
| + ARRAY_SIZE(argv), argv, &has_pending_exception);
|
| + if (has_pending_exception) return Failure::Exception();
|
|
|
| - // Check for AccessorDescriptor.
|
| - Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
|
| - Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
|
| + // [[GetProperty]] requires to check that all properties are configurable.
|
| + Handle<String> configurable_name =
|
| + isolate->factory()->LookupAsciiSymbol("configurable_");
|
| + Handle<Object> configurable(
|
| + v8::internal::GetProperty(desc, configurable_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + ASSERT(configurable->IsTrue() || configurable->IsFalse());
|
| + if (configurable->IsFalse()) {
|
| + Handle<String> trap =
|
| + isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
|
| + Handle<Object> args[] = { handler, trap, name };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
|
| + return isolate->Throw(*error);
|
| + }
|
| + ASSERT(configurable->IsTrue());
|
| +
|
| + // Check for DataDescriptor.
|
| + Handle<String> hasWritable_name =
|
| + isolate->factory()->LookupAsciiSymbol("hasWritable_");
|
| + Handle<Object> hasWritable(v8::internal::GetProperty(desc, hasWritable_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
|
| + if (hasWritable->IsTrue()) {
|
| + Handle<String> writable_name =
|
| + isolate->factory()->LookupAsciiSymbol("writable_");
|
| + Handle<Object> writable(v8::internal::GetProperty(desc, writable_name));
|
| ASSERT(!isolate->has_pending_exception());
|
| - if (!setter->IsUndefined()) {
|
| - // We have a setter -- invoke it.
|
| - // TODO(rossberg): nicer would be to cast to some JSCallable here...
|
| - return proxy->SetPropertyWithDefinedSetter(
|
| - JSReceiver::cast(*setter), *value);
|
| - } else {
|
| - Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
|
| - Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
|
| - ASSERT(!isolate->has_pending_exception());
|
| - if (!getter->IsUndefined()) {
|
| - // We have a getter but no setter -- the property may not be
|
| - // written. In strict mode, throw an error.
|
| - if (strict_mode == kNonStrictMode) return *value;
|
| - Handle<Object> args[] = { name, proxy };
|
| - Handle<Object> error = isolate->factory()->NewTypeError(
|
| - "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
|
| - return isolate->Throw(*error);
|
| - }
|
| - }
|
| - // Fall-through.
|
| + ASSERT(writable->IsTrue() || writable->IsFalse());
|
| + *done = writable->IsFalse();
|
| + if (!*done) return GetHeap()->the_hole_value();
|
| + if (strict_mode == kNonStrictMode) return *value;
|
| + Handle<Object> args[] = { name, receiver };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
|
| + return isolate->Throw(*error);
|
| }
|
|
|
| - // The proxy does not define the property as an accessor.
|
| - *found = false;
|
| - return *value;
|
| + // We have an AccessorDescriptor.
|
| + Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
|
| + Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + if (!setter->IsUndefined()) {
|
| + // TODO(rossberg): nicer would be to cast to some JSCallable here...
|
| + return proxy->SetPropertyWithDefinedSetter(
|
| + JSReceiver::cast(*setter), *value);
|
| + }
|
| +
|
| + if (strict_mode == kNonStrictMode) return *value;
|
| + Handle<Object> args2[] = { name, proxy };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
|
| + return isolate->Throw(*error);
|
| }
|
|
|
|
|
| @@ -2918,18 +2927,11 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
|
| }
|
|
|
| if (!result->IsProperty() && !IsJSContextExtensionObject()) {
|
| - bool found = false;
|
| - MaybeObject* result_object;
|
| - result_object = SetPropertyWithCallbackSetterInPrototypes(name,
|
| - value,
|
| - attributes,
|
| - &found,
|
| - strict_mode);
|
| - if (found) return result_object;
|
| - }
|
| -
|
| - // At this point, no GC should have happened, as this would invalidate
|
| - // 'result', which we cannot handlify!
|
| + bool done = false;
|
| + MaybeObject* result_object =
|
| + SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
|
| + if (done) return result_object;
|
| + }
|
|
|
| if (!result->IsFound()) {
|
| // Neither properties nor transitions found.
|
|
|