| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <sstream> | 5 #include <sstream> |
| 6 | 6 |
| 7 #include "src/v8.h" | 7 #include "src/v8.h" |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/allocation-site-scopes.h" | 10 #include "src/allocation-site-scopes.h" |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 | 426 |
| 427 Handle<Object> argv[] = { value }; | 427 Handle<Object> argv[] = { value }; |
| 428 RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver, | 428 RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver, |
| 429 arraysize(argv), argv, true), | 429 arraysize(argv), argv, true), |
| 430 Object); | 430 Object); |
| 431 return value; | 431 return value; |
| 432 } | 432 } |
| 433 | 433 |
| 434 | 434 |
| 435 static bool FindAllCanReadHolder(LookupIterator* it) { | 435 static bool FindAllCanReadHolder(LookupIterator* it) { |
| 436 for (; it->IsFound(); it->Next()) { | 436 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of |
| 437 // which have already been checked. |
| 438 DCHECK(it->state() == LookupIterator::ACCESS_CHECK || |
| 439 it->state() == LookupIterator::INTERCEPTOR); |
| 440 for (it->Next(); it->IsFound(); it->Next()) { |
| 437 if (it->state() == LookupIterator::ACCESSOR) { | 441 if (it->state() == LookupIterator::ACCESSOR) { |
| 438 Handle<Object> accessors = it->GetAccessors(); | 442 auto accessors = it->GetAccessors(); |
| 439 if (accessors->IsAccessorInfo()) { | 443 if (accessors->IsAccessorInfo()) { |
| 440 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; | 444 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; |
| 441 } | 445 } |
| 446 } else if (it->state() == LookupIterator::INTERCEPTOR) { |
| 447 auto holder = it->GetHolder<JSObject>(); |
| 448 if (holder->GetNamedInterceptor()->all_can_read()) return true; |
| 442 } | 449 } |
| 443 } | 450 } |
| 444 return false; | 451 return false; |
| 445 } | 452 } |
| 446 | 453 |
| 447 | 454 |
| 448 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( | 455 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( |
| 449 LookupIterator* it) { | 456 LookupIterator* it) { |
| 450 Handle<JSObject> checked = it->GetHolder<JSObject>(); | 457 Handle<JSObject> checked = it->GetHolder<JSObject>(); |
| 451 if (FindAllCanReadHolder(it)) { | 458 while (FindAllCanReadHolder(it)) { |
| 452 return GetPropertyWithAccessor(it->GetReceiver(), it->name(), | 459 if (it->state() == LookupIterator::ACCESSOR) { |
| 453 it->GetHolder<JSObject>(), | 460 return GetPropertyWithAccessor(it->GetReceiver(), it->name(), |
| 454 it->GetAccessors()); | 461 it->GetHolder<JSObject>(), |
| 462 it->GetAccessors()); |
| 463 } |
| 464 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
| 465 auto receiver = Handle<JSObject>::cast(it->GetReceiver()); |
| 466 auto result = GetPropertyWithInterceptor(it->GetHolder<JSObject>(), |
| 467 receiver, it->name()); |
| 468 if (it->isolate()->has_scheduled_exception()) break; |
| 469 if (!result.is_null()) return result; |
| 455 } | 470 } |
| 456 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET); | 471 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET); |
| 457 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); | 472 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
| 458 return it->factory()->undefined_value(); | 473 return it->factory()->undefined_value(); |
| 459 } | 474 } |
| 460 | 475 |
| 461 | 476 |
| 462 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( | 477 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( |
| 463 LookupIterator* it) { | 478 LookupIterator* it) { |
| 464 Handle<JSObject> checked = it->GetHolder<JSObject>(); | 479 Handle<JSObject> checked = it->GetHolder<JSObject>(); |
| 465 if (FindAllCanReadHolder(it)) | 480 while (FindAllCanReadHolder(it)) { |
| 466 return maybe(it->property_details().attributes()); | 481 if (it->state() == LookupIterator::ACCESSOR) { |
| 482 return maybe(it->property_details().attributes()); |
| 483 } |
| 484 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
| 485 auto result = GetPropertyAttributesWithInterceptor( |
| 486 it->GetHolder<JSObject>(), it->GetReceiver(), it->name()); |
| 487 if (it->isolate()->has_scheduled_exception()) break; |
| 488 if (result.has_value && result.value != ABSENT) return result; |
| 489 } |
| 467 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); | 490 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); |
| 468 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), | 491 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), |
| 469 Maybe<PropertyAttributes>()); | 492 Maybe<PropertyAttributes>()); |
| 470 return maybe(ABSENT); | 493 return maybe(ABSENT); |
| 471 } | 494 } |
| 472 | 495 |
| 473 | 496 |
| 474 static bool FindAllCanWriteHolder(LookupIterator* it) { | 497 static bool FindAllCanWriteHolder(LookupIterator* it) { |
| 475 for (; it->IsFound(); it->Next()) { | 498 for (; it->IsFound(); it->Next()) { |
| 476 if (it->state() == LookupIterator::ACCESSOR) { | 499 if (it->state() == LookupIterator::ACCESSOR) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 PropertyCell::cast(property_dictionary->ValueAt(entry))); | 566 PropertyCell::cast(property_dictionary->ValueAt(entry))); |
| 544 PropertyCell::SetValueInferType(cell, value); | 567 PropertyCell::SetValueInferType(cell, value); |
| 545 // Please note we have to update the property details. | 568 // Please note we have to update the property details. |
| 546 property_dictionary->DetailsAtPut(entry, details); | 569 property_dictionary->DetailsAtPut(entry, details); |
| 547 } else { | 570 } else { |
| 548 property_dictionary->SetEntry(entry, name, value, details); | 571 property_dictionary->SetEntry(entry, name, value, details); |
| 549 } | 572 } |
| 550 } | 573 } |
| 551 | 574 |
| 552 | 575 |
| 576 static MaybeHandle<JSObject> FindIndexedAllCanReadHolder( |
| 577 Isolate* isolate, Handle<JSObject> js_object, |
| 578 PrototypeIterator::WhereToStart where_to_start) { |
| 579 for (PrototypeIterator iter(isolate, js_object, where_to_start); |
| 580 !iter.IsAtEnd(); iter.Advance()) { |
| 581 auto curr = PrototypeIterator::GetCurrent(iter); |
| 582 if (!curr->IsJSObject()) break; |
| 583 auto obj = Handle<JSObject>::cast(curr); |
| 584 if (!obj->HasIndexedInterceptor()) continue; |
| 585 if (obj->GetIndexedInterceptor()->all_can_read()) return obj; |
| 586 } |
| 587 return MaybeHandle<JSObject>(); |
| 588 } |
| 589 |
| 590 |
| 591 MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck( |
| 592 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
| 593 uint32_t index) { |
| 594 Handle<JSObject> holder = object; |
| 595 PrototypeIterator::WhereToStart where_to_start = |
| 596 PrototypeIterator::START_AT_RECEIVER; |
| 597 while (true) { |
| 598 auto all_can_read_holder = |
| 599 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
| 600 if (!all_can_read_holder.ToHandle(&holder)) break; |
| 601 auto result = |
| 602 JSObject::GetElementWithInterceptor(holder, receiver, index, false); |
| 603 if (isolate->has_scheduled_exception()) break; |
| 604 if (!result.is_null()) return result; |
| 605 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
| 606 } |
| 607 isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET); |
| 608 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| 609 return isolate->factory()->undefined_value(); |
| 610 } |
| 611 |
| 612 |
| 613 Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( |
| 614 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
| 615 uint32_t index) { |
| 616 Handle<JSObject> holder = object; |
| 617 PrototypeIterator::WhereToStart where_to_start = |
| 618 PrototypeIterator::START_AT_RECEIVER; |
| 619 while (true) { |
| 620 auto all_can_read_holder = |
| 621 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
| 622 if (!all_can_read_holder.ToHandle(&holder)) break; |
| 623 auto result = |
| 624 JSObject::GetElementAttributeFromInterceptor(object, receiver, index); |
| 625 if (isolate->has_scheduled_exception()) break; |
| 626 if (result.has_value && result.value != ABSENT) return result; |
| 627 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
| 628 } |
| 629 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS); |
| 630 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>()); |
| 631 return maybe(ABSENT); |
| 632 } |
| 633 |
| 634 |
| 553 MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, | 635 MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
| 554 Handle<Object> object, | 636 Handle<Object> object, |
| 555 Handle<Object> receiver, | 637 Handle<Object> receiver, |
| 556 uint32_t index) { | 638 uint32_t index) { |
| 557 if (object->IsUndefined()) { | 639 if (object->IsUndefined()) { |
| 558 // TODO(verwaest): Why is this check here? | 640 // TODO(verwaest): Why is this check here? |
| 559 UNREACHABLE(); | 641 UNREACHABLE(); |
| 560 return isolate->factory()->undefined_value(); | 642 return isolate->factory()->undefined_value(); |
| 561 } | 643 } |
| 562 | 644 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 575 | 657 |
| 576 // Inline the case for JSObjects. Doing so significantly improves the | 658 // Inline the case for JSObjects. Doing so significantly improves the |
| 577 // performance of fetching elements where checking the prototype chain is | 659 // performance of fetching elements where checking the prototype chain is |
| 578 // necessary. | 660 // necessary. |
| 579 Handle<JSObject> js_object = | 661 Handle<JSObject> js_object = |
| 580 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 662 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| 581 | 663 |
| 582 // Check access rights if needed. | 664 // Check access rights if needed. |
| 583 if (js_object->IsAccessCheckNeeded()) { | 665 if (js_object->IsAccessCheckNeeded()) { |
| 584 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) { | 666 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) { |
| 585 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET); | 667 return JSObject::GetElementWithFailedAccessCheck(isolate, js_object, |
| 586 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 668 receiver, index); |
| 587 return isolate->factory()->undefined_value(); | |
| 588 } | 669 } |
| 589 } | 670 } |
| 590 | 671 |
| 591 if (js_object->HasIndexedInterceptor()) { | 672 if (js_object->HasIndexedInterceptor()) { |
| 592 return JSObject::GetElementWithInterceptor(js_object, receiver, index); | 673 return JSObject::GetElementWithInterceptor(js_object, receiver, index, |
| 674 true); |
| 593 } | 675 } |
| 594 | 676 |
| 595 if (js_object->elements() != isolate->heap()->empty_fixed_array()) { | 677 if (js_object->elements() != isolate->heap()->empty_fixed_array()) { |
| 596 Handle<Object> result; | 678 Handle<Object> result; |
| 597 ASSIGN_RETURN_ON_EXCEPTION( | 679 ASSIGN_RETURN_ON_EXCEPTION( |
| 598 isolate, result, | 680 isolate, result, |
| 599 js_object->GetElementsAccessor()->Get(receiver, js_object, index), | 681 js_object->GetElementsAccessor()->Get(receiver, js_object, index), |
| 600 Object); | 682 Object); |
| 601 if (!result->IsTheHole()) return result; | 683 if (!result->IsTheHole()) return result; |
| 602 } | 684 } |
| (...skipping 3402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4005 | 4087 |
| 4006 | 4088 |
| 4007 Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver( | 4089 Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver( |
| 4008 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index, | 4090 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index, |
| 4009 bool check_prototype) { | 4091 bool check_prototype) { |
| 4010 Isolate* isolate = object->GetIsolate(); | 4092 Isolate* isolate = object->GetIsolate(); |
| 4011 | 4093 |
| 4012 // Check access rights if needed. | 4094 // Check access rights if needed. |
| 4013 if (object->IsAccessCheckNeeded()) { | 4095 if (object->IsAccessCheckNeeded()) { |
| 4014 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) { | 4096 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) { |
| 4015 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS); | 4097 return GetElementAttributesWithFailedAccessCheck(isolate, object, |
| 4016 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>()); | 4098 receiver, index); |
| 4017 return maybe(ABSENT); | |
| 4018 } | 4099 } |
| 4019 } | 4100 } |
| 4020 | 4101 |
| 4021 if (object->IsJSGlobalProxy()) { | 4102 if (object->IsJSGlobalProxy()) { |
| 4022 PrototypeIterator iter(isolate, object); | 4103 PrototypeIterator iter(isolate, object); |
| 4023 if (iter.IsAtEnd()) return maybe(ABSENT); | 4104 if (iter.IsAtEnd()) return maybe(ABSENT); |
| 4024 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | 4105 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); |
| 4025 return JSObject::GetElementAttributeWithReceiver( | 4106 return JSObject::GetElementAttributeWithReceiver( |
| 4026 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver, | 4107 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver, |
| 4027 index, check_prototype); | 4108 index, check_prototype); |
| (...skipping 9229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13257 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { | 13338 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
| 13258 Isolate* isolate = array->GetIsolate(); | 13339 Isolate* isolate = array->GetIsolate(); |
| 13259 Handle<Name> length = isolate->factory()->length_string(); | 13340 Handle<Name> length = isolate->factory()->length_string(); |
| 13260 Handle<Object> args[2] = { length, array }; | 13341 Handle<Object> args[2] = { length, array }; |
| 13261 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", | 13342 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", |
| 13262 HandleVector(args, arraysize(args))), | 13343 HandleVector(args, arraysize(args))), |
| 13263 Object); | 13344 Object); |
| 13264 } | 13345 } |
| 13265 | 13346 |
| 13266 | 13347 |
| 13267 MaybeHandle<Object> JSObject::GetElementWithInterceptor( | 13348 MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object, |
| 13268 Handle<JSObject> object, | 13349 Handle<Object> receiver, |
| 13269 Handle<Object> receiver, | 13350 uint32_t index, |
| 13270 uint32_t index) { | 13351 bool check_prototype) { |
| 13271 Isolate* isolate = object->GetIsolate(); | 13352 Isolate* isolate = object->GetIsolate(); |
| 13272 | 13353 |
| 13273 // Make sure that the top context does not change when doing | 13354 // Make sure that the top context does not change when doing |
| 13274 // callbacks or interceptor calls. | 13355 // callbacks or interceptor calls. |
| 13275 AssertNoContextChange ncc(isolate); | 13356 AssertNoContextChange ncc(isolate); |
| 13276 | 13357 |
| 13277 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate); | 13358 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate); |
| 13278 if (!interceptor->getter()->IsUndefined()) { | 13359 if (!interceptor->getter()->IsUndefined()) { |
| 13279 v8::IndexedPropertyGetterCallback getter = | 13360 v8::IndexedPropertyGetterCallback getter = |
| 13280 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); | 13361 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); |
| 13281 LOG(isolate, | 13362 LOG(isolate, |
| 13282 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index)); | 13363 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index)); |
| 13283 PropertyCallbackArguments | 13364 PropertyCallbackArguments |
| 13284 args(isolate, interceptor->data(), *receiver, *object); | 13365 args(isolate, interceptor->data(), *receiver, *object); |
| 13285 v8::Handle<v8::Value> result = args.Call(getter, index); | 13366 v8::Handle<v8::Value> result = args.Call(getter, index); |
| 13286 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 13367 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| 13287 if (!result.IsEmpty()) { | 13368 if (!result.IsEmpty()) { |
| 13288 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); | 13369 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
| 13289 result_internal->VerifyApiCallResultType(); | 13370 result_internal->VerifyApiCallResultType(); |
| 13290 // Rebox handle before return. | 13371 // Rebox handle before return. |
| 13291 return handle(*result_internal, isolate); | 13372 return handle(*result_internal, isolate); |
| 13292 } | 13373 } |
| 13293 } | 13374 } |
| 13294 | 13375 |
| 13376 if (!check_prototype) return MaybeHandle<Object>(); |
| 13377 |
| 13295 ElementsAccessor* handler = object->GetElementsAccessor(); | 13378 ElementsAccessor* handler = object->GetElementsAccessor(); |
| 13296 Handle<Object> result; | 13379 Handle<Object> result; |
| 13297 ASSIGN_RETURN_ON_EXCEPTION( | 13380 ASSIGN_RETURN_ON_EXCEPTION( |
| 13298 isolate, result, handler->Get(receiver, object, index), | 13381 isolate, result, handler->Get(receiver, object, index), |
| 13299 Object); | 13382 Object); |
| 13300 if (!result->IsTheHole()) return result; | 13383 if (!result->IsTheHole()) return result; |
| 13301 | 13384 |
| 13302 PrototypeIterator iter(isolate, object); | 13385 PrototypeIterator iter(isolate, object); |
| 13303 if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); | 13386 if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); |
| 13304 return Object::GetElementWithReceiver( | 13387 return Object::GetElementWithReceiver( |
| (...skipping 3572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16877 Handle<DependentCode> codes = | 16960 Handle<DependentCode> codes = |
| 16878 DependentCode::Insert(handle(cell->dependent_code(), info->isolate()), | 16961 DependentCode::Insert(handle(cell->dependent_code(), info->isolate()), |
| 16879 DependentCode::kPropertyCellChangedGroup, | 16962 DependentCode::kPropertyCellChangedGroup, |
| 16880 info->object_wrapper()); | 16963 info->object_wrapper()); |
| 16881 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); | 16964 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); |
| 16882 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( | 16965 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( |
| 16883 cell, info->zone()); | 16966 cell, info->zone()); |
| 16884 } | 16967 } |
| 16885 | 16968 |
| 16886 } } // namespace v8::internal | 16969 } } // namespace v8::internal |
| OLD | NEW |