Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(935)

Unified Diff: src/objects.cc

Issue 10388047: Implement correct checking for inherited readonliness on assignment. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed Michael's comments. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/stub-cache.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « src/objects.h ('k') | src/stub-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698