summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic/ic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ic/ic.cc')
-rw-r--r--deps/v8/src/ic/ic.cc491
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