diff --git a/src/ast/ast.cc b/src/ast/ast.cc index efee2a8b20..9235b47dfb 100644 --- a/src/ast/ast.cc +++ b/src/ast/ast.cc @@ -250,16 +250,16 @@ static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec, FeedbackSlot* out_slot) { Property* property = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(property); - if ((assign_type == VARIABLE && - expr->AsVariableProxy()->var()->IsUnallocated()) || - assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { - // TODO(ishell): consider using ICSlotCache for variables here. - if (assign_type == KEYED_PROPERTY) { - *out_slot = spec->AddKeyedStoreICSlot(language_mode); + // TODO(ishell): consider using ICSlotCache for variables here. + if (assign_type == VARIABLE && + expr->AsVariableProxy()->var()->IsUnallocated()) { + *out_slot = spec->AddStoreGlobalICSlot(language_mode); - } else { - *out_slot = spec->AddStoreICSlot(language_mode); - } + } else if (assign_type == NAMED_PROPERTY) { + *out_slot = spec->AddStoreICSlot(language_mode); + + } else if (assign_type == KEYED_PROPERTY) { + *out_slot = spec->AddKeyedStoreICSlot(language_mode); } } diff --git a/src/code-events.h b/src/code-events.h index 056aa4139d..ca92e2b5e4 100644 --- a/src/code-events.h +++ b/src/code-events.h @@ -65,6 +65,7 @@ class String; V(REG_EXP_TAG, "RegExp") \ V(SCRIPT_TAG, "Script") \ V(STORE_IC_TAG, "StoreIC") \ + V(STORE_GLOBAL_IC_TAG, "StoreGlobalIC") \ V(STORE_POLYMORPHIC_IC_TAG, "StorePolymorphicIC") \ V(STUB_TAG, "Stub") \ V(NATIVE_FUNCTION_TAG, "Function") \ diff --git a/src/code-factory.cc b/src/code-factory.cc index 7755d2bd31..96a360601c 100644 --- a/src/code-factory.cc +++ b/src/code-factory.cc @@ -147,6 +147,25 @@ Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) { StoreWithVectorDescriptor(isolate)); } +// static +Callable CodeFactory::StoreGlobalIC(Isolate* isolate, + LanguageMode language_mode) { + // TODO(ishell): Use StoreGlobalIC[Strict]Trampoline when it's ready. + return Callable(language_mode == STRICT + ? isolate->builtins()->StoreICStrictTrampoline() + : isolate->builtins()->StoreICTrampoline(), + StoreDescriptor(isolate)); +} + +// static +Callable CodeFactory::StoreGlobalICInOptimizedCode(Isolate* isolate, + LanguageMode language_mode) { + // TODO(ishell): Use StoreGlobalIC[Strict] when it's ready. + return Callable(language_mode == STRICT ? isolate->builtins()->StoreICStrict() + : isolate->builtins()->StoreIC(), + StoreWithVectorDescriptor(isolate)); +} + // static Callable CodeFactory::KeyedStoreIC(Isolate* isolate, LanguageMode language_mode) { diff --git a/src/code-factory.h b/src/code-factory.h index 54d107b9b5..da85ce4ca7 100644 --- a/src/code-factory.h +++ b/src/code-factory.h @@ -41,6 +41,9 @@ class V8_EXPORT_PRIVATE CodeFactory final { static Callable CallICTrampoline( Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny, TailCallMode tail_call_mode = TailCallMode::kDisallow); + static Callable StoreGlobalIC(Isolate* isolate, LanguageMode mode); + static Callable StoreGlobalICInOptimizedCode(Isolate* isolate, + LanguageMode mode); static Callable StoreIC(Isolate* isolate, LanguageMode mode); static Callable StoreICInOptimizedCode(Isolate* isolate, LanguageMode mode); static Callable StoreIC_Uninitialized(Isolate* isolate, LanguageMode mode); diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index c54cb7a8ec..1876f1fb01 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -256,7 +256,7 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) { CallDescriptor::Flags flags = FrameStateFlagForCall(node); const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op()); Callable callable = - CodeFactory::StoreICInOptimizedCode(isolate(), p.language_mode()); + CodeFactory::StoreGlobalICInOptimizedCode(isolate(), p.language_mode()); Node* vector = jsgraph()->HeapConstant(p.feedback().vector()); // Load global object from the context. Node* native_context = effect = diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc index 8d52e96f02..80711504af 100644 --- a/src/crankshaft/hydrogen.cc +++ b/src/crankshaft/hydrogen.cc @@ -6573,13 +6573,15 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var, HValue* name = Add(var->name()); HValue* vector_value = Add(vector); HValue* slot_value = Add(vector->GetIndex(slot)); + DCHECK(vector->IsStoreGlobalIC(slot)); DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode()); - Callable callable = CodeFactory::StoreICInOptimizedCode( + Callable callable = CodeFactory::StoreGlobalICInOptimizedCode( isolate(), function_language_mode()); HValue* stub = Add(callable.code()); HValue* values[] = {global_object, name, value, slot_value, vector_value}; - HCallWithDescriptor* instr = Add( - Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); + HCallWithDescriptor* instr = + Add(Code::STORE_GLOBAL_IC, stub, 0, + callable.descriptor(), ArrayVector(values)); USE(instr); DCHECK(instr->HasObservableSideEffects()); Add(ast_id, REMOVABLE_SIMULATE); diff --git a/src/feedback-vector-inl.h b/src/feedback-vector-inl.h index b6512e20ff..f429ba5654 100644 --- a/src/feedback-vector-inl.h +++ b/src/feedback-vector-inl.h @@ -65,6 +65,8 @@ int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) { case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: case FeedbackSlotKind::kStoreOwnNamed: + case FeedbackSlotKind::kStoreGlobalSloppy: + case FeedbackSlotKind::kStoreGlobalStrict: case FeedbackSlotKind::kStoreKeyedSloppy: case FeedbackSlotKind::kStoreKeyedStrict: case FeedbackSlotKind::kStoreDataPropertyInLiteral: @@ -185,6 +187,8 @@ void FeedbackVector::ComputeCounts(int* with_type_info, int* generic, case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: case FeedbackSlotKind::kStoreOwnNamed: + case FeedbackSlotKind::kStoreGlobalSloppy: + case FeedbackSlotKind::kStoreGlobalStrict: case FeedbackSlotKind::kStoreKeyedSloppy: case FeedbackSlotKind::kStoreKeyedStrict: case FeedbackSlotKind::kStoreDataPropertyInLiteral: diff --git a/src/feedback-vector.cc b/src/feedback-vector.cc index e175044beb..b937436bd4 100644 --- a/src/feedback-vector.cc +++ b/src/feedback-vector.cc @@ -116,43 +116,47 @@ bool FeedbackMetadata::SpecDiffersFrom( const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) { switch (kind) { case FeedbackSlotKind::kInvalid: - return "INVALID"; + return "Invalid"; case FeedbackSlotKind::kCall: - return "CALL_IC"; + return "Call"; case FeedbackSlotKind::kLoadProperty: - return "LOAD_IC"; + return "LoadProperty"; case FeedbackSlotKind::kLoadGlobalInsideTypeof: - return "LOAD_GLOBAL_INSIDE_TYPEOF_IC"; + return "LoadGlobalInsideTypeof"; case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: - return "LOAD_GLOBAL_NOT_INSIDE_TYPEOF_IC"; + return "LoadGlobalNotInsideTypeof"; case FeedbackSlotKind::kLoadKeyed: - return "KEYED_LOAD_IC"; + return "LoadKeyed"; case FeedbackSlotKind::kStoreNamedSloppy: - return "STORE_SLOPPY_IC"; + return "StoreNamedSloppy"; case FeedbackSlotKind::kStoreNamedStrict: - return "STORE_STRICT_IC"; + return "StoreNamedStrict"; case FeedbackSlotKind::kStoreOwnNamed: - return "STORE_OWN_IC"; + return "StoreOwnNamed"; + case FeedbackSlotKind::kStoreGlobalSloppy: + return "StoreGlobalSloppy"; + case FeedbackSlotKind::kStoreGlobalStrict: + return "StoreGlobalStrict"; case FeedbackSlotKind::kStoreKeyedSloppy: - return "KEYED_STORE_SLOPPY_IC"; + return "StoreKeyedSloppy"; case FeedbackSlotKind::kStoreKeyedStrict: - return "KEYED_STORE_STRICT_IC"; + return "StoreKeyedStrict"; case FeedbackSlotKind::kBinaryOp: - return "INTERPRETER_BINARYOP_IC"; + return "BinaryOp"; case FeedbackSlotKind::kCompareOp: - return "INTERPRETER_COMPARE_IC"; + return "CompareOp"; case FeedbackSlotKind::kToBoolean: - return "TO_BOOLEAN_IC"; + return "ToBoolean"; case FeedbackSlotKind::kStoreDataPropertyInLiteral: - return "STORE_DATA_PROPERTY_IN_LITERAL_IC"; + return "StoreDataPropertyInLiteral"; case FeedbackSlotKind::kCreateClosure: return "kCreateClosure"; case FeedbackSlotKind::kLiteral: - return "LITERAL"; + return "Literal"; case FeedbackSlotKind::kTypeProfile: - return "TYPE_PROFILE"; + return "TypeProfile"; case FeedbackSlotKind::kGeneral: - return "STUB"; + return "General"; case FeedbackSlotKind::kKindsNumber: break; } @@ -240,6 +244,8 @@ Handle FeedbackVector::New(Isolate* isolate, case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: case FeedbackSlotKind::kStoreOwnNamed: + case FeedbackSlotKind::kStoreGlobalSloppy: + case FeedbackSlotKind::kStoreGlobalStrict: case FeedbackSlotKind::kStoreKeyedSloppy: case FeedbackSlotKind::kStoreKeyedStrict: case FeedbackSlotKind::kStoreDataPropertyInLiteral: @@ -341,7 +347,9 @@ void FeedbackVector::ClearSlots(JSFunction* host_function) { } case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: - case FeedbackSlotKind::kStoreOwnNamed: { + case FeedbackSlotKind::kStoreOwnNamed: + case FeedbackSlotKind::kStoreGlobalSloppy: + case FeedbackSlotKind::kStoreGlobalStrict: { StoreICNexus nexus(this, slot); if (!nexus.IsCleared()) { nexus.Clear(); diff --git a/src/feedback-vector.h b/src/feedback-vector.h index a90c3069b0..598cb23604 100644 --- a/src/feedback-vector.h +++ b/src/feedback-vector.h @@ -27,6 +27,8 @@ enum class FeedbackSlotKind { kLoadGlobalNotInsideTypeof, kLoadGlobalInsideTypeof, kLoadKeyed, + kStoreGlobalSloppy, + kStoreGlobalStrict, kStoreNamedSloppy, kStoreNamedStrict, kStoreOwnNamed, @@ -62,6 +64,11 @@ inline bool IsKeyedLoadICKind(FeedbackSlotKind kind) { return kind == FeedbackSlotKind::kLoadKeyed; } +inline bool IsStoreGlobalICKind(FeedbackSlotKind kind) { + return kind == FeedbackSlotKind::kStoreGlobalSloppy || + kind == FeedbackSlotKind::kStoreGlobalStrict; +} + inline bool IsStoreICKind(FeedbackSlotKind kind) { return kind == FeedbackSlotKind::kStoreNamedSloppy || kind == FeedbackSlotKind::kStoreNamedStrict; @@ -89,8 +96,9 @@ inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) { inline LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind) { DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind) || - IsKeyedStoreICKind(kind)); + IsStoreGlobalICKind(kind) || IsKeyedStoreICKind(kind)); return (kind == FeedbackSlotKind::kStoreNamedSloppy || + kind == FeedbackSlotKind::kStoreGlobalSloppy || kind == FeedbackSlotKind::kStoreKeyedSloppy) ? SLOPPY : STRICT; @@ -132,6 +140,13 @@ class FeedbackVectorSpecBase { return AddSlot(FeedbackSlotKind::kStoreOwnNamed); } + FeedbackSlot AddStoreGlobalICSlot(LanguageMode language_mode) { + STATIC_ASSERT(LANGUAGE_END == 2); + return AddSlot(is_strict(language_mode) + ? FeedbackSlotKind::kStoreGlobalStrict + : FeedbackSlotKind::kStoreGlobalSloppy); + } + FeedbackSlot AddKeyedStoreICSlot(LanguageMode language_mode) { STATIC_ASSERT(LANGUAGE_END == 2); return AddSlot(is_strict(language_mode) @@ -336,6 +351,7 @@ class FeedbackVector : public FixedArray { DEFINE_SLOT_KIND_PREDICATE(IsKeyedLoadIC) DEFINE_SLOT_KIND_PREDICATE(IsStoreIC) DEFINE_SLOT_KIND_PREDICATE(IsStoreOwnIC) + DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC) DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC) DEFINE_SLOT_KIND_PREDICATE(IsTypeProfile) #undef DEFINE_SLOT_KIND_PREDICATE @@ -616,11 +632,13 @@ class StoreICNexus : public FeedbackNexus { public: StoreICNexus(Handle vector, FeedbackSlot slot) : FeedbackNexus(vector, slot) { - DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot)); + DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot) || + vector->IsStoreGlobalIC(slot)); } StoreICNexus(FeedbackVector* vector, FeedbackSlot slot) : FeedbackNexus(vector, slot) { - DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot)); + DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot) || + vector->IsStoreGlobalIC(slot)); } void Clear() override { ConfigurePremonomorphic(); } diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index 94b4b18708..d8e49bce52 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -1265,7 +1265,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(r0)); __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1722,7 +1722,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, if (var->IsUnallocated()) { // Global var, const, or let. __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 13ad1c617e..e41035e3b0 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -1251,7 +1251,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(x0)); __ Peek(StoreDescriptor::ReceiverRegister(), 0); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1669,7 +1669,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, if (var->IsUnallocated()) { // Global var, const, or let. __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index 3573c1f2f4..736870b456 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -217,7 +217,7 @@ void FullCodeGenerator::CallLoadIC(FeedbackSlot slot, Handle name) { } void FullCodeGenerator::CallStoreIC(FeedbackSlot slot, Handle name, - bool store_own_property) { + StoreICKind store_ic_kind) { DCHECK(name->IsName()); __ Move(StoreDescriptor::NameRegister(), name); @@ -231,16 +231,26 @@ void FullCodeGenerator::CallStoreIC(FeedbackSlot slot, Handle name, } Handle code; - if (store_own_property) { - DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed, - feedback_vector_spec()->GetKind(slot)); - code = CodeFactory::StoreOwnIC(isolate()).code(); - } else { - // Ensure that language mode is in sync with the IC slot kind. - DCHECK_EQ( - GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)), - language_mode()); - code = CodeFactory::StoreIC(isolate(), language_mode()).code(); + switch (store_ic_kind) { + case kStoreOwn: + DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed, + feedback_vector_spec()->GetKind(slot)); + code = CodeFactory::StoreOwnIC(isolate()).code(); + break; + case kStoreGlobal: + // Ensure that language mode is in sync with the IC slot kind. + DCHECK_EQ( + GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)), + language_mode()); + code = CodeFactory::StoreGlobalIC(isolate(), language_mode()).code(); + break; + case kStoreNamed: + // Ensure that language mode is in sync with the IC slot kind. + DCHECK_EQ( + GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)), + language_mode()); + code = CodeFactory::StoreIC(isolate(), language_mode()).code(); + break; } __ Call(code, RelocInfo::CODE_TARGET); RestoreContext(); diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h index d03788262a..94d3c9f22e 100644 --- a/src/full-codegen/full-codegen.h +++ b/src/full-codegen/full-codegen.h @@ -512,8 +512,9 @@ class FullCodeGenerator final : public AstVisitor { TypeFeedbackId id = TypeFeedbackId::None()); void CallLoadIC(FeedbackSlot slot, Handle name); + enum StoreICKind { kStoreNamed, kStoreOwn, kStoreGlobal }; void CallStoreIC(FeedbackSlot slot, Handle name, - bool store_own_property = false); + StoreICKind store_ic_kind = kStoreNamed); void CallKeyedStoreIC(FeedbackSlot slot); void SetFunctionPosition(FunctionLiteral* fun); diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 2e81b76e95..8ac31909c4 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -1193,7 +1193,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(eax)); __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); @@ -1645,7 +1645,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ mov(StoreDescriptor::ReceiverRegister(), ContextOperand(StoreDescriptor::ReceiverRegister(), Context::EXTENSION_INDEX)); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index 6c46452246..114b98b103 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -1262,7 +1262,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(StoreDescriptor::ValueRegister(), result_register()); DCHECK(StoreDescriptor::ValueRegister().is(a0)); __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1733,7 +1733,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, // Global var, const, or let. __ mov(StoreDescriptor::ValueRegister(), result_register()); __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index efd7ba707c..1b7fdf1a83 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -1264,7 +1264,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(StoreDescriptor::ValueRegister(), result_register()); DCHECK(StoreDescriptor::ValueRegister().is(a0)); __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1734,7 +1734,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, // Global var, const, or let. __ mov(StoreDescriptor::ValueRegister(), result_register()); __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/ppc/full-codegen-ppc.cc b/src/full-codegen/ppc/full-codegen-ppc.cc index a8e6f52704..bc27cb61dc 100644 --- a/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/src/full-codegen/ppc/full-codegen-ppc.cc @@ -1232,7 +1232,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(r3)); __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1731,7 +1731,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, if (var->IsUnallocated()) { // Global var, const, or let. __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/s390/full-codegen-s390.cc b/src/full-codegen/s390/full-codegen-s390.cc index 556c8298cc..41e974e55a 100644 --- a/src/full-codegen/s390/full-codegen-s390.cc +++ b/src/full-codegen/s390/full-codegen-s390.cc @@ -1197,7 +1197,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(r2)); __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1704,7 +1704,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, if (var->IsUnallocated()) { // Global var, const, or let. __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { // Non-initializing assignment to let variable needs a write barrier. diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 4e3fe3ffda..e1e09695d2 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -1224,7 +1224,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(rax)); __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { @@ -1636,7 +1636,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, if (var->IsUnallocated()) { // Global var, const, or let. __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index e48f691c10..49224ccdcd 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -1183,7 +1183,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); DCHECK(StoreDescriptor::ValueRegister().is(eax)); __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); - CallStoreIC(property->GetSlot(0), key->value(), true); + CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); if (NeedsHomeObject(value)) { EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); @@ -1635,7 +1635,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ mov(StoreDescriptor::ReceiverRegister(), ContextOperand(StoreDescriptor::ReceiverRegister(), Context::EXTENSION_INDEX)); - CallStoreIC(slot, var->name()); + CallStoreIC(slot, var->name(), kStoreGlobal); } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { DCHECK(!var->IsLookupSlot()); diff --git a/src/ic/ic.cc b/src/ic/ic.cc index 4daf1662d5..49a50a8c0e 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1471,46 +1471,51 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle value, return it->IsCacheableTransition(); } +MaybeHandle StoreGlobalIC::Store(Handle object, + Handle name, + Handle value) { + DCHECK(object->IsJSGlobalObject()); + DCHECK(name->IsString()); + + // Look up in script context table. + Handle str_name = Handle::cast(name); + Handle global = Handle::cast(object); + Handle script_contexts( + global->native_context()->script_context_table()); + + ScriptContextTable::LookupResult lookup_result; + if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { + Handle script_context = ScriptContextTable::GetContext( + script_contexts, lookup_result.context_index); + if (lookup_result.mode == CONST) { + return TypeError(MessageTemplate::kConstAssign, object, name); + } + + Handle previous_value = + FixedArray::get(*script_context, lookup_result.slot_index, isolate()); + + if (previous_value->IsTheHole(isolate())) { + // Do not install stubs and stay pre-monomorphic for + // uninitialized accesses. + return ReferenceError(name); + } + + if (FLAG_use_ic && StoreScriptContextFieldStub::Accepted(&lookup_result)) { + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub); + StoreScriptContextFieldStub stub(isolate(), &lookup_result); + PatchCache(name, stub.GetCode()); + } + + script_context->set(lookup_result.slot_index, *value); + return value; + } + + return StoreIC::Store(object, name, value); +} MaybeHandle StoreIC::Store(Handle object, Handle name, Handle value, JSReceiver::StoreFromKeyed store_mode) { - if (object->IsJSGlobalObject() && name->IsString()) { - // Look up in script context table. - Handle str_name = Handle::cast(name); - Handle global = Handle::cast(object); - Handle script_contexts( - global->native_context()->script_context_table()); - - ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { - Handle script_context = ScriptContextTable::GetContext( - script_contexts, lookup_result.context_index); - if (lookup_result.mode == CONST) { - return TypeError(MessageTemplate::kConstAssign, object, name); - } - - Handle previous_value = - FixedArray::get(*script_context, lookup_result.slot_index, isolate()); - - if (previous_value->IsTheHole(isolate())) { - // Do not install stubs and stay pre-monomorphic for - // uninitialized accesses. - return ReferenceError(name); - } - - if (FLAG_use_ic && - StoreScriptContextFieldStub::Accepted(&lookup_result)) { - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub); - StoreScriptContextFieldStub stub(isolate(), &lookup_result); - PatchCache(name, stub.GetCode()); - } - - script_context->set(lookup_result.slot_index, *value); - return value; - } - } - // TODO(verwaest): Let SetProperty do the migration, since storing a property // might deprecate the current map again, if value does not fit. if (MigrateDeprecated(object) || object->IsJSProxy()) { @@ -2361,6 +2366,11 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { StoreIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); + } else if (IsStoreGlobalICKind(kind)) { + StoreICNexus nexus(vector, vector_slot); + StoreGlobalIC ic(isolate, &nexus); + ic.UpdateState(receiver, key); + RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } else { DCHECK(IsKeyedStoreICKind(kind)); KeyedStoreICNexus nexus(vector, vector_slot); diff --git a/src/ic/ic.h b/src/ic/ic.h index 0a8f665f94..ec8b11f427 100644 --- a/src/ic/ic.h +++ b/src/ic/ic.h @@ -55,7 +55,8 @@ class IC { return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC(); } bool IsAnyStore() const { - return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC(); + return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() || + IsKeyedStoreIC(); } // The ICs that don't pass slot and vector through the stack have to @@ -140,6 +141,7 @@ class IC { bool IsLoadIC() const { return IsLoadICKind(kind_); } bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); } bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); } + bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); } bool IsStoreIC() const { return IsStoreICKind(kind_); } bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); } bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); } @@ -348,7 +350,7 @@ class StoreIC : public IC { protected: // Stub accessors. Handle slow_stub() const { - // StoreIC and KeyedStoreIC share the same slow stub. + // All StoreICs share the same slow stub. return isolate()->builtins()->KeyedStoreIC_Slow(); } @@ -367,6 +369,15 @@ class StoreIC : public IC { friend class IC; }; +class StoreGlobalIC : public StoreIC { + public: + StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus) + : StoreIC(isolate, nexus) {} + + MUST_USE_RESULT MaybeHandle Store(Handle object, + Handle name, + Handle value); +}; enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap }; diff --git a/src/interpreter/interpreter-generator.cc b/src/interpreter/interpreter-generator.cc index 045f0fc26d..b0cb8b3d68 100644 --- a/src/interpreter/interpreter-generator.cc +++ b/src/interpreter/interpreter-generator.cc @@ -388,7 +388,7 @@ void InterpreterGenerator::DoStaGlobal(Callable ic, // Store the value in the accumulator into the global with name in constant pool // entry using FeedBackVector slot in sloppy mode. void InterpreterGenerator::DoStaGlobalSloppy(InterpreterAssembler* assembler) { - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, SLOPPY); + Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(isolate_, SLOPPY); DoStaGlobal(ic, assembler); } @@ -397,7 +397,7 @@ void InterpreterGenerator::DoStaGlobalSloppy(InterpreterAssembler* assembler) { // Store the value in the accumulator into the global with name in constant pool // entry using FeedBackVector slot in strict mode. void InterpreterGenerator::DoStaGlobalStrict(InterpreterAssembler* assembler) { - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, STRICT); + Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(isolate_, STRICT); DoStaGlobal(ic, assembler); } diff --git a/src/log.cc b/src/log.cc index d32ce1aa8e..c4c11b8907 100644 --- a/src/log.cc +++ b/src/log.cc @@ -1566,6 +1566,10 @@ void Logger::LogCodeObject(Object* object) { description = "A store IC from the snapshot"; tag = CodeEventListener::STORE_IC_TAG; break; + case AbstractCode::STORE_GLOBAL_IC: + description = "A store global IC from the snapshot"; + tag = CodeEventListener::STORE_GLOBAL_IC_TAG; + break; case AbstractCode::KEYED_STORE_IC: description = "A keyed store IC from the snapshot"; tag = CodeEventListener::KEYED_STORE_IC_TAG; diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 870c0a1e66..4651680946 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -722,7 +722,9 @@ void FeedbackVector::FeedbackVectorPrint(std::ostream& os) { // NOLINT } case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: - case FeedbackSlotKind::kStoreOwnNamed: { + case FeedbackSlotKind::kStoreOwnNamed: + case FeedbackSlotKind::kStoreGlobalSloppy: + case FeedbackSlotKind::kStoreGlobalStrict: { StoreICNexus nexus(this, slot); os << Code::ICState2String(nexus.StateFromFeedback()); break; diff --git a/src/objects.h b/src/objects.h index e7d8b14d3d..03d9811c76 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4877,6 +4877,7 @@ class Code: public HeapObject { V(LOAD_GLOBAL_IC) \ V(KEYED_LOAD_IC) \ V(STORE_IC) \ + V(STORE_GLOBAL_IC) \ V(KEYED_STORE_IC) \ V(BINARY_OP_IC) \ V(COMPARE_IC) \ diff --git a/src/type-info.cc b/src/type-info.cc index d7de1b8618..4bb971e8cd 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -89,7 +89,7 @@ InlineCacheState TypeFeedbackOracle::LoadInlineCacheState(FeedbackSlot slot) { bool TypeFeedbackOracle::StoreIsUninitialized(FeedbackSlot slot) { if (!slot.IsInvalid()) { FeedbackSlotKind kind = feedback_vector_->GetKind(slot); - if (IsStoreICKind(kind)) { + if (IsStoreICKind(kind) || IsStoreGlobalICKind(kind)) { StoreICNexus nexus(feedback_vector_, slot); return nexus.StateFromFeedback() == UNINITIALIZED; } else if (IsKeyedStoreICKind(kind)) { @@ -454,7 +454,8 @@ void TypeFeedbackOracle::CollectReceiverTypes(StubCache* stub_cache, void TypeFeedbackOracle::CollectReceiverTypes(FeedbackSlot slot, SmallMapList* types) { FeedbackSlotKind kind = feedback_vector_->GetKind(slot); - if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) { + if (IsStoreICKind(kind) || IsStoreOwnICKind(kind) || + IsStoreGlobalICKind(kind)) { StoreICNexus nexus(feedback_vector_, slot); CollectReceiverTypes(&nexus, types); } else { diff --git a/test/cctest/test-feedback-vector.cc b/test/cctest/test-feedback-vector.cc index 0d6fc55911..dc111e340f 100644 --- a/test/cctest/test-feedback-vector.cc +++ b/test/cctest/test-feedback-vector.cc @@ -481,9 +481,9 @@ TEST(ReferenceContextAllocatesNoSlots) { handle(f->feedback_vector(), isolate); FeedbackVectorHelper helper(feedback_vector); CHECK_EQ(4, helper.slot_count()); - CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreNamedSloppy); + CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy); CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof); - CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy); + CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreGlobalSloppy); CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kLoadGlobalNotInsideTypeof); }