Commit 7cdfb6df authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[ic] Introduce proper StoreGlobalIC dispatcher.

The dispatcher is responsible for handling stores to lexical environment
variables and for storing directly to the JSGlobalObject. In the latter
case the dispatcher also ensures that JSGlobalProxy is provided as
a receiver if a setter function has to be called.
Unlike StoreIC the calling convention for the StoreGlobalIC does not include
receiver.

Bug: v8:7206, chromium:576312, v8:5561
Change-Id: Ifa896c7b41bf440785b757c2272ec91211e79c98
Reviewed-on: https://chromium-review.googlesource.com/818965
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50081}
parent ce5eb004
......@@ -572,6 +572,8 @@ namespace internal {
TFH(LoadICTrampoline, Load) \
TFH(KeyedLoadIC, LoadWithVector) \
TFH(KeyedLoadICTrampoline, Load) \
TFH(StoreGlobalIC, StoreGlobalWithVector) \
TFH(StoreGlobalICTrampoline, StoreGlobal) \
TFH(StoreIC, StoreWithVector) \
TFH(StoreICTrampoline, Store) \
TFH(KeyedStoreIC, StoreWithVector) \
......
......@@ -29,6 +29,8 @@ IC_BUILTIN(LoadField)
IC_BUILTIN(KeyedLoadICTrampoline)
IC_BUILTIN(KeyedLoadIC_Megamorphic)
IC_BUILTIN(KeyedLoadIC_PolymorphicName)
IC_BUILTIN(StoreGlobalIC)
IC_BUILTIN(StoreGlobalICTrampoline)
IC_BUILTIN(StoreIC)
IC_BUILTIN(StoreICTrampoline)
IC_BUILTIN(KeyedStoreIC)
......
......@@ -83,22 +83,6 @@ 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(BUILTIN_CODE(isolate, StoreICTrampoline),
StoreDescriptor(isolate));
}
// static
Callable CodeFactory::StoreGlobalICInOptimizedCode(Isolate* isolate,
LanguageMode language_mode) {
// TODO(ishell): Use StoreGlobalIC[Strict] when it's ready.
return Callable(BUILTIN_CODE(isolate, StoreIC),
StoreWithVectorDescriptor(isolate));
}
// static
Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
switch (op) {
......
......@@ -28,9 +28,6 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode);
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
TypeofMode typeof_mode);
static Callable StoreGlobalIC(Isolate* isolate, LanguageMode mode);
static Callable StoreGlobalICInOptimizedCode(Isolate* isolate,
LanguageMode mode);
static Callable StoreOwnIC(Isolate* isolate);
static Callable StoreOwnICInOptimizedCode(Isolate* isolate);
......
......@@ -251,32 +251,17 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
Node* context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Load global object from the context.
Node* native_context = effect =
graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
jsgraph()->IntPtrConstant(
Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
effect, control);
Node* global = effect = graph()->NewNode(
machine()->Load(MachineType::AnyTagged()), native_context,
jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
effect, control);
NodeProperties::ReplaceEffectInput(node, effect);
node->InsertInput(zone(), 0, global);
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
if (outer_state->opcode() != IrOpcode::kFrameState) {
Callable callable =
CodeFactory::StoreGlobalIC(isolate(), p.language_mode());
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalICTrampoline);
ReplaceWithStubCall(node, callable, flags);
} else {
Callable callable =
CodeFactory::StoreGlobalICInOptimizedCode(isolate(), p.language_mode());
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
node->InsertInput(zone(), 4, vector);
node->InsertInput(zone(), 3, vector);
ReplaceWithStubCall(node, callable, flags);
}
}
......
......@@ -255,6 +255,8 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
switch (kind) {
case FeedbackSlotKind::kLoadGlobalInsideTypeof:
case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
case FeedbackSlotKind::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict:
vector->set(index, isolate->heap()->empty_weak_cell(),
SKIP_WRITE_BARRIER);
break;
......@@ -280,8 +282,6 @@ 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:
......@@ -432,10 +432,17 @@ bool FeedbackVector::ClearSlots(Isolate* isolate) {
}
case FeedbackSlotKind::kStoreNamedSloppy:
case FeedbackSlotKind::kStoreNamedStrict:
case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kStoreOwnNamed: {
StoreICNexus nexus(this, slot);
if (!nexus.IsCleared()) {
nexus.Clear();
feedback_updated = true;
}
break;
}
case FeedbackSlotKind::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict: {
StoreICNexus nexus(this, slot);
StoreGlobalICNexus nexus(this, slot);
if (!nexus.IsCleared()) {
nexus.Clear();
feedback_updated = true;
......@@ -610,6 +617,37 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
return UNINITIALIZED;
}
void StoreGlobalICNexus::ConfigureUninitialized() {
Isolate* isolate = GetIsolate();
SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
SKIP_WRITE_BARRIER);
}
void StoreGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
Isolate* isolate = GetIsolate();
SetFeedback(*isolate->factory()->NewWeakCell(cell));
SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
SKIP_WRITE_BARRIER);
}
void StoreGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
SetFeedback(GetIsolate()->heap()->empty_weak_cell());
SetFeedbackExtra(*handler);
}
InlineCacheState StoreGlobalICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
Object* extra = GetFeedbackExtra();
if (!WeakCell::cast(feedback)->cleared() ||
extra != *FeedbackVector::UninitializedSentinel(isolate)) {
return MONOMORPHIC;
}
return UNINITIALIZED;
}
InlineCacheState StoreICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
......
......@@ -728,13 +728,11 @@ class StoreICNexus : public FeedbackNexus {
public:
StoreICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot) ||
vector->IsStoreGlobalIC(slot));
DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot));
}
StoreICNexus(FeedbackVector* vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot) ||
vector->IsStoreGlobalIC(slot));
DCHECK(vector->IsStoreIC(slot) || vector->IsStoreOwnIC(slot));
}
void Clear() override { ConfigurePremonomorphic(); }
......@@ -742,6 +740,35 @@ class StoreICNexus : public FeedbackNexus {
InlineCacheState StateFromFeedback() const override;
};
class StoreGlobalICNexus : public FeedbackNexus {
public:
StoreGlobalICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->IsStoreGlobalIC(slot));
}
StoreGlobalICNexus(FeedbackVector* vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->IsStoreGlobalIC(slot));
}
int ExtractMaps(MapHandles* maps) const final {
// StoreGlobalICs don't record map feedback.
return 0;
}
MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const final {
return MaybeHandle<Code>();
}
bool FindHandlers(ObjectHandles* code_list, int length = -1) const final {
return length == 0;
}
void ConfigureUninitialized() override;
void ConfigurePropertyCellMode(Handle<PropertyCell> cell);
void ConfigureHandlerMode(Handle<Object> handler);
InlineCacheState StateFromFeedback() const override;
};
// TODO(ishell): Currently we use StoreOwnIC only for storing properties that
// already exist in the boilerplate therefore we can use StoreIC.
typedef StoreICNexus StoreOwnICNexus;
......
......@@ -2731,6 +2731,41 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
}
}
void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
Label try_handler(this), miss(this, Label::kDeferred);
Node* feedback =
LoadFeedbackVectorSlot(pp->vector, pp->slot, 0, SMI_PARAMETERS);
Node* property_cell = LoadWeakCellValue(feedback, &try_handler);
ExitPoint direct_exit(this);
StoreGlobalIC_PropertyCellCase(property_cell, pp->value, &direct_exit, &miss);
BIND(&try_handler);
{
Comment("StoreGlobalIC_try_handler");
Node* handler = LoadFeedbackVectorSlot(pp->vector, pp->slot, kPointerSize,
SMI_PARAMETERS);
GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
&miss);
StoreICParameters p = *pp;
DCHECK_NULL(p.receiver);
Node* native_context = LoadNativeContext(p.context);
p.receiver =
LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
HandleStoreICHandlerCase(&p, handler, &miss);
}
BIND(&miss);
{
TailCallRuntime(Runtime::kStoreGlobalIC_Miss, pp->context, pp->value,
pp->slot, pp->vector, pp->name);
}
}
void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
Node* value,
ExitPoint* exit_point,
......@@ -2745,6 +2780,11 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
LoadObjectField(property_cell, PropertyCell::kValueOffset);
Node* details = LoadAndUntagToWord32ObjectField(property_cell,
PropertyCell::kDetailsOffset);
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
CSA_ASSERT(this,
Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
Int32Constant(kData)));
Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
Label constant(this), store(this), not_smi(this);
......@@ -3041,6 +3081,33 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
KeyedLoadICPolymorphicName(&p);
}
void AccessorAssembler::GenerateStoreGlobalIC() {
typedef StoreGlobalWithVectorDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
StoreICParameters p(context, nullptr, name, value, slot, vector);
StoreGlobalIC(&p);
}
void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
typedef StoreGlobalDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
TailCallStub(callable, context, name, value, slot, vector);
}
void AccessorAssembler::GenerateStoreIC() {
typedef StoreWithVectorDescriptor Descriptor;
......
......@@ -34,6 +34,8 @@ class AccessorAssembler : public CodeStubAssembler {
void GenerateKeyedLoadIC_PolymorphicName();
void GenerateStoreIC();
void GenerateStoreICTrampoline();
void GenerateStoreGlobalIC();
void GenerateStoreGlobalICTrampoline();
void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
......@@ -121,6 +123,7 @@ class AccessorAssembler : public CodeStubAssembler {
void KeyedLoadICGeneric(const LoadICParameters* p);
void KeyedLoadICPolymorphicName(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
void StoreGlobalIC(const StoreICParameters* p);
void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
ExitPoint* exit_point, Label* miss);
void KeyedStoreIC(const StoreICParameters* p);
......
......@@ -255,7 +255,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// This is a contextual access, always just update the handler and stay
// monomorphic.
if (IsLoadGlobalIC()) return true;
if (IsGlobalIC()) return true;
// The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or
......@@ -395,6 +395,11 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
if (IsLoadGlobalIC()) {
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
nexus->ConfigureHandlerMode(handler);
} else if (IsStoreGlobalIC()) {
StoreGlobalICNexus* nexus = casted_nexus<StoreGlobalICNexus>();
nexus->ConfigureHandlerMode(handler);
} else {
// Non-keyed ICs don't track the name explicitly.
if (!is_keyed()) name = Handle<Name>::null();
......@@ -408,7 +413,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
ObjectHandles* handlers) {
DCHECK(!IsLoadGlobalIC());
DCHECK(!IsGlobalIC());
// Non-keyed ICs don't track the name explicitly.
if (!is_keyed()) name = Handle<Name>::null();
nexus()->ConfigurePolymorphic(name, maps, handlers);
......@@ -623,7 +628,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
break;
case RECOMPUTE_HANDLER:
case MONOMORPHIC:
if (IsLoadGlobalIC()) {
if (IsGlobalIC()) {
UpdateMonomorphicIC(handler, name);
break;
}
......@@ -1285,15 +1290,13 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
return it->IsCacheableTransition();
}
MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
Handle<Name> name,
MaybeHandle<Object> StoreGlobalIC::Store(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<JSGlobalObject> global = isolate()->global_object();
Handle<ScriptContextTable> script_contexts(
global->native_context()->script_context_table());
......@@ -1302,7 +1305,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
Handle<Context> script_context = ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index);
if (lookup_result.mode == CONST) {
return TypeError(MessageTemplate::kConstAssign, object, name);
return TypeError(MessageTemplate::kConstAssign, global, name);
}
Handle<Object> previous_value =
......@@ -1324,7 +1327,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
return value;
}
return StoreIC::Store(object, name, value);
return StoreIC::Store(global, name, value);
}
MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
......@@ -1379,7 +1382,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode,
MaybeHandle<Object> cached_handler) {
if (state() == UNINITIALIZED) {
if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
......@@ -1392,6 +1395,17 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
if (!cached_handler.is_null()) {
handler = cached_handler.ToHandleChecked();
} else if (LookupForWrite(lookup, value, store_mode)) {
if (IsStoreGlobalIC()) {
if (lookup->state() == LookupIterator::DATA &&
lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
// Now update the cell in the feedback vector.
StoreGlobalICNexus* nexus = casted_nexus<StoreGlobalICNexus>();
nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
TRACE_IC("StoreGlobalIC", lookup->name());
return;
}
}
if (created_new_transition_) {
// The first time a transition is performed, there's a good chance that
// it won't be taken again, so don't bother creating a handler.
......@@ -2170,10 +2184,12 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else if (IsStoreGlobalICKind(kind)) {
StoreICNexus nexus(vector, vector_slot);
DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
receiver = isolate->global_object();
StoreGlobalICNexus nexus(vector, vector_slot);
StoreGlobalIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
} else {
DCHECK(IsKeyedStoreICKind(kind));
KeyedStoreICNexus nexus(vector, vector_slot);
......@@ -2183,6 +2199,22 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
}
}
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_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<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Name> key = args.at<Name>(3);
FeedbackSlot vector_slot = vector->ToSlot(slot->value());
StoreGlobalICNexus nexus(vector, vector_slot);
StoreGlobalIC ic(isolate, &nexus);
Handle<JSGlobalObject> global = isolate->global_object();
ic.UpdateState(global, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
}
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
......@@ -2190,9 +2222,19 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> object = args.at(3);
CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
#ifdef DEBUG
{
FeedbackSlot vector_slot = vector->ToSlot(slot->value());
FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
DCHECK(IsStoreGlobalICKind(slot_kind));
Handle<Object> receiver = args.at(3);
DCHECK(receiver->IsJSGlobalProxy());
}
#endif
Handle<JSGlobalObject> global = isolate->global_object();
Handle<Context> native_context = isolate->native_context();
Handle<ScriptContextTable> script_contexts(
native_context->script_context_table());
......@@ -2203,7 +2245,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
script_contexts, lookup_result.context_index);
if (lookup_result.mode == CONST) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstAssign, object, name));
isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
}
Handle<Object> previous_value =
......@@ -2222,7 +2264,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, name, value, language_mode));
Runtime::SetObjectProperty(isolate, global, name, value, language_mode));
}
// Used from ic-<arch>.cc.
......@@ -2387,8 +2429,19 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
FeedbackSlot vector_slot = vector->ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
DCHECK(receiver->HasNamedInterceptor());
Handle<InterceptorInfo> interceptor(receiver->GetNamedInterceptor(), isolate);
// TODO(ishell): Cache interceptor_holder in the store handler like we do
// for LoadHandler::kInterceptor case.
Handle<JSObject> interceptor_holder = receiver;
if (receiver->IsJSGlobalProxy()) {
FeedbackSlotKind kind = vector->GetKind(vector_slot);
if (IsStoreGlobalICKind(kind)) {
interceptor_holder = Handle<JSObject>::cast(isolate->global_object());
}
}
DCHECK(interceptor_holder->HasNamedInterceptor());
Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
isolate);
DCHECK(!interceptor->non_masking());
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
*receiver, kDontThrow);
......
......@@ -119,6 +119,7 @@ class IC {
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
void PatchCache(Handle<Name> name, Handle<Object> code);
FeedbackSlotKind kind() const { return kind_; }
bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
bool IsLoadIC() const { return IsLoadICKind(kind_); }
bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
......@@ -339,8 +340,7 @@ class StoreGlobalIC : public StoreIC {
StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
: StoreIC(isolate, nexus) {}
MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
Handle<Name> name,
MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Name> name,
Handle<Object> value);
protected:
......
......@@ -170,6 +170,42 @@ void LoadGlobalWithVectorDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void StoreGlobalDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kName, kValue, kSlot
MachineType machine_types[] = {MachineType::AnyTagged(),
MachineType::AnyTagged(),
MachineType::TaggedSigned()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);
}
void StoreGlobalDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NameRegister(), ValueRegister(), SlotRegister()};
int len = arraysize(registers) - kStackArgumentsCount;
data->InitializePlatformSpecific(len, registers);
}
void StoreGlobalWithVectorDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kName, kValue, kSlot, kVector
MachineType machine_types[] = {
MachineType::AnyTagged(), MachineType::AnyTagged(),
MachineType::TaggedSigned(), MachineType::AnyTagged()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);
}
void StoreGlobalWithVectorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NameRegister(), ValueRegister(), SlotRegister(),
VectorRegister()};
int len = arraysize(registers) - kStackArgumentsCount;
data->InitializePlatformSpecific(len, registers);
}
void StoreDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kReceiver, kName, kValue, kSlot
......
......@@ -29,6 +29,8 @@ class PlatformInterfaceDescriptor;
V(StoreWithVector) \
V(StoreNamedTransition) \
V(StoreTransition) \
V(StoreGlobal) \
V(StoreGlobalWithVector) \
V(FastNewClosure) \
V(FastNewFunctionContext) \
V(FastNewObject) \
......@@ -455,6 +457,44 @@ class StoreWithVectorDescriptor : public StoreDescriptor {
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};
class StoreGlobalDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kName, kValue, kSlot)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(StoreGlobalDescriptor,
CallInterfaceDescriptor)
static const bool kPassLastArgsOnStack =
StoreDescriptor::kPassLastArgsOnStack;
// Pass value and slot through the stack.
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 2 : 0;
static const Register NameRegister() {
return StoreDescriptor::NameRegister();
}
static const Register ValueRegister() {
return StoreDescriptor::ValueRegister();
}
static const Register SlotRegister() {
return StoreDescriptor::SlotRegister();
}
};
class StoreGlobalWithVectorDescriptor : public StoreGlobalDescriptor {
public:
DEFINE_PARAMETERS(kName, kValue, kSlot, kVector)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(StoreGlobalWithVectorDescriptor,
StoreGlobalDescriptor)
static const Register VectorRegister() {
return StoreWithVectorDescriptor::VectorRegister();
}
// Pass value, slot and vector through the stack.
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};
class LoadWithVectorDescriptor : public LoadDescriptor {
public:
DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector)
......
......@@ -254,8 +254,6 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
void StaGlobal(Callable ic) {
// Get the global object.
Node* context = GetContext();
Node* native_context = LoadNativeContext(context);
Node* global = LoadContextElement(native_context, Context::EXTENSION_INDEX);
// Store the global via the StoreIC.
Node* code_target = HeapConstant(ic.code());
......@@ -265,8 +263,8 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
Node* raw_slot = BytecodeOperandIdx(1);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
CallStub(ic.descriptor(), code_target, context, global, name, value,
smi_slot, feedback_vector);
CallStub(ic.descriptor(), code_target, context, name, value, smi_slot,
feedback_vector);
Dispatch();
}
};
......@@ -276,8 +274,7 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
// Store the value in the accumulator into the global with name in constant pool
// entry <name_index> using FeedBackVector slot <slot> in sloppy mode.
IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) {
Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(
isolate(), LanguageMode::kSloppy);
Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
StaGlobal(ic);
}
......@@ -286,8 +283,7 @@ IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) {
// Store the value in the accumulator into the global with name in constant pool
// entry <name_index> using FeedBackVector slot <slot> in strict mode.
IGNITION_HANDLER(StaGlobalStrict, InterpreterStoreGlobalAssembler) {
Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(
isolate(), LanguageMode::kStrict);
Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
StaGlobal(ic);
}
......
......@@ -19135,6 +19135,14 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
details = details.set_cell_type(new_type);
cell->set_property_details(details);
if (new_type == PropertyCellType::kConstant ||
new_type == PropertyCellType::kConstantType) {
// Store the value now to ensure that the cell contains the constant or
// type information. Otherwise subsequent store operation will turn
// the cell to mutable.
cell->set_value(*value);
}
// Deopt when transitioning from a constant type.
if (!invalidate && (old_type != new_type ||
original_details.IsReadOnly() != details.IsReadOnly())) {
......
......@@ -684,6 +684,7 @@ namespace internal {
F(LoadIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \
F(StoreCallbackProperty, 6, 1) \
F(StoreGlobalIC_Miss, 4, 1) \
F(StoreGlobalIC_Slow, 5, 1) \
F(StoreIC_Miss, 5, 1) \
F(StorePropertyWithInterceptor, 5, 1) \
......
......@@ -647,10 +647,32 @@ THREADED_TEST(GlobalObjectAccessor) {
" set : function() { set_value = this; }"
"});"
"function getter() { return x; }"
"function setter() { x = 1; }"
"for (var i = 0; i < 4; i++) { getter(); setter(); }");
CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
"function setter() { x = 1; }");
Local<Script> check_getter = v8_compile("getter()");
Local<Script> check_setter = v8_compile("setter(); set_value");
// Ensure that LoadGlobalICs in getter and StoreGlobalICs setter get
// JSGlobalProxy as a receiver regardless of the current IC state and
// the order in which ICs are executed.
for (int i = 0; i < 10; i++) {
CHECK(
v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
->IsJSGlobalProxy());
}
for (int i = 0; i < 10; i++) {
CHECK(
v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
->IsJSGlobalProxy());
}
for (int i = 0; i < 10; i++) {
CHECK(
v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
->IsJSGlobalProxy());
CHECK(
v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
->IsJSGlobalProxy());
}
}
......
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