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 |