Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 3eedfe92faf08b10e71b512049509a7e197ceb26..831c81836a36aa7339987ab2cebc9f3fc7decd1e 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -802,6 +802,103 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
| } |
| +static MaybeHandle<Object> GetElementStructure(Isolate* isolate, |
| + Handle<JSObject> object, |
| + uint32_t index) { |
|
Toon Verwaest
2014/10/14 08:31:54
Replace by JSObject::GetOwnElementAccessorPair
Dmitry Lomov (no reviews)
2014/10/14 09:08:37
Is that enough? SetElementWithCallback handles mor
|
| + if (!object->HasDictionaryElements() && |
| + !object->HasDictionaryArgumentsElements()) |
| + return MaybeHandle<Object>(); |
| + Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
| + bool is_arguments = |
| + (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); |
| + Handle<SeededNumberDictionary> dictionary( |
| + is_arguments ? SeededNumberDictionary::cast(elements->get(1)) |
| + : SeededNumberDictionary::cast(*elements)); |
| + int entry = dictionary->FindEntry(index); |
| + if (entry != SeededNumberDictionary::kNotFound) { |
| + Handle<Object> element(dictionary->ValueAt(entry), isolate); |
| + PropertyDetails details = dictionary->DetailsAt(entry); |
| + if (details.type() == CALLBACKS) return element; |
| + } |
| + return MaybeHandle<Object>(); |
| +} |
| + |
| + |
| +MaybeHandle<Object> Object::SetElementWithReceiver( |
| + Isolate* isolate, Handle<Object> object, Handle<Object> receiver, |
| + uint32_t index, Handle<Object> value, StrictMode strict_mode) { |
| + // Iterate up the prototype chain until an element is found or the null |
| + // prototype is encountered. |
| + bool done = false; |
| + for (PrototypeIterator iter(isolate, object, |
| + object->IsJSProxy() || object->IsJSObject() |
| + ? PrototypeIterator::START_AT_RECEIVER |
| + : PrototypeIterator::START_AT_PROTOTYPE); |
| + !iter.IsAtEnd() && !done; iter.Advance()) { |
| + if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
| + // TODO(dslomov): implement. |
| + isolate->ThrowIllegalOperation(); |
| + return MaybeHandle<Object>(); |
| + } |
| + |
| + Handle<JSObject> js_object = |
| + Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| + |
| + // Check access rights if needed. |
| + if (js_object->IsAccessCheckNeeded()) { |
| + if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_SET)) { |
| + isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_SET); |
| + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| + return isolate->factory()->undefined_value(); |
| + } |
| + } |
| + |
| + if (js_object->HasIndexedInterceptor()) { |
| + Maybe<PropertyAttributes> from_interceptor = |
| + JSObject::GetElementAttributeFromInterceptor(js_object, receiver, |
| + index); |
| + if (from_interceptor.has_value) { |
|
Toon Verwaest
2014/10/14 08:31:54
The contract is normally that if !has_value, an ex
Dmitry Lomov (no reviews)
2014/10/14 09:08:37
I see. Wow, all those things could use some docume
Dmitry Lomov (no reviews)
2014/10/14 09:28:26
Done.
|
| + if ((from_interceptor.value & READ_ONLY) != 0) { |
| + return WriteToReadOnlyElement(isolate, receiver, index, value, |
| + strict_mode); |
| + } |
| + // Treat indexed interceptor as presence of data property. |
| + done = true; |
| + } |
| + } else if (js_object->elements() != isolate->heap()->empty_fixed_array()) { |
| + ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| + PropertyAttributes attrs = |
| + accessor->GetAttributes(receiver, js_object, index); |
| + if ((attrs & READ_ONLY) != 0) { |
| + return WriteToReadOnlyElement(isolate, receiver, index, value, |
| + strict_mode); |
| + } |
| + Handle<Object> element_structure; |
| + if (GetElementStructure(isolate, js_object, index) |
| + .ToHandle(&element_structure)) { |
| + return JSObject::SetElementWithCallback( |
| + receiver, element_structure, index, value, js_object, strict_mode); |
| + } else { |
| + done = attrs != ABSENT; |
| + } |
| + } |
| + } |
| + |
| + if (!receiver->IsJSObject()) { |
| + return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode); |
| + } |
| + Handle<JSObject> target = Handle<JSObject>::cast(receiver); |
| + ElementsAccessor* accessor = target->GetElementsAccessor(); |
| + PropertyAttributes attrs = accessor->GetAttributes(receiver, target, index); |
| + if ((attrs & READ_ONLY) != 0) { |
| + return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode); |
| + } |
| + PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE; |
| + return JSObject::SetElement(target, index, value, new_attrs, strict_mode, |
| + false); |
| +} |
| + |
| + |
| Map* Object::GetRootMap(Isolate* isolate) { |
| DisallowHeapAllocation no_alloc; |
| if (IsSmi()) { |
| @@ -2930,6 +3027,21 @@ MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it, |
| } |
| +MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate, |
| + Handle<Object> receiver, |
| + uint32_t index, |
| + Handle<Object> value, |
| + StrictMode strict_mode) { |
| + if (strict_mode != STRICT) return value; |
| + |
| + Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index), |
| + receiver}; |
| + THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", |
| + HandleVector(args, arraysize(args))), |
| + Object); |
| +} |
| + |
| + |
| Handle<Object> Object::SetDataProperty(LookupIterator* it, |
| Handle<Object> value) { |
| // Proxies are handled on the WithHandler path. Other non-JSObjects cannot |
| @@ -4057,6 +4169,21 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor( |
| // callbacks or interceptor calls. |
| AssertNoContextChange ncc(isolate); |
| + Maybe<PropertyAttributes> from_interceptor = |
| + GetElementAttributeFromInterceptor(object, receiver, index); |
| + |
| + if (from_interceptor.has_value) return from_interceptor; |
| + |
| + return GetElementAttributeWithoutInterceptor(object, receiver, index, |
| + check_prototype); |
| +} |
| + |
| + |
| +Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor( |
| + Handle<JSObject> object, Handle<Object> receiver, uint32_t index) { |
| + Isolate* isolate = object->GetIsolate(); |
| + AssertNoContextChange ncc(isolate); |
| + |
| Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); |
| PropertyCallbackArguments args( |
| isolate, interceptor->data(), *receiver, *object); |
| @@ -4078,8 +4205,7 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor( |
| if (!result.IsEmpty()) return maybe(NONE); |
| } |
| - return GetElementAttributeWithoutInterceptor( |
| - object, receiver, index, check_prototype); |
| + return Maybe<PropertyAttributes>(); |
| } |
| @@ -11871,13 +11997,10 @@ MaybeHandle<Object> JSObject::GetElementWithCallback( |
| } |
| -MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object, |
| - Handle<Object> structure, |
| - uint32_t index, |
| - Handle<Object> value, |
| - Handle<JSObject> holder, |
| - StrictMode strict_mode) { |
| - Isolate* isolate = object->GetIsolate(); |
| +MaybeHandle<Object> JSObject::SetElementWithCallback( |
| + Handle<Object> object, Handle<Object> structure, uint32_t index, |
| + Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode) { |
| + Isolate* isolate = holder->GetIsolate(); |
| // We should never get here to initialize a const with the hole |
| // value since a const declaration would conflict with the setter. |
| @@ -11893,7 +12016,7 @@ MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object, |
| if (call_fun == NULL) return value; |
| Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
| Handle<String> key(isolate->factory()->NumberToString(number)); |
| - LOG(isolate, ApiNamedPropertyAccess("store", *object, *key)); |
| + LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key)); |
| PropertyCallbackArguments |
| args(isolate, data->data(), *object, *holder); |
| args.Call(call_fun, |