diff options
Diffstat (limited to 'deps/v8/src/ic/ic.cc')
-rw-r--r-- | deps/v8/src/ic/ic.cc | 491 |
1 files changed, 279 insertions, 212 deletions
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index c607679a2a..b050513adb 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -88,7 +88,7 @@ const char* GetModifier(KeyedAccessStoreMode mode) { void IC::TraceIC(const char* type, Handle<Object> name) { if (FLAG_ic_stats) { if (AddressIsDeoptimizedCode()) return; - State new_state = nexus()->StateFromFeedback(); + State new_state = nexus()->ic_state(); TraceIC(type, name, state(), new_state); } } @@ -200,7 +200,7 @@ IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot, } pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind()); - state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.StateFromFeedback(); + state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.ic_state(); old_state_ = state_; } @@ -216,7 +216,7 @@ JSFunction IC::GetHostFunction() const { return frame->function(); } -static void LookupForRead(Isolate* isolate, LookupIterator* it) { +static void LookupForRead(LookupIterator* it, bool is_has_property) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: @@ -227,7 +227,13 @@ static void LookupForRead(Isolate* isolate, LookupIterator* it) { case LookupIterator::INTERCEPTOR: { // If there is a getter, return; otherwise loop to perform the lookup. Handle<JSObject> holder = it->GetHolder<JSObject>(); - if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) { + if (!holder->GetNamedInterceptor()->getter()->IsUndefined( + it->isolate())) { + return; + } + if (is_has_property && + !holder->GetNamedInterceptor()->query()->IsUndefined( + it->isolate())) { return; } break; @@ -277,14 +283,13 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) { if (is_keyed()) { // Determine whether the failure is due to a name failure. if (!name->IsName()) return false; - Name stub_name = nexus()->FindFirstName(); + Name stub_name = nexus()->GetName(); if (*name != stub_name) return false; } return true; } - void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { if (state() == NO_FEEDBACK) return; update_receiver_map(receiver); @@ -306,7 +311,6 @@ MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object, THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object); } - MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) { HandleScope scope(isolate()); THROW_NEW_ERROR( @@ -429,7 +433,8 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. - if (object->IsNullOrUndefined(isolate())) { + if (IsAnyHas() ? !object->IsJSReceiver() + : object->IsNullOrUndefined(isolate())) { if (use_ic && state() != PREMONOMORPHIC) { // Ensure the IC state progresses. TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); @@ -441,7 +446,9 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) { return Runtime::ThrowIteratorError(isolate(), object); } - return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name); + return TypeError(IsAnyHas() ? MessageTemplate::kInvalidInOperatorUse + : MessageTemplate::kNonObjectPropertyLoad, + object, name); } if (MigrateDeprecated(object)) use_ic = false; @@ -450,9 +457,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate()); update_receiver_map(object); } - // Named lookup in the object. + LookupIterator it(isolate(), object, name); - LookupForRead(isolate(), &it); + + // Named lookup in the object. + LookupForRead(&it, IsAnyHas()); if (name->IsPrivate()) { if (name->IsPrivateName() && !it.IsFound()) { @@ -473,6 +482,14 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { // Update inline cache and stub cache. if (use_ic) UpdateCaches(&it); + if (IsAnyHas()) { + // Named lookup in the object. + Maybe<bool> maybe = JSReceiver::HasProperty(&it); + if (maybe.IsNothing()) return MaybeHandle<Object>(); + return maybe.FromJust() ? ReadOnlyRoots(isolate()).true_value_handle() + : ReadOnlyRoots(isolate()).false_value_handle(); + } + // Get the property. Handle<Object> result; @@ -498,7 +515,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { global->native_context()->script_context_table(), isolate()); ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name, + if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name, &lookup_result)) { Handle<Context> script_context = ScriptContextTable::GetContext( isolate(), script_contexts, lookup_result.context_index); @@ -514,8 +531,9 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic; if (use_ic) { - if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index, - lookup_result.slot_index)) { + if (nexus()->ConfigureLexicalVarMode( + lookup_result.context_index, lookup_result.slot_index, + lookup_result.mode == VariableMode::kConst)) { TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField); } else { // Given combination of indices can't be encoded, so use slow stub. @@ -546,7 +564,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler) { DCHECK(IsHandler(*handler)); if (is_keyed() && state() != RECOMPUTE_HANDLER) { - if (nexus()->FindFirstName() != *name) return false; + if (nexus()->GetName() != *name) return false; } Handle<Map> map = receiver_map(); MapHandles maps; @@ -586,7 +604,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, int number_of_valid_maps = number_of_maps - deprecated_maps - (handler_to_overwrite != -1); - if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false; + if (number_of_valid_maps >= FLAG_max_polymorphic_map_count) return false; if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { return false; } @@ -595,7 +613,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, if (number_of_valid_maps == 1) { ConfigureVectorState(name, receiver_map(), handler); } else { - if (is_keyed() && nexus()->FindFirstName() != *name) return false; + if (is_keyed() && nexus()->GetName() != *name) return false; if (handler_to_overwrite >= 0) { handlers[handler_to_overwrite] = handler; if (!map.is_identical_to(maps.at(handler_to_overwrite))) { @@ -618,7 +636,6 @@ void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler, ConfigureVectorState(name, receiver_map(), handler); } - void IC::CopyICToMegamorphicCache(Handle<Name> name) { MapHandles maps; MaybeObjectHandles handlers; @@ -653,7 +670,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) { DCHECK(IsHandler(*handler)); // Currently only load and store ICs support non-code handlers. - DCHECK(IsAnyLoad() || IsAnyStore()); + DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas()); switch (state()) { case NO_FEEDBACK: break; @@ -727,6 +744,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { } StubCache* IC::stub_cache() { + DCHECK(!IsAnyHas()); if (IsAnyLoad()) { return isolate()->load_stub_cache(); } else { @@ -737,13 +755,15 @@ StubCache* IC::stub_cache() { void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, const MaybeObjectHandle& handler) { - stub_cache()->Set(*name, *map, *handler); + if (!IsAnyHas()) { + stub_cache()->Set(*name, *map, *handler); + } } void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state()); if (V8_LIKELY(!FLAG_runtime_stats)) return; - if (IsAnyLoad()) { + if (IsAnyLoad() || IsAnyHas()) { TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor); } else { DCHECK(IsAnyStore()); @@ -754,22 +774,29 @@ void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { Handle<Object> receiver = lookup->GetReceiver(); ReadOnlyRoots roots(isolate()); - if (receiver->IsString() && *lookup->name() == roots.length_string()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength); - return BUILTIN_CODE(isolate(), LoadIC_StringLength); - } - if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength); - return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength); - } + // `in` cannot be called on strings, and will always return true for string + // wrapper length and function prototypes. The latter two cases are given + // LoadHandler::LoadNativeDataProperty below. + if (!IsAnyHas()) { + if (receiver->IsString() && *lookup->name() == roots.length_string()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength); + return BUILTIN_CODE(isolate(), LoadIC_StringLength); + } + + if (receiver->IsStringWrapper() && + *lookup->name() == roots.length_string()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength); + return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength); + } - // Use specialized code for getting prototype of functions. - if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() && - !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) { - Handle<Code> stub; - TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub); - return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype); + // Use specialized code for getting prototype of functions. + if (receiver->IsJSFunction() && + *lookup->name() == roots.prototype_string() && + !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub); + return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype); + } } Handle<Map> map = receiver_map(); @@ -1081,24 +1108,66 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver, } } +namespace { + +bool AllowConvertHoleElementToUndefined(Isolate* isolate, + Handle<Map> receiver_map) { + if (receiver_map->IsJSTypedArrayMap()) { + // For JSTypedArray we never lookup elements in the prototype chain. + return true; + } + + // For other {receiver}s we need to check the "no elements" protector. + if (isolate->IsNoElementsProtectorIntact()) { + if (receiver_map->IsStringMap()) { + return true; + } + if (receiver_map->IsJSObjectMap()) { + // For other JSObjects (including JSArrays) we can only continue if + // the {receiver}s prototype is either the initial Object.prototype + // or the initial Array.prototype, which are both guarded by the + // "no elements" protector checked above. + Handle<Object> receiver_prototype(receiver_map->prototype(), isolate); + + if (isolate->IsInAnyContext(*receiver_prototype, + Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || + isolate->IsInAnyContext(*receiver_prototype, + Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) { + return true; + } + } + } + + return false; +} +} // namespace + Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map, KeyedAccessLoadMode load_mode) { + // Has a getter interceptor, or is any has and has a query interceptor. if (receiver_map->has_indexed_interceptor() && - !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined( - isolate()) && + (!receiver_map->GetIndexedInterceptor()->getter()->IsUndefined( + isolate()) || + (IsAnyHas() && + !receiver_map->GetIndexedInterceptor()->query()->IsUndefined( + isolate()))) && !receiver_map->GetIndexedInterceptor()->non_masking()) { // TODO(jgruber): Update counter name. TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); - return BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); + return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC) + : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); } + InstanceType instance_type = receiver_map->instance_type(); if (instance_type < FIRST_NONSTRING_TYPE) { TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH); + if (IsAnyHas()) return BUILTIN_CODE(isolate(), HasIC_Slow); return LoadHandler::LoadIndexedString(isolate(), load_mode); } if (instance_type < FIRST_JS_RECEIVER_TYPE) { TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub); - return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow); + return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow) + : BUILTIN_CODE(isolate(), KeyedLoadIC_Slow); } if (instance_type == JS_PROXY_TYPE) { return LoadHandler::LoadProxy(isolate()); @@ -1108,7 +1177,8 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map, if (IsSloppyArgumentsElementsKind(elements_kind)) { // TODO(jgruber): Update counter name. TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub); - return BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments); + return IsAnyHas() ? BUILTIN_CODE(isolate(), KeyedHasIC_SloppyArguments) + : BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments); } bool is_js_array = instance_type == JS_ARRAY_TYPE; if (elements_kind == DICTIONARY_ELEMENTS) { @@ -1118,11 +1188,10 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map, } DCHECK(IsFastElementsKind(elements_kind) || IsFixedTypedArrayElementsKind(elements_kind)); - // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind). bool convert_hole_to_undefined = - is_js_array && elements_kind == HOLEY_ELEMENTS && - *receiver_map == - isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind); + (elements_kind == HOLEY_SMI_ELEMENTS || + elements_kind == HOLEY_ELEMENTS) && + AllowConvertHoleElementToUndefined(isolate(), receiver_map); TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH); return LoadHandler::LoadElement(isolate(), elements_kind, convert_hole_to_undefined, is_js_array, @@ -1198,46 +1267,39 @@ bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) { KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver, uint32_t index) { if (IsOutOfBoundsAccess(receiver, index)) { - if (receiver->IsJSTypedArray()) { - // For JSTypedArray we never lookup elements in the prototype chain. + DCHECK(receiver->IsHeapObject()); + Handle<Map> receiver_map(Handle<HeapObject>::cast(receiver)->map(), + isolate); + if (AllowConvertHoleElementToUndefined(isolate, receiver_map)) { return LOAD_IGNORE_OUT_OF_BOUNDS; } - - // For other {receiver}s we need to check the "no elements" protector. - if (isolate->IsNoElementsProtectorIntact()) { - if (receiver->IsString()) { - // ToObject(receiver) will have the initial String.prototype. - return LOAD_IGNORE_OUT_OF_BOUNDS; - } - if (receiver->IsJSObject()) { - // For other JSObjects (including JSArrays) we can only continue if - // the {receiver}s prototype is either the initial Object.prototype - // or the initial Array.prototype, which are both guarded by the - // "no elements" protector checked above. - Handle<Object> receiver_prototype( - JSObject::cast(*receiver)->map()->prototype(), isolate); - if (isolate->IsInAnyContext(*receiver_prototype, - Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || - isolate->IsInAnyContext(*receiver_prototype, - Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) { - return LOAD_IGNORE_OUT_OF_BOUNDS; - } - } - } } return STANDARD_LOAD; } } // namespace -MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, - Handle<Object> key) { - if (MigrateDeprecated(object)) { - Handle<Object> result; +MaybeHandle<Object> KeyedLoadIC::RuntimeLoad(Handle<Object> object, + Handle<Object> key) { + Handle<Object> result; + + if (IsKeyedLoadIC()) { ASSIGN_RETURN_ON_EXCEPTION( isolate(), result, Runtime::GetObjectProperty(isolate(), object, key), Object); - return result; + } else { + DCHECK(IsKeyedHasIC()); + ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, + Runtime::HasProperty(isolate(), object, key), + Object); + } + return result; +} + +MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, + Handle<Object> key) { + if (MigrateDeprecated(object)) { + return RuntimeLoad(object, key); } Handle<Object> load_handle; @@ -1268,11 +1330,7 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, if (!load_handle.is_null()) return load_handle; - Handle<Object> result; - ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, - Runtime::GetObjectProperty(isolate(), object, key), - Object); - return result; + return RuntimeLoad(object, key); } bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, @@ -1357,7 +1415,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name, global->native_context()->script_context_table(), isolate()); ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name, + if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name, &lookup_result)) { Handle<Context> script_context = ScriptContextTable::GetContext( isolate(), script_contexts, lookup_result.context_index); @@ -1376,8 +1434,9 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name, bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic; if (use_ic) { - if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index, - lookup_result.slot_index)) { + if (nexus()->ConfigureLexicalVarMode( + lookup_result.context_index, lookup_result.slot_index, + lookup_result.mode == VariableMode::kConst)) { TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField); } else { // Given combination of indices can't be encoded, so use slow stub. @@ -1402,8 +1461,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, if (MigrateDeprecated(object)) { Handle<Object> result; ASSIGN_RETURN_ON_EXCEPTION( - isolate(), result, - Object::SetProperty(isolate(), object, name, value, language_mode()), + isolate(), result, Object::SetProperty(isolate(), object, name, value), Object); return result; } @@ -1443,8 +1501,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, } if (use_ic) UpdateCaches(&it, value, store_origin); - MAYBE_RETURN_NULL( - Object::SetProperty(&it, value, language_mode(), store_origin)); + MAYBE_RETURN_NULL(Object::SetProperty(&it, value, store_origin)); return value; } @@ -1473,6 +1530,24 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, } handler = ComputeHandler(lookup); } else { + if (state() == UNINITIALIZED && IsStoreGlobalIC() && + lookup->state() == LookupIterator::INTERCEPTOR) { + InterceptorInfo info = + lookup->GetHolder<JSObject>()->GetNamedInterceptor(); + if (!lookup->HolderIsReceiverOrHiddenPrototype() && + !info->getter()->IsUndefined(isolate())) { + // Utilize premonomorphic state for global store ics that run into + // an interceptor because the property doesn't exist yet. + // After we actually set the property, we'll have more information. + // Premonomorphism gives us a chance to find more information the + // second time. + TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_Premonomorphic); + ConfigureVectorState(receiver_map()); + TraceIC("StoreGlobalIC", lookup->name()); + return; + } + } + set_slow_stub_reason("LookupForWrite said 'false'"); // TODO(marja): change slow_stub to return MaybeObjectHandle. handler = MaybeObjectHandle(slow_stub()); @@ -1814,7 +1889,6 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, } } - Handle<Map> KeyedStoreIC::ComputeTransitionedMap( Handle<Map> map, KeyedAccessStoreMode store_mode) { switch (store_mode) { @@ -1952,7 +2026,6 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( } } - static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, uint32_t index, Handle<Object> value) { bool oob_access = IsOutOfBoundsAccess(receiver, index); @@ -1997,7 +2070,6 @@ static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, } } - MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, Handle<Object> key, Handle<Object> value) { @@ -2008,7 +2080,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, ASSIGN_RETURN_ON_EXCEPTION( isolate(), result, Runtime::SetObjectProperty(isolate(), object, key, value, - language_mode(), StoreOrigin::kMaybeKeyed), + StoreOrigin::kMaybeKeyed), Object); return result; } @@ -2083,7 +2155,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, Handle<JSArray>::cast(object)->elements()->IsCowArray(); ASSIGN_RETURN_ON_EXCEPTION( isolate(), store_handle, - Runtime::SetObjectProperty(isolate(), object, key, value, language_mode(), + Runtime::SetObjectProperty(isolate(), object, key, value, StoreOrigin::kMaybeKeyed), Object); @@ -2129,8 +2201,8 @@ void StoreOwnElement(Isolate* isolate, Handle<JSArray> array, isolate, array, index, &success, LookupIterator::OWN); DCHECK(success); - CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE, - kThrowOnError) + CHECK(JSObject::DefineOwnPropertyIgnoreAttributes( + &it, value, NONE, Just(ShouldThrow::kThrowOnError)) .FromJust()); } } // namespace @@ -2176,20 +2248,6 @@ void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index, // Static IC stub generators. // // -namespace { - -// TODO(8580): Compute the language mode lazily to avoid the expensive -// computation of language mode here. -LanguageMode GetLanguageMode(Handle<FeedbackVector> vector, Context context) { - LanguageMode language_mode = vector->shared_function_info()->language_mode(); - if (context->scope_info()->language_mode() > language_mode) { - return context->scope_info()->language_mode(); - } - return language_mode; -} - -} // namespace - RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(4, args.length()); @@ -2274,7 +2332,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { native_context->script_context_table(), isolate); ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(isolate, script_contexts, name, + if (ScriptContextTable::Lookup(isolate, *script_contexts, *name, &lookup_result)) { Handle<Context> script_context = ScriptContextTable::GetContext( isolate, script_contexts, lookup_result.context_index); @@ -2334,51 +2392,27 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); Handle<Smi> slot = args.at<Smi>(1); - Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); + Handle<HeapObject> maybe_vector = args.at<HeapObject>(2); Handle<Object> receiver = args.at(3); Handle<Name> key = args.at<Name>(4); FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); - FeedbackSlotKind kind = vector->GetKind(vector_slot); - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); - if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) { - StoreIC ic(isolate, vector, vector_slot, kind, language_mode); - ic.UpdateState(receiver, key); - RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); - } else if (IsStoreGlobalICKind(kind)) { - DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver); - receiver = isolate->global_object(); - StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode); - ic.UpdateState(receiver, key); - RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value)); - } else { - DCHECK(IsKeyedStoreICKind(kind)); - KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode); - ic.UpdateState(receiver, key); - RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); + + // When there is no feedback vector it is OK to use the StoreNamedStrict as + // the feedback slot kind. We only need if it is StoreOwnICKind when + // installing the handler for storing const properties. This will happen only + // when feedback vector is available. + FeedbackSlotKind kind = FeedbackSlotKind::kStoreNamedStrict; + Handle<FeedbackVector> vector = Handle<FeedbackVector>(); + if (!maybe_vector->IsUndefined()) { + DCHECK(maybe_vector->IsFeedbackVector()); + vector = Handle<FeedbackVector>::cast(maybe_vector); + kind = vector->GetKind(vector_slot); } -} -RUNTIME_FUNCTION(Runtime_StoreICNoFeedback_Miss) { - HandleScope scope(isolate); - DCHECK_EQ(5, args.length()); - Handle<Object> value = args.at(0); - Handle<Object> receiver = args.at(1); - Handle<Name> key = args.at<Name>(2); - CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); - CONVERT_INT32_ARG_CHECKED(is_own_property_value, 4); - NamedPropertyType property_type = - static_cast<NamedPropertyType>(is_own_property_value); - - FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict) - ? FeedbackSlotKind::kStoreNamedStrict - : FeedbackSlotKind::kStoreNamedSloppy; - if (property_type == NamedPropertyType::kOwn) { - language_mode = LanguageMode::kStrict; - kind = FeedbackSlotKind::kStoreOwnNamed; - } - StoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind, - language_mode); + DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind)); + StoreIC ic(isolate, vector, vector_slot, kind); + ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } @@ -2393,8 +2427,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) { FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); FeedbackSlotKind kind = vector->GetKind(vector_slot); - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); - StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode); + StoreGlobalIC ic(isolate, vector, vector_slot, kind); Handle<JSGlobalObject> global = isolate->global_object(); ic.UpdateState(global, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value)); @@ -2402,31 +2435,30 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) { RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) { HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); + DCHECK_EQ(2, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); Handle<Name> key = args.at<Name>(1); - CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); - FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict) - ? FeedbackSlotKind::kStoreGlobalStrict - : FeedbackSlotKind::kStoreGlobalSloppy; - StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind, - language_mode); + // TODO(mythria): Replace StoreGlobalStrict/Sloppy with StoreNamed. + StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), + FeedbackSlotKind::kStoreGlobalStrict); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value)); } +// TODO(mythria): Remove Feedback vector and slot. Since they are not used apart +// from the DCHECK. RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); - Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); CONVERT_ARG_HANDLE_CHECKED(String, name, 4); #ifdef DEBUG { Handle<Smi> slot = args.at<Smi>(1); + Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); FeedbackSlotKind slot_kind = vector->GetKind(vector_slot); DCHECK(IsStoreGlobalICKind(slot_kind)); @@ -2441,7 +2473,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { native_context->script_context_table(), isolate); ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(isolate, script_contexts, name, + if (ScriptContextTable::Lookup(isolate, *script_contexts, *name, &lookup_result)) { Handle<Context> script_context = ScriptContextTable::GetContext( isolate, script_contexts, lookup_result.context_index); @@ -2462,11 +2494,9 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { return *value; } - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); RETURN_RESULT_OR_FAILURE( - isolate, - Runtime::SetObjectProperty(isolate, global, name, value, language_mode, - StoreOrigin::kMaybeKeyed)); + isolate, Runtime::SetObjectProperty(isolate, global, name, value, + StoreOrigin::kMaybeKeyed)); } RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { @@ -2475,18 +2505,29 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); Handle<Smi> slot = args.at<Smi>(1); - Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); + Handle<HeapObject> maybe_vector = args.at<HeapObject>(2); Handle<Object> receiver = args.at(3); Handle<Object> key = args.at(4); - - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); - FeedbackSlotKind kind = vector->GetKind(vector_slot); + + // When the feedback vector is not valid the slot can only be of type + // StoreKeyed. Storing in array literals falls back to + // StoreInArrayLiterIC_Miss. This function is also used from store handlers + // installed in feedback vectors. In such cases, we need to get the kind from + // feedback vector slot since the handlers are used for both for StoreKeyed + // and StoreInArrayLiteral kinds. + FeedbackSlotKind kind = FeedbackSlotKind::kStoreKeyedStrict; + Handle<FeedbackVector> vector = Handle<FeedbackVector>(); + if (!maybe_vector->IsUndefined()) { + DCHECK(maybe_vector->IsFeedbackVector()); + vector = Handle<FeedbackVector>::cast(maybe_vector); + kind = vector->GetKind(vector_slot); + } // The elements store stubs miss into this function, but they are shared by // different ICs. if (IsKeyedStoreICKind(kind)) { - KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode); + KeyedStoreIC ic(isolate, vector, vector_slot, kind); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } else { @@ -2500,23 +2541,6 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { } } -RUNTIME_FUNCTION(Runtime_KeyedStoreICNoFeedback_Miss) { - HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - // Runtime functions don't follow the IC's calling convention. - Handle<Object> value = args.at(0); - Handle<Object> receiver = args.at(1); - Handle<Object> key = args.at(2); - CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); - - FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict) - ? FeedbackSlotKind::kStoreKeyedStrict - : FeedbackSlotKind::kStoreKeyedSloppy; - KeyedStoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind, - language_mode); - RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); -} - RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); @@ -2541,17 +2565,14 @@ RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) { RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { HandleScope scope(isolate); - DCHECK_EQ(5, args.length()); + DCHECK_EQ(3, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<Object> value = args.at(0); - Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); - Handle<Object> object = args.at(3); - Handle<Object> key = args.at(4); - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); + Handle<Object> object = args.at(1); + Handle<Object> key = args.at(2); RETURN_RESULT_OR_FAILURE( - isolate, - Runtime::SetObjectProperty(isolate, object, key, value, language_mode, - StoreOrigin::kMaybeKeyed)); + isolate, Runtime::SetObjectProperty(isolate, object, key, value, + StoreOrigin::kMaybeKeyed)); } RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) { @@ -2588,11 +2609,9 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { return *value; } else { DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind)); - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); RETURN_RESULT_OR_FAILURE( - isolate, - Runtime::SetObjectProperty(isolate, object, key, value, language_mode, - StoreOrigin::kMaybeKeyed)); + isolate, Runtime::SetObjectProperty(isolate, object, key, value, + StoreOrigin::kMaybeKeyed)); } } @@ -2734,22 +2753,18 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { Handle<AccessorInfo> info = args.at<AccessorInfo>(2); Handle<Name> name = args.at<Name>(3); Handle<Object> value = args.at(4); - CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5); HandleScope scope(isolate); if (V8_UNLIKELY(FLAG_runtime_stats)) { RETURN_RESULT_OR_FAILURE( - isolate, - Runtime::SetObjectProperty(isolate, receiver, name, value, - language_mode, StoreOrigin::kMaybeKeyed)); + isolate, Runtime::SetObjectProperty(isolate, receiver, name, value, + StoreOrigin::kMaybeKeyed)); } DCHECK(info->IsCompatibleReceiver(*receiver)); - ShouldThrow should_throw = - is_sloppy(language_mode) ? kDontThrow : kThrowOnError; PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder, - should_throw); + Nothing<ShouldThrow>()); arguments.CallAccessorSetter(info, name, value); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return *value; @@ -2765,7 +2780,7 @@ RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) { DCHECK(info->IsCompatibleReceiver(*receiver)); PropertyCallbackArguments custom_args(isolate, info->data(), *receiver, - *holder, kThrowOnError); + *holder, Just(kThrowOnError)); Handle<Object> result = custom_args.CallAccessorGetter(info, name); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value(); @@ -2813,7 +2828,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate); PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, - *holder, kDontThrow); + *holder, Just(kDontThrow)); Handle<Object> result = arguments.CallNamedGetter(interceptor, name); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); @@ -2848,7 +2863,6 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name())); } - RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); @@ -2859,7 +2873,6 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { Handle<JSObject> receiver = args.at<JSObject>(3); Handle<Name> name = args.at<Name>(4); FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); - LanguageMode language_mode = GetLanguageMode(vector, isolate->context()); // TODO(ishell): Cache interceptor_holder in the store handler like we do // for LoadHandler::kInterceptor case. @@ -2876,7 +2889,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { DCHECK(!interceptor->non_masking()); PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, - *receiver, kDontThrow); + *receiver, Just(kDontThrow)); Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); @@ -2892,13 +2905,11 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); it.Next(); - MAYBE_RETURN( - Object::SetProperty(&it, value, language_mode, StoreOrigin::kNamed), - ReadOnlyRoots(isolate).exception()); + MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed), + ReadOnlyRoots(isolate).exception()); return *value; } - RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) { // TODO(verwaest): This should probably get the holder and receiver as input. HandleScope scope(isolate); @@ -2909,7 +2920,7 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) { Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(), isolate); PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, - *receiver, kDontThrow); + *receiver, Just(kDontThrow)); Handle<Object> result = arguments.CallIndexedGetter(interceptor, index); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); @@ -2924,5 +2935,61 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) { return *result; } + +RUNTIME_FUNCTION(Runtime_KeyedHasIC_Miss) { + HandleScope scope(isolate); + DCHECK_EQ(4, args.length()); + // Runtime functions don't follow the IC's calling convention. + Handle<Object> receiver = args.at(0); + Handle<Object> key = args.at(1); + Handle<Smi> slot = args.at<Smi>(2); + Handle<HeapObject> maybe_vector = args.at<HeapObject>(3); + + Handle<FeedbackVector> vector = Handle<FeedbackVector>(); + if (!maybe_vector->IsUndefined()) { + DCHECK(maybe_vector->IsFeedbackVector()); + vector = Handle<FeedbackVector>::cast(maybe_vector); + } + FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); + KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kHasKeyed); + ic.UpdateState(receiver, key); + RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); +} + +RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) { + HandleScope scope(isolate); + Handle<JSObject> receiver = args.at<JSObject>(0); + DCHECK_GE(args.smi_at(1), 0); + uint32_t index = args.smi_at(1); + + Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(), + isolate); + PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, + *receiver, Just(kDontThrow)); + + if (!interceptor->query()->IsUndefined(isolate)) { + Handle<Object> result = arguments.CallIndexedQuery(interceptor, index); + if (!result.is_null()) { + int32_t value; + CHECK(result->ToInt32(&value)); + return value == ABSENT ? ReadOnlyRoots(isolate).false_value() + : ReadOnlyRoots(isolate).true_value(); + } + } else if (!interceptor->getter()->IsUndefined(isolate)) { + Handle<Object> result = arguments.CallIndexedGetter(interceptor, index); + if (!result.is_null()) { + return ReadOnlyRoots(isolate).true_value(); + } + } + + LookupIterator it(isolate, receiver, index, receiver); + DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); + it.Next(); + Maybe<bool> maybe = JSReceiver::HasProperty(&it); + if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception(); + return maybe.FromJust() ? ReadOnlyRoots(isolate).true_value() + : ReadOnlyRoots(isolate).false_value(); +} + } // namespace internal } // namespace v8 |