Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/lookup.cc b/src/lookup.cc
index 8088f4d..48da4fa 100644
--- a/src/lookup.cc
+++ b/src/lookup.cc
@@ -2,17 +2,49 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
+#include "src/lookup.h"
#include "src/bootstrapper.h"
#include "src/deoptimizer.h"
-#include "src/lookup.h"
-#include "src/lookup-inl.h"
+#include "src/elements.h"
+#include "src/isolate-inl.h"
namespace v8 {
namespace internal {
+// static
+LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
+ Handle<Object> receiver,
+ Handle<Object> key,
+ bool* success,
+ Configuration configuration) {
+ uint32_t index = 0;
+ if (key->ToArrayIndex(&index)) {
+ *success = true;
+ return LookupIterator(isolate, receiver, index, configuration);
+ }
+
+ Handle<Name> name;
+ *success = Object::ToName(isolate, key).ToHandle(&name);
+ if (!*success) {
+ DCHECK(isolate->has_pending_exception());
+ // Return an unusable dummy.
+ return LookupIterator(receiver, isolate->factory()->empty_string());
+ }
+
+ if (name->AsArrayIndex(&index)) {
+ LookupIterator it(isolate, receiver, index, configuration);
+ // Here we try to avoid having to rebuild the string later
+ // by storing it on the indexed LookupIterator.
+ it.name_ = name;
+ return it;
+ }
+
+ return LookupIterator(receiver, name, configuration);
+}
+
+
void LookupIterator::Next() {
DCHECK_NE(JSPROXY, state_);
DCHECK_NE(TRANSITION, state_);
@@ -29,7 +61,13 @@
// Continue lookup if lookup on current holder failed.
do {
JSReceiver* maybe_holder = NextHolder(map);
- if (maybe_holder == NULL) break;
+ if (maybe_holder == nullptr) {
+ if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
+ RestartLookupForNonMaskingInterceptors();
+ return;
+ }
+ break;
+ }
holder = maybe_holder;
map = holder->map();
state_ = LookupInHolder(map, holder);
@@ -42,17 +80,42 @@
}
-Handle<JSReceiver> LookupIterator::GetRoot() const {
- if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_);
- Handle<Object> root =
- handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_);
- CHECK(!root->IsNull());
+void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
+ state_ = NOT_FOUND;
+ interceptor_state_ = interceptor_state;
+ property_details_ = PropertyDetails::Empty();
+ holder_ = initial_holder_;
+ holder_map_ = handle(holder_->map(), isolate_);
+ number_ = DescriptorArray::kNotFound;
+ Next();
+}
+
+
+// static
+Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
+ Isolate* isolate, Handle<Object> receiver, uint32_t index) {
+ // Strings are the only objects with properties (only elements) directly on
+ // the wrapper. Hence we can skip generating the wrapper for all other cases.
+ if (index != kMaxUInt32 && receiver->IsString() &&
+ index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
+ // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
+ // context, ensuring that we don't leak it into JS?
+ Handle<JSFunction> constructor = isolate->string_function();
+ Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
+ Handle<JSValue>::cast(result)->set_value(*receiver);
+ return result;
+ }
+ auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
+ if (root->IsNull()) {
+ unsigned int magic = 0xbbbbbbbb;
+ isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
+ }
return Handle<JSReceiver>::cast(root);
}
Handle<Map> LookupIterator::GetReceiverMap() const {
- if (receiver_->IsNumber()) return isolate_->factory()->heap_number_map();
+ if (receiver_->IsNumber()) return factory()->heap_number_map();
return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
}
@@ -61,37 +124,63 @@
if (receiver_->IsJSGlobalProxy()) {
PrototypeIterator iter(isolate(), receiver_);
if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_);
- return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+ return PrototypeIterator::GetCurrent<JSGlobalObject>(iter);
}
return Handle<JSObject>::cast(receiver_);
}
-bool LookupIterator::IsBootstrapping() const {
- return isolate_->bootstrapper()->IsActive();
-}
-
-
-bool LookupIterator::HasAccess(v8::AccessType access_type) const {
+bool LookupIterator::HasAccess() const {
DCHECK_EQ(ACCESS_CHECK, state_);
- return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type);
+ return isolate_->MayAccess(handle(isolate_->context()),
+ GetHolder<JSObject>());
}
void LookupIterator::ReloadPropertyInformation() {
state_ = BEFORE_PROPERTY;
+ interceptor_state_ = InterceptorState::kUninitialized;
state_ = LookupInHolder(*holder_map_, *holder_);
DCHECK(IsFound() || holder_map_->is_dictionary_map());
}
+void LookupIterator::ReloadHolderMap() {
+ DCHECK_EQ(DATA, state_);
+ DCHECK(IsElement());
+ DCHECK(JSObject::cast(*holder_)->HasFixedTypedArrayElements());
+ if (*holder_map_ != holder_->map()) {
+ holder_map_ = handle(holder_->map(), isolate_);
+ }
+}
+
+
void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
DCHECK(state_ == DATA || state_ == ACCESSOR);
DCHECK(HolderIsReceiverOrHiddenPrototype());
- if (holder_map_->is_dictionary_map()) return;
- holder_map_ =
- Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
- JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_);
+
+ Handle<JSObject> holder = GetHolder<JSObject>();
+
+ if (IsElement()) {
+ ElementsKind kind = holder_map_->elements_kind();
+ ElementsKind to = value->OptimalElementsKind();
+ if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
+ to = GetMoreGeneralElementsKind(kind, to);
+ JSObject::TransitionElementsKind(holder, to);
+ holder_map_ = handle(holder->map(), isolate_);
+
+ // Copy the backing store if it is copy-on-write.
+ if (IsFastSmiOrObjectElementsKind(to)) {
+ JSObject::EnsureWritableFastElements(holder);
+ }
+
+ } else {
+ if (holder_map_->is_dictionary_map()) return;
+ holder_map_ =
+ Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
+ }
+
+ JSObject::MigrateToMap(holder, holder_map_);
ReloadPropertyInformation();
}
@@ -101,16 +190,32 @@
DCHECK(state_ == DATA || state_ == ACCESSOR);
DCHECK(HolderIsReceiverOrHiddenPrototype());
Handle<JSObject> holder = GetHolder<JSObject>();
- if (holder_map_->is_dictionary_map()) {
- PropertyDetails details(attributes, FIELD, 0);
+ if (IsElement()) {
+ DCHECK(!holder->HasFixedTypedArrayElements());
+ DCHECK(attributes != NONE || !holder->HasFastElements());
+ Handle<FixedArrayBase> elements(holder->elements());
+ holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
+ attributes);
+ } else if (holder_map_->is_dictionary_map()) {
+ PropertyDetails details(attributes, v8::internal::DATA, 0,
+ PropertyCellType::kMutable);
JSObject::SetNormalizedProperty(holder, name(), value, details);
} else {
- holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(),
- attributes);
+ holder_map_ = Map::ReconfigureExistingProperty(
+ holder_map_, descriptor_number(), i::kData, attributes);
+ holder_map_ =
+ Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
JSObject::MigrateToMap(holder, holder_map_);
}
ReloadPropertyInformation();
+ WriteDataValue(value);
+
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ holder->JSObjectVerify();
+ }
+#endif
}
@@ -119,9 +224,10 @@
Object::StoreFromKeyed store_mode) {
if (state_ == TRANSITION) return;
DCHECK(state_ != LookupIterator::ACCESSOR ||
- GetAccessors()->IsDeclaredAccessorInfo());
+ (GetAccessors()->IsAccessorInfo() &&
+ AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
+ DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
-
// Can only be called when the receiver is a JSObject. JSProxy has to be
// handled via a trap. Adding properties to primitive values is not
// observable.
@@ -132,9 +238,22 @@
return;
}
- transition_map_ = Map::TransitionToDataProperty(
+ auto transition = Map::TransitionToDataProperty(
handle(receiver->map(), isolate_), name_, value, attributes, store_mode);
state_ = TRANSITION;
+ transition_ = transition;
+
+ if (receiver->IsJSGlobalObject()) {
+ // Install a property cell.
+ InternalizeName();
+ auto cell = JSGlobalObject::EnsurePropertyCell(
+ Handle<JSGlobalObject>::cast(receiver), name());
+ DCHECK(cell->value()->IsTheHole());
+ transition_ = cell;
+ } else if (!transition->is_dictionary_map()) {
+ property_details_ = transition->GetLastDescriptorDetails();
+ has_property_ = true;
+ }
}
@@ -142,13 +261,40 @@
DCHECK_EQ(TRANSITION, state_);
Handle<JSObject> receiver = GetStoreTarget();
+ if (receiver->IsJSGlobalObject()) return;
holder_ = receiver;
- holder_map_ = transition_map_;
+ holder_map_ = transition_map();
JSObject::MigrateToMap(receiver, holder_map_);
ReloadPropertyInformation();
}
+void LookupIterator::Delete() {
+ Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
+ if (IsElement()) {
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
+ ElementsAccessor* accessor = object->GetElementsAccessor();
+ accessor->Delete(object, number_);
+ } else {
+ PropertyNormalizationMode mode = holder->map()->is_prototype_map()
+ ? KEEP_INOBJECT_PROPERTIES
+ : CLEAR_INOBJECT_PROPERTIES;
+
+ if (holder->HasFastProperties()) {
+ JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
+ "DeletingProperty");
+ holder_map_ = handle(holder->map(), isolate_);
+ ReloadPropertyInformation();
+ }
+ // TODO(verwaest): Get rid of the name_ argument.
+ JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
+ if (holder->IsJSObject()) {
+ JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
+ }
+ }
+}
+
+
void LookupIterator::TransitionToAccessorProperty(
AccessorComponent component, Handle<Object> accessor,
PropertyAttributes attributes) {
@@ -157,24 +303,19 @@
// handled via a trap. Adding properties to primitive values is not
// observable.
Handle<JSObject> receiver = GetStoreTarget();
- holder_ = receiver;
- holder_map_ =
- Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_),
- name_, component, accessor, attributes);
- JSObject::MigrateToMap(receiver, holder_map_);
- ReloadPropertyInformation();
+ if (!IsElement() && !receiver->map()->is_dictionary_map()) {
+ holder_ = receiver;
+ holder_map_ = Map::TransitionToAccessorProperty(
+ handle(receiver->map(), isolate_), name_, component, accessor,
+ attributes);
+ JSObject::MigrateToMap(receiver, holder_map_);
- if (!holder_map_->is_dictionary_map()) return;
+ ReloadPropertyInformation();
- // We have to deoptimize since accesses to data properties may have been
- // inlined without a corresponding map-check.
- if (holder_map_->IsGlobalObjectMap()) {
- Deoptimizer::DeoptimizeGlobalObject(*receiver);
+ if (!holder_map_->is_dictionary_map()) return;
}
- // Install the accessor into the dictionary-mode object.
- PropertyDetails details(attributes, CALLBACKS, 0);
Handle<AccessorPair> pair;
if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
pair = Handle<AccessorPair>::cast(GetAccessors());
@@ -186,12 +327,62 @@
pair->set(component, *accessor);
}
} else {
- pair = isolate()->factory()->NewAccessorPair();
+ pair = factory()->NewAccessorPair();
pair->set(component, *accessor);
}
- JSObject::SetNormalizedProperty(receiver, name_, pair, details);
- JSObject::ReoptimizeIfPrototype(receiver);
+ TransitionToAccessorPair(pair, attributes);
+
+#if VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ receiver->JSObjectVerify();
+ }
+#endif
+}
+
+
+void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
+ PropertyAttributes attributes) {
+ Handle<JSObject> receiver = GetStoreTarget();
+ holder_ = receiver;
+
+ PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0,
+ PropertyCellType::kMutable);
+
+ if (IsElement()) {
+ // TODO(verwaest): Move code into the element accessor.
+ Handle<SeededNumberDictionary> dictionary =
+ JSObject::NormalizeElements(receiver);
+
+ // We unconditionally pass used_as_prototype=false here because the call
+ // to RequireSlowElements takes care of the required IC clearing and
+ // we don't want to walk the heap twice.
+ dictionary =
+ SeededNumberDictionary::Set(dictionary, index_, pair, details, false);
+ receiver->RequireSlowElements(*dictionary);
+
+ if (receiver->HasSlowArgumentsElements()) {
+ FixedArray* parameter_map = FixedArray::cast(receiver->elements());
+ uint32_t length = parameter_map->length() - 2;
+ if (number_ < length) {
+ parameter_map->set(number_ + 2, heap()->the_hole_value());
+ }
+ FixedArray::cast(receiver->elements())->set(1, *dictionary);
+ } else {
+ receiver->set_elements(*dictionary);
+ }
+ } else {
+ PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
+ ? KEEP_INOBJECT_PROPERTIES
+ : CLEAR_INOBJECT_PROPERTIES;
+ // Normalize object to make this operation simple.
+ JSObject::NormalizeProperties(receiver, mode, 0,
+ "TransitionToAccessorPair");
+
+ JSObject::SetNormalizedProperty(receiver, name_, pair, details);
+ JSObject::ReoptimizeIfPrototype(receiver);
+ }
+
holder_map_ = handle(receiver->map(), isolate_);
ReloadPropertyInformation();
}
@@ -199,6 +390,10 @@
bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
+ return InternalHolderIsReceiverOrHiddenPrototype();
+}
+
+bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const {
// Optimization that only works if configuration_ is not mutable.
if (!check_prototype_chain()) return true;
DisallowHeapAllocation no_gc;
@@ -212,7 +407,7 @@
PrototypeIterator iter(isolate(), current,
PrototypeIterator::START_AT_RECEIVER);
do {
- if (JSReceiver::cast(iter.GetCurrent()) == holder) return true;
+ if (iter.GetCurrent<JSReceiver>() == holder) return true;
DCHECK(!current->IsJSProxy());
iter.Advance();
} while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
@@ -222,13 +417,27 @@
Handle<Object> LookupIterator::FetchValue() const {
Object* result = NULL;
- Handle<JSObject> holder = GetHolder<JSObject>();
- if (holder_map_->is_dictionary_map()) {
- result = holder->property_dictionary()->ValueAt(number_);
- if (holder_map_->IsGlobalObjectMap()) {
- result = PropertyCell::cast(result)->value();
+ if (IsElement()) {
+ Handle<JSObject> holder = GetHolder<JSObject>();
+ // TODO(verwaest): Optimize.
+ if (holder->IsStringObjectWithCharacterAt(index_)) {
+ Handle<JSValue> js_value = Handle<JSValue>::cast(holder);
+ Handle<String> string(String::cast(js_value->value()));
+ return factory()->LookupSingleCharacterStringFromCode(
+ String::Flatten(string)->Get(index_));
}
- } else if (property_details_.type() == v8::internal::FIELD) {
+
+ ElementsAccessor* accessor = holder->GetElementsAccessor();
+ return accessor->Get(handle(holder->elements()), number_);
+ } else if (holder_map_->IsJSGlobalObjectMap()) {
+ Handle<JSObject> holder = GetHolder<JSObject>();
+ result = holder->global_dictionary()->ValueAt(number_);
+ DCHECK(result->IsPropertyCell());
+ result = PropertyCell::cast(result)->value();
+ } else if (holder_map_->is_dictionary_map()) {
+ result = holder_->property_dictionary()->ValueAt(number_);
+ } else if (property_details_.type() == v8::internal::DATA) {
+ Handle<JSObject> holder = GetHolder<JSObject>();
FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_);
return JSObject::FastPropertyAt(holder, property_details_.representation(),
field_index);
@@ -239,10 +448,19 @@
}
+int LookupIterator::GetAccessorIndex() const {
+ DCHECK(has_property_);
+ DCHECK(!holder_map_->is_dictionary_map());
+ DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type());
+ return descriptor_number();
+}
+
+
int LookupIterator::GetConstantIndex() const {
DCHECK(has_property_);
DCHECK(!holder_map_->is_dictionary_map());
- DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
+ DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
+ DCHECK(!IsElement());
return descriptor_number();
}
@@ -250,7 +468,8 @@
FieldIndex LookupIterator::GetFieldIndex() const {
DCHECK(has_property_);
DCHECK(!holder_map_->is_dictionary_map());
- DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+ DCHECK_EQ(v8::internal::DATA, property_details_.type());
+ DCHECK(!IsElement());
int index =
holder_map_->instance_descriptors()->GetFieldIndex(descriptor_number());
bool is_double = representation().IsDouble();
@@ -261,7 +480,7 @@
Handle<HeapType> LookupIterator::GetFieldType() const {
DCHECK(has_property_);
DCHECK(!holder_map_->is_dictionary_map());
- DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+ DCHECK_EQ(v8::internal::DATA, property_details_.type());
return handle(
holder_map_->instance_descriptors()->GetFieldType(descriptor_number()),
isolate_);
@@ -269,10 +488,12 @@
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
+ DCHECK(!IsElement());
Handle<JSObject> holder = GetHolder<JSObject>();
- Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
- Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
- return Handle<PropertyCell>(PropertyCell::cast(value));
+ Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
+ Object* value = global->global_dictionary()->ValueAt(dictionary_entry());
+ DCHECK(value->IsPropertyCell());
+ return handle(PropertyCell::cast(value));
}
@@ -289,46 +510,50 @@
}
-Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
+void LookupIterator::WriteDataValue(Handle<Object> value) {
DCHECK_EQ(DATA, state_);
- Handle<JSObject> holder = GetHolder<JSObject>();
- if (holder_map_->is_dictionary_map()) {
+ Handle<JSReceiver> holder = GetHolder<JSReceiver>();
+ if (IsElement()) {
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
+ ElementsAccessor* accessor = object->GetElementsAccessor();
+ accessor->Set(object->elements(), number_, *value);
+ } else if (holder->IsJSGlobalObject()) {
+ Handle<GlobalDictionary> property_dictionary =
+ handle(JSObject::cast(*holder)->global_dictionary());
+ PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value,
+ property_details_);
+ } else if (holder_map_->is_dictionary_map()) {
NameDictionary* property_dictionary = holder->property_dictionary();
- if (holder->IsGlobalObject()) {
- Handle<PropertyCell> cell(
- PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
- value = PropertyCell::SetValueInferType(cell, value);
- } else {
- property_dictionary->ValueAtPut(dictionary_entry(), *value);
- }
- } else if (property_details_.type() == v8::internal::FIELD) {
- holder->WriteToField(descriptor_number(), *value);
+ property_dictionary->ValueAtPut(dictionary_entry(), *value);
+ } else if (property_details_.type() == v8::internal::DATA) {
+ JSObject::cast(*holder)->WriteToField(descriptor_number(), *value);
} else {
- DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
+ DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
}
- return value;
}
-bool LookupIterator::IsSpecialNumericIndex() const {
- if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
+bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
+ DCHECK(exotic_index_state_ != ExoticIndexState::kNotExotic);
+ if (exotic_index_state_ == ExoticIndexState::kExotic) return true;
+ if (!InternalHolderIsReceiverOrHiddenPrototype()) {
+ exotic_index_state_ = ExoticIndexState::kNotExotic;
+ return false;
+ }
+ DCHECK(exotic_index_state_ == ExoticIndexState::kUninitialized);
+ bool result = false;
+ // Compute and cache result.
+ if (IsElement()) {
+ result = index_ >= JSTypedArray::cast(holder)->length_value();
+ } else if (name()->IsString()) {
Handle<String> name_string = Handle<String>::cast(name());
- if (name_string->length() > 0) {
- double d =
- StringToDouble(isolate()->unicode_cache(), name_string, NO_FLAGS);
- if (!std::isnan(d)) {
- if (String::Equals(isolate()->factory()->minus_zero_string(),
- name_string))
- return true;
-
- Factory* factory = isolate()->factory();
- Handle<Object> num = factory->NewNumber(d);
- Handle<String> roundtrip_string = factory->NumberToString(num);
- if (String::Equals(name_string, roundtrip_string)) return true;
- }
+ if (name_string->length() != 0) {
+ result = IsSpecialIndex(isolate_->unicode_cache(), *name_string);
}
}
- return false;
+ exotic_index_state_ =
+ result ? ExoticIndexState::kExotic : ExoticIndexState::kNotExotic;
+ return result;
}
@@ -336,4 +561,160 @@
if (name_->IsUniqueName()) return;
name_ = factory()->InternalizeString(Handle<String>::cast(name_));
}
-} } // namespace v8::internal
+
+
+bool LookupIterator::HasInterceptor(Map* map) const {
+ if (IsElement()) return map->has_indexed_interceptor();
+ return map->has_named_interceptor();
+}
+
+
+bool LookupIterator::SkipInterceptor(JSObject* holder) {
+ auto info = GetInterceptor(holder);
+ // TODO(dcarney): check for symbol/can_intercept_symbols here as well.
+ if (info->non_masking()) {
+ switch (interceptor_state_) {
+ case InterceptorState::kUninitialized:
+ interceptor_state_ = InterceptorState::kSkipNonMasking;
+ // Fall through.
+ case InterceptorState::kSkipNonMasking:
+ return true;
+ case InterceptorState::kProcessNonMasking:
+ return false;
+ }
+ }
+ return interceptor_state_ == InterceptorState::kProcessNonMasking;
+}
+
+
+JSReceiver* LookupIterator::NextHolder(Map* map) {
+ DisallowHeapAllocation no_gc;
+ if (!map->prototype()->IsJSReceiver()) return NULL;
+
+ JSReceiver* next = JSReceiver::cast(map->prototype());
+ DCHECK(!next->map()->IsJSGlobalObjectMap() ||
+ next->map()->is_hidden_prototype());
+
+ if (!check_prototype_chain() &&
+ !(check_hidden() && next->map()->is_hidden_prototype()) &&
+ // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
+ // when not checking other hidden prototypes.
+ !map->IsJSGlobalProxyMap()) {
+ return NULL;
+ }
+
+ return next;
+}
+
+
+LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
+ JSReceiver* const holder) {
+ STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
+ DisallowHeapAllocation no_gc;
+ if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
+ return LookupNonMaskingInterceptorInHolder(map, holder);
+ }
+ switch (state_) {
+ case NOT_FOUND:
+ if (map->IsJSProxyMap()) {
+ // Do not leak private property names.
+ if (IsElement() || !name_->IsPrivate()) return JSPROXY;
+ }
+ if (map->is_access_check_needed() &&
+ (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) {
+ return ACCESS_CHECK;
+ }
+ // Fall through.
+ case ACCESS_CHECK:
+ if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
+ holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) {
+ return INTEGER_INDEXED_EXOTIC;
+ }
+ if (check_interceptor() && HasInterceptor(map) &&
+ !SkipInterceptor(JSObject::cast(holder))) {
+ // Do not leak private property names.
+ if (!name_.is_null() && name_->IsPrivate()) return NOT_FOUND;
+ return INTERCEPTOR;
+ }
+ // Fall through.
+ case INTERCEPTOR:
+ if (IsElement()) {
+ // TODO(verwaest): Optimize.
+ if (holder->IsStringObjectWithCharacterAt(index_)) {
+ PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
+ property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0,
+ PropertyCellType::kNoCell);
+ } else {
+ JSObject* js_object = JSObject::cast(holder);
+ if (js_object->elements() == isolate()->heap()->empty_fixed_array()) {
+ return NOT_FOUND;
+ }
+
+ ElementsAccessor* accessor = js_object->GetElementsAccessor();
+ FixedArrayBase* backing_store = js_object->elements();
+ number_ =
+ accessor->GetEntryForIndex(js_object, backing_store, index_);
+ if (number_ == kMaxUInt32) return NOT_FOUND;
+ property_details_ = accessor->GetDetails(backing_store, number_);
+ }
+ } else if (!map->is_dictionary_map()) {
+ DescriptorArray* descriptors = map->instance_descriptors();
+ int number = descriptors->SearchWithCache(*name_, map);
+ if (number == DescriptorArray::kNotFound) return NOT_FOUND;
+ number_ = static_cast<uint32_t>(number);
+ property_details_ = descriptors->GetDetails(number_);
+ } else if (map->IsJSGlobalObjectMap()) {
+ GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
+ int number = dict->FindEntry(name_);
+ if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
+ number_ = static_cast<uint32_t>(number);
+ DCHECK(dict->ValueAt(number_)->IsPropertyCell());
+ PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
+ if (cell->value()->IsTheHole()) return NOT_FOUND;
+ property_details_ = cell->property_details();
+ } else {
+ NameDictionary* dict = holder->property_dictionary();
+ int number = dict->FindEntry(name_);
+ if (number == NameDictionary::kNotFound) return NOT_FOUND;
+ number_ = static_cast<uint32_t>(number);
+ property_details_ = dict->DetailsAt(number_);
+ }
+ has_property_ = true;
+ switch (property_details_.kind()) {
+ case v8::internal::kData:
+ return DATA;
+ case v8::internal::kAccessor:
+ return ACCESSOR;
+ }
+ case ACCESSOR:
+ case DATA:
+ return NOT_FOUND;
+ case INTEGER_INDEXED_EXOTIC:
+ case JSPROXY:
+ case TRANSITION:
+ UNREACHABLE();
+ }
+ UNREACHABLE();
+ return state_;
+}
+
+
+LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
+ Map* const map, JSReceiver* const holder) {
+ switch (state_) {
+ case NOT_FOUND:
+ if (check_interceptor() && HasInterceptor(map) &&
+ !SkipInterceptor(JSObject::cast(holder))) {
+ return INTERCEPTOR;
+ }
+ // Fall through.
+ default:
+ return NOT_FOUND;
+ }
+ UNREACHABLE();
+ return state_;
+}
+
+} // namespace internal
+} // namespace v8