[ic] Split StoreIC into StoreGlobalIC and StoreIC.
The former will handle stores to global variables, lets and undeclared variables. The latter will handle named stores to explicit receiver. BUG=chromium:576312, v8:5561 Change-Id: I335fa21db47c3d001da8cc79fa8cb6f8abcbb7e2 Reviewed-on: https://chromium-review.googlesource.com/458639 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#44085}
This commit is contained in:
parent
083a8d7209
commit
16c38aa820
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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") \
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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 =
|
||||
|
@ -6573,13 +6573,15 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
|
||||
HValue* name = Add<HConstant>(var->name());
|
||||
HValue* vector_value = Add<HConstant>(vector);
|
||||
HValue* slot_value = Add<HConstant>(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<HConstant>(callable.code());
|
||||
HValue* values[] = {global_object, name, value, slot_value, vector_value};
|
||||
HCallWithDescriptor* instr = Add<HCallWithDescriptor>(
|
||||
Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
|
||||
HCallWithDescriptor* instr =
|
||||
Add<HCallWithDescriptor>(Code::STORE_GLOBAL_IC, stub, 0,
|
||||
callable.descriptor(), ArrayVector(values));
|
||||
USE(instr);
|
||||
DCHECK(instr->HasObservableSideEffects());
|
||||
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
||||
|
@ -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:
|
||||
|
@ -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> 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();
|
||||
|
@ -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<FeedbackVector> 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(); }
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -217,7 +217,7 @@ void FullCodeGenerator::CallLoadIC(FeedbackSlot slot, Handle<Object> name) {
|
||||
}
|
||||
|
||||
void FullCodeGenerator::CallStoreIC(FeedbackSlot slot, Handle<Object> 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<Object> name,
|
||||
}
|
||||
|
||||
Handle<Code> 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();
|
||||
|
@ -512,8 +512,9 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
|
||||
TypeFeedbackId id = TypeFeedbackId::None());
|
||||
|
||||
void CallLoadIC(FeedbackSlot slot, Handle<Object> name);
|
||||
enum StoreICKind { kStoreNamed, kStoreOwn, kStoreGlobal };
|
||||
void CallStoreIC(FeedbackSlot slot, Handle<Object> name,
|
||||
bool store_own_property = false);
|
||||
StoreICKind store_ic_kind = kStoreNamed);
|
||||
void CallKeyedStoreIC(FeedbackSlot slot);
|
||||
|
||||
void SetFunctionPosition(FunctionLiteral* fun);
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
82
src/ic/ic.cc
82
src/ic/ic.cc
@ -1471,46 +1471,51 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
return it->IsCacheableTransition();
|
||||
}
|
||||
|
||||
MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value) {
|
||||
DCHECK(object->IsJSGlobalObject());
|
||||
DCHECK(name->IsString());
|
||||
|
||||
// Look up in script context table.
|
||||
Handle<String> str_name = Handle<String>::cast(name);
|
||||
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
|
||||
Handle<ScriptContextTable> script_contexts(
|
||||
global->native_context()->script_context_table());
|
||||
|
||||
ScriptContextTable::LookupResult lookup_result;
|
||||
if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
|
||||
Handle<Context> script_context = ScriptContextTable::GetContext(
|
||||
script_contexts, lookup_result.context_index);
|
||||
if (lookup_result.mode == CONST) {
|
||||
return TypeError(MessageTemplate::kConstAssign, object, name);
|
||||
}
|
||||
|
||||
Handle<Object> 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<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
JSReceiver::StoreFromKeyed store_mode) {
|
||||
if (object->IsJSGlobalObject() && name->IsString()) {
|
||||
// Look up in script context table.
|
||||
Handle<String> str_name = Handle<String>::cast(name);
|
||||
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
|
||||
Handle<ScriptContextTable> script_contexts(
|
||||
global->native_context()->script_context_table());
|
||||
|
||||
ScriptContextTable::LookupResult lookup_result;
|
||||
if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
|
||||
Handle<Context> script_context = ScriptContextTable::GetContext(
|
||||
script_contexts, lookup_result.context_index);
|
||||
if (lookup_result.mode == CONST) {
|
||||
return TypeError(MessageTemplate::kConstAssign, object, name);
|
||||
}
|
||||
|
||||
Handle<Object> 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);
|
||||
|
15
src/ic/ic.h
15
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<Code> 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<Object> Store(Handle<Object> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value);
|
||||
};
|
||||
|
||||
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
|
||||
|
||||
|
@ -388,7 +388,7 @@ void InterpreterGenerator::DoStaGlobal(Callable ic,
|
||||
// Store the value in the accumulator into the global with name in constant pool
|
||||
// entry <name_index> using FeedBackVector slot <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 <name_index> using FeedBackVector slot <slot> in strict mode.
|
||||
void InterpreterGenerator::DoStaGlobalStrict(InterpreterAssembler* assembler) {
|
||||
Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, STRICT);
|
||||
Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(isolate_, STRICT);
|
||||
DoStaGlobal(ic, assembler);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user