Commit 937b8cb6 authored by ishell's avatar ishell Committed by Commit bot

[ic] Support data handlers in LoadGlobalIC.

Also fixed handling of load non-existent handlers outside typeof.

BUG=v8:5561, chromium:662854

Review-Url: https://codereview.chromium.org/2511603002
Cr-Commit-Position: refs/heads/master@{#41073}
parent 48bbd1a7
......@@ -439,9 +439,6 @@ Handle<Code> TurboFanCodeStub::GenerateCode() {
ACCESSOR_ASSEMBLER(LoadIC)
ACCESSOR_ASSEMBLER(LoadICTrampoline)
ACCESSOR_ASSEMBLER(LoadICProtoArray)
ACCESSOR_ASSEMBLER(LoadGlobalIC)
ACCESSOR_ASSEMBLER(LoadGlobalICTrampoline)
ACCESSOR_ASSEMBLER(KeyedLoadICTF)
ACCESSOR_ASSEMBLER(KeyedLoadICTrampolineTF)
ACCESSOR_ASSEMBLER(StoreIC)
......@@ -449,16 +446,28 @@ ACCESSOR_ASSEMBLER(StoreICTrampoline)
#undef ACCESSOR_ASSEMBLER
void LoadICProtoArrayStub::GenerateAssembly(CodeAssemblerState* state) const {
AccessorAssembler::GenerateLoadICProtoArray(
state, throw_reference_error_if_nonexistent());
}
void LoadGlobalICStub::GenerateAssembly(CodeAssemblerState* state) const {
AccessorAssembler::GenerateLoadGlobalIC(state, typeof_mode());
}
void LoadGlobalICTrampolineStub::GenerateAssembly(
CodeAssemblerState* state) const {
AccessorAssembler::GenerateLoadGlobalICTrampoline(state, typeof_mode());
}
void KeyedStoreICTrampolineTFStub::GenerateAssembly(
CodeAssemblerState* state) const {
LanguageMode language_mode = StoreICState::GetLanguageMode(GetExtraICState());
AccessorAssembler::GenerateKeyedStoreICTrampolineTF(state, language_mode);
AccessorAssembler::GenerateKeyedStoreICTrampolineTF(state, language_mode());
}
void KeyedStoreICTFStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
LanguageMode language_mode = StoreICState::GetLanguageMode(GetExtraICState());
AccessorAssembler::GenerateKeyedStoreICTF(state, language_mode);
AccessorAssembler::GenerateKeyedStoreICTF(state, language_mode());
}
void StoreMapStub::GenerateAssembly(compiler::CodeAssemblerState* state) const {
......
......@@ -1956,6 +1956,11 @@ class LoadGlobalICTrampolineStub : public TurboFanCodeStub {
Code::Kind GetCodeKind() const override { return Code::LOAD_GLOBAL_IC; }
TypeofMode typeof_mode() const {
LoadGlobalICState state(GetExtraICState());
return state.typeof_mode();
}
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
......@@ -2022,6 +2027,10 @@ class KeyedStoreICTrampolineTFStub : public StoreICTrampolineStub {
Code::Kind GetCodeKind() const override { return Code::KEYED_STORE_IC; }
LanguageMode language_mode() const {
return StoreICState(GetExtraICState()).language_mode();
}
DEFINE_TURBOFAN_CODE_STUB(KeyedStoreICTrampolineTF, StoreICTrampolineStub);
};
......@@ -2059,7 +2068,23 @@ class LoadICStub : public TurboFanCodeStub {
class LoadICProtoArrayStub : public TurboFanCodeStub {
public:
explicit LoadICProtoArrayStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
explicit LoadICProtoArrayStub(Isolate* isolate,
bool throw_reference_error_if_nonexistent)
: TurboFanCodeStub(isolate) {
minor_key_ = ThrowReferenceErrorIfNonexistentBits::encode(
throw_reference_error_if_nonexistent);
}
bool throw_reference_error_if_nonexistent() const {
return ThrowReferenceErrorIfNonexistentBits::decode(minor_key_);
}
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
private:
class ThrowReferenceErrorIfNonexistentBits : public BitField<bool, 0, 1> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadICProtoArray);
DEFINE_TURBOFAN_CODE_STUB(LoadICProtoArray, TurboFanCodeStub);
......@@ -2074,6 +2099,11 @@ class LoadGlobalICStub : public TurboFanCodeStub {
Code::Kind GetCodeKind() const override { return Code::LOAD_GLOBAL_IC; }
TypeofMode typeof_mode() const {
LoadGlobalICState state(GetExtraICState());
return state.typeof_mode();
}
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
......@@ -2099,6 +2129,11 @@ class StoreICStub : public TurboFanCodeStub {
}
Code::Kind GetCodeKind() const override { return Code::STORE_IC; }
LanguageMode language_mode() const {
return StoreICState(GetExtraICState()).language_mode();
}
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
......@@ -2136,6 +2171,10 @@ class KeyedStoreICTFStub : public StoreICStub {
Code::Kind GetCodeKind() const override { return Code::KEYED_STORE_IC; }
LanguageMode language_mode() const {
return StoreICState(GetExtraICState()).language_mode();
}
DEFINE_TURBOFAN_CODE_STUB(KeyedStoreICTF, StoreICStub);
};
......
......@@ -508,6 +508,7 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
proxy->VariableFeedbackSlot());
Handle<Code> code = CodeFactory::LoadGlobalIC(isolate(), typeof_mode).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
}
void FullCodeGenerator::VisitSloppyBlockFunctionStatement(
......
......@@ -314,26 +314,24 @@ inline std::ostream& operator<<(std::ostream& os, const LanguageMode& mode) {
return os;
}
inline bool is_sloppy(LanguageMode language_mode) {
return language_mode == SLOPPY;
}
inline bool is_strict(LanguageMode language_mode) {
return language_mode != SLOPPY;
}
inline bool is_valid_language_mode(int language_mode) {
return language_mode == SLOPPY || language_mode == STRICT;
}
inline LanguageMode construct_language_mode(bool strict_bit) {
return static_cast<LanguageMode>(strict_bit);
}
enum TypeofMode : int { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
// This constant is used as an undefined value when passing source positions.
const int kNoSourcePosition = -1;
......
......@@ -19,16 +19,13 @@ using compiler::Node;
#define ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(V) \
V(LoadIC) \
V(LoadICTrampoline) \
V(LoadICProtoArray) \
V(LoadGlobalIC) \
V(LoadGlobalICTrampoline) \
V(KeyedLoadICTF) \
V(KeyedLoadICTrampolineTF) \
V(KeyedLoadICMegamorphic) \
V(StoreIC) \
V(StoreICTrampoline)
// KeyedStoreIC and KeyedStoreICTrampoline need custom handling because of
// their "language_mode" parameter.
// The other IC entry points need custom handling because of additional
// parameters like "typeof_mode" or "language_mode".
class AccessorAssemblerImpl : public CodeStubAssembler {
public:
......@@ -40,6 +37,11 @@ class AccessorAssemblerImpl : public CodeStubAssembler {
ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DECLARE_PUBLIC_METHOD)
#undef DECLARE_PUBLIC_METHOD
void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
void GenerateLoadGlobalIC(TypeofMode typeof_mode);
void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
void GenerateKeyedStoreICTF(LanguageMode language_mode);
void GenerateKeyedStoreICTrampolineTF(LanguageMode language_mode);
......@@ -88,8 +90,9 @@ class AccessorAssemblerImpl : public CodeStubAssembler {
// Stub generation entry points.
void LoadIC(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler);
void LoadGlobalIC(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent);
void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
......@@ -120,13 +123,22 @@ class AccessorAssemblerImpl : public CodeStubAssembler {
Node* smi_handler, Label* miss,
ElementSupport support_elements);
void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
Variable* var_holder, Variable* var_smi_handler,
Label* if_smi_handler, Label* miss);
void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
Variable* var_holder,
Variable* var_smi_handler,
Label* if_smi_handler, Label* miss,
bool throw_reference_error_if_nonexistent);
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags,
Label* miss);
Label* miss,
bool throw_reference_error_if_nonexistent);
// LoadGlobalIC implementation.
void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
Label* miss,
bool throw_reference_error_if_nonexistent);
// StoreIC implementation.
......
This diff is collapsed.
......@@ -18,10 +18,13 @@ class AccessorAssembler {
public:
static void GenerateLoadIC(compiler::CodeAssemblerState* state);
static void GenerateLoadICTrampoline(compiler::CodeAssemblerState* state);
static void GenerateLoadICProtoArray(compiler::CodeAssemblerState* state);
static void GenerateLoadGlobalIC(compiler::CodeAssemblerState* state);
static void GenerateLoadICProtoArray(
compiler::CodeAssemblerState* state,
bool throw_reference_error_if_nonexistent);
static void GenerateLoadGlobalIC(compiler::CodeAssemblerState* state,
TypeofMode typeof_mode);
static void GenerateLoadGlobalICTrampoline(
compiler::CodeAssemblerState* state);
compiler::CodeAssemblerState* state, TypeofMode typeof_mode);
static void GenerateKeyedLoadICTF(compiler::CodeAssemblerState* state);
static void GenerateKeyedLoadICTrampolineTF(
compiler::CodeAssemblerState* state);
......
......@@ -564,7 +564,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
nexus->ConfigureMonomorphic(map, handler);
} else if (kind() == Code::LOAD_GLOBAL_IC) {
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
nexus->ConfigureHandlerMode(handler);
} else if (kind() == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, handler);
......@@ -794,6 +794,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
DCHECK(IsHandler(*handler));
// Currently only LoadIC and KeyedLoadIC support non-code handlers.
DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC ||
kind() == Code::LOAD_GLOBAL_IC ||
kind() == Code::KEYED_LOAD_IC ||
kind() == Code::STORE_IC ||
kind() == Code::KEYED_STORE_IC);
......@@ -858,10 +859,6 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<Name> name, int first_index) {
DCHECK(holder.is_null() || holder->HasFastProperties());
// The following kinds of receiver maps require custom handler compilation.
if (receiver_map->IsJSGlobalObjectMap()) {
return -1;
}
// We don't encode the requirement to check access rights because we already
// passed the access check for current native context and the access
// can't be revoked.
......@@ -882,6 +879,17 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
native_context->self_weak_cell());
}
checks_count++;
} else if (receiver_map->IsJSGlobalObjectMap()) {
if (fill_array) {
Handle<JSGlobalObject> global = isolate->global_object();
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell);
}
checks_count++;
}
// Create/count entries for each global or dictionary prototype appeared in
......@@ -937,14 +945,14 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<Object> smi_handler) {
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
} else if (receiver_map->is_dictionary_map()) {
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler =
LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler);
}
......@@ -975,10 +983,11 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<JSObject> holder; // null handle
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> smi_handler = LoadHandler::LoadNonExistent(
isolate(), receiver_map->is_dictionary_map());
bool do_negative_lookup_on_receiver =
receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap();
Handle<Object> smi_handler =
LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver);
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
DCHECK(!receiver_map->is_dictionary_map());
......@@ -1066,14 +1075,16 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsFound()) {
if (kind() == Code::LOAD_IC) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
code = LoadNonExistent(receiver_map(), lookup->name());
} else if (kind() == Code::LOAD_GLOBAL_IC) {
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
receiver_map());
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
if (code.is_null()) code = slow_stub();
if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) {
if (FLAG_tf_load_ic_stub) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
code = LoadNonExistent(receiver_map(), lookup->name());
} else {
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
receiver_map());
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
if (code.is_null()) code = slow_stub();
}
} else {
code = slow_stub();
}
......@@ -1394,7 +1405,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (receiver_is_holder) {
return smi_handler;
}
if (FLAG_tf_load_ic_stub && kind() != Code::LOAD_GLOBAL_IC) {
if (FLAG_tf_load_ic_stub) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
......@@ -1410,10 +1421,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
return smi_handler;
}
if (kind() != Code::LOAD_GLOBAL_IC) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
} else {
if (receiver_is_holder) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub);
......
......@@ -181,10 +181,6 @@ enum KeyedAccessStoreMode {
STORE_NO_TRANSITION_HANDLE_COW
};
enum TypeofMode : int { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
enum MutableMode {
MUTABLE,
IMMUTABLE
......
......@@ -713,7 +713,7 @@ void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
SKIP_WRITE_BARRIER);
}
void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) {
void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
SetFeedback(GetIsolate()->heap()->empty_weak_cell());
SetFeedbackExtra(*handler);
}
......
......@@ -555,7 +555,7 @@ class LoadGlobalICNexus : public FeedbackNexus {
void ConfigureUninitialized() override;
void ConfigurePropertyCellMode(Handle<PropertyCell> cell);
void ConfigureHandlerMode(Handle<Code> handler);
void ConfigureHandlerMode(Handle<Object> handler);
InlineCacheState StateFromFeedback() const override;
};
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function f() {
typeof boom;
boom;
}
assertThrows(()=>f());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment