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 { ...@@ -572,6 +572,8 @@ namespace internal {
TFH(LoadICTrampoline, Load) \ TFH(LoadICTrampoline, Load) \
TFH(KeyedLoadIC, LoadWithVector) \ TFH(KeyedLoadIC, LoadWithVector) \
TFH(KeyedLoadICTrampoline, Load) \ TFH(KeyedLoadICTrampoline, Load) \
TFH(StoreGlobalIC, StoreGlobalWithVector) \
TFH(StoreGlobalICTrampoline, StoreGlobal) \
TFH(StoreIC, StoreWithVector) \ TFH(StoreIC, StoreWithVector) \
TFH(StoreICTrampoline, Store) \ TFH(StoreICTrampoline, Store) \
TFH(KeyedStoreIC, StoreWithVector) \ TFH(KeyedStoreIC, StoreWithVector) \
......
...@@ -29,6 +29,8 @@ IC_BUILTIN(LoadField) ...@@ -29,6 +29,8 @@ IC_BUILTIN(LoadField)
IC_BUILTIN(KeyedLoadICTrampoline) IC_BUILTIN(KeyedLoadICTrampoline)
IC_BUILTIN(KeyedLoadIC_Megamorphic) IC_BUILTIN(KeyedLoadIC_Megamorphic)
IC_BUILTIN(KeyedLoadIC_PolymorphicName) IC_BUILTIN(KeyedLoadIC_PolymorphicName)
IC_BUILTIN(StoreGlobalIC)
IC_BUILTIN(StoreGlobalICTrampoline)
IC_BUILTIN(StoreIC) IC_BUILTIN(StoreIC)
IC_BUILTIN(StoreICTrampoline) IC_BUILTIN(StoreICTrampoline)
IC_BUILTIN(KeyedStoreIC) IC_BUILTIN(KeyedStoreIC)
......
...@@ -83,22 +83,6 @@ Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) { ...@@ -83,22 +83,6 @@ Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) {
StoreWithVectorDescriptor(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 // static
Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) { Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
switch (op) { switch (op) {
......
...@@ -28,9 +28,6 @@ class V8_EXPORT_PRIVATE CodeFactory final { ...@@ -28,9 +28,6 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode); static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode);
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate, static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
TypeofMode typeof_mode); TypeofMode typeof_mode);
static Callable StoreGlobalIC(Isolate* isolate, LanguageMode mode);
static Callable StoreGlobalICInOptimizedCode(Isolate* isolate,
LanguageMode mode);
static Callable StoreOwnIC(Isolate* isolate); static Callable StoreOwnIC(Isolate* isolate);
static Callable StoreOwnICInOptimizedCode(Isolate* isolate); static Callable StoreOwnICInOptimizedCode(Isolate* isolate);
......
...@@ -251,32 +251,17 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) { ...@@ -251,32 +251,17 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op()); const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
Node* frame_state = NodeProperties::GetFrameStateInput(node); Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
Node* context = NodeProperties::GetContextInput(node); node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
Node* effect = NodeProperties::GetEffectInput(node); node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
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()));
if (outer_state->opcode() != IrOpcode::kFrameState) { if (outer_state->opcode() != IrOpcode::kFrameState) {
Callable callable = Callable callable =
CodeFactory::StoreGlobalIC(isolate(), p.language_mode()); Builtins::CallableFor(isolate(), Builtins::kStoreGlobalICTrampoline);
ReplaceWithStubCall(node, callable, flags); ReplaceWithStubCall(node, callable, flags);
} else { } else {
Callable callable = Callable callable =
CodeFactory::StoreGlobalICInOptimizedCode(isolate(), p.language_mode()); Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
Node* vector = jsgraph()->HeapConstant(p.feedback().vector()); Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
node->InsertInput(zone(), 4, vector); node->InsertInput(zone(), 3, vector);
ReplaceWithStubCall(node, callable, flags); ReplaceWithStubCall(node, callable, flags);
} }
} }
......
...@@ -255,6 +255,8 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate, ...@@ -255,6 +255,8 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
switch (kind) { switch (kind) {
case FeedbackSlotKind::kLoadGlobalInsideTypeof: case FeedbackSlotKind::kLoadGlobalInsideTypeof:
case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
case FeedbackSlotKind::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict:
vector->set(index, isolate->heap()->empty_weak_cell(), vector->set(index, isolate->heap()->empty_weak_cell(),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
break; break;
...@@ -280,8 +282,6 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate, ...@@ -280,8 +282,6 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedSloppy:
case FeedbackSlotKind::kStoreNamedStrict: case FeedbackSlotKind::kStoreNamedStrict:
case FeedbackSlotKind::kStoreOwnNamed: case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict:
case FeedbackSlotKind::kStoreKeyedSloppy: case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict: case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreDataPropertyInLiteral: case FeedbackSlotKind::kStoreDataPropertyInLiteral:
...@@ -432,10 +432,17 @@ bool FeedbackVector::ClearSlots(Isolate* isolate) { ...@@ -432,10 +432,17 @@ bool FeedbackVector::ClearSlots(Isolate* isolate) {
} }
case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedSloppy:
case FeedbackSlotKind::kStoreNamedStrict: 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::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict: { case FeedbackSlotKind::kStoreGlobalStrict: {
StoreICNexus nexus(this, slot); StoreGlobalICNexus nexus(this, slot);
if (!nexus.IsCleared()) { if (!nexus.IsCleared()) {
nexus.Clear(); nexus.Clear();
feedback_updated = true; feedback_updated = true;
...@@ -610,6 +617,37 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const { ...@@ -610,6 +617,37 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
return UNINITIALIZED; 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 { InlineCacheState StoreICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback(); Object* feedback = GetFeedback();
......
...@@ -728,13 +728,11 @@ class StoreICNexus : public FeedbackNexus { ...@@ -728,13 +728,11 @@ class StoreICNexus : public FeedbackNexus {
public: public:
StoreICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot) StoreICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: FeedbackNexus(vector, 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) StoreICNexus(FeedbackVector* vector, FeedbackSlot slot)
: FeedbackNexus(vector, 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(); } void Clear() override { ConfigurePremonomorphic(); }
...@@ -742,6 +740,35 @@ class StoreICNexus : public FeedbackNexus { ...@@ -742,6 +740,35 @@ class StoreICNexus : public FeedbackNexus {
InlineCacheState StateFromFeedback() const override; 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 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
// already exist in the boilerplate therefore we can use StoreIC. // already exist in the boilerplate therefore we can use StoreIC.
typedef StoreICNexus StoreOwnICNexus; typedef StoreICNexus StoreOwnICNexus;
......
...@@ -2731,6 +2731,41 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { ...@@ -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, void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
Node* value, Node* value,
ExitPoint* exit_point, ExitPoint* exit_point,
...@@ -2745,6 +2780,11 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell, ...@@ -2745,6 +2780,11 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
LoadObjectField(property_cell, PropertyCell::kValueOffset); LoadObjectField(property_cell, PropertyCell::kValueOffset);
Node* details = LoadAndUntagToWord32ObjectField(property_cell, Node* details = LoadAndUntagToWord32ObjectField(property_cell,
PropertyCell::kDetailsOffset); PropertyCell::kDetailsOffset);
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
CSA_ASSERT(this,
Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
Int32Constant(kData)));
Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details); Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
Label constant(this), store(this), not_smi(this); Label constant(this), store(this), not_smi(this);
...@@ -3041,6 +3081,33 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() { ...@@ -3041,6 +3081,33 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
KeyedLoadICPolymorphicName(&p); 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() { void AccessorAssembler::GenerateStoreIC() {
typedef StoreWithVectorDescriptor Descriptor; typedef StoreWithVectorDescriptor Descriptor;
......
...@@ -34,6 +34,8 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -34,6 +34,8 @@ class AccessorAssembler : public CodeStubAssembler {
void GenerateKeyedLoadIC_PolymorphicName(); void GenerateKeyedLoadIC_PolymorphicName();
void GenerateStoreIC(); void GenerateStoreIC();
void GenerateStoreICTrampoline(); void GenerateStoreICTrampoline();
void GenerateStoreGlobalIC();
void GenerateStoreGlobalICTrampoline();
void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent); void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
...@@ -121,6 +123,7 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -121,6 +123,7 @@ class AccessorAssembler : public CodeStubAssembler {
void KeyedLoadICGeneric(const LoadICParameters* p); void KeyedLoadICGeneric(const LoadICParameters* p);
void KeyedLoadICPolymorphicName(const LoadICParameters* p); void KeyedLoadICPolymorphicName(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p); void StoreIC(const StoreICParameters* p);
void StoreGlobalIC(const StoreICParameters* p);
void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value, void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
ExitPoint* exit_point, Label* miss); ExitPoint* exit_point, Label* miss);
void KeyedStoreIC(const StoreICParameters* p); void KeyedStoreIC(const StoreICParameters* p);
......
...@@ -255,7 +255,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) { ...@@ -255,7 +255,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// This is a contextual access, always just update the handler and stay // This is a contextual access, always just update the handler and stay
// monomorphic. // monomorphic.
if (IsLoadGlobalIC()) return true; if (IsGlobalIC()) return true;
// The current map wasn't handled yet. There's no reason to stay monomorphic, // 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 // *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, ...@@ -395,6 +395,11 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
if (IsLoadGlobalIC()) { if (IsLoadGlobalIC()) {
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
nexus->ConfigureHandlerMode(handler); nexus->ConfigureHandlerMode(handler);
} else if (IsStoreGlobalIC()) {
StoreGlobalICNexus* nexus = casted_nexus<StoreGlobalICNexus>();
nexus->ConfigureHandlerMode(handler);
} else { } else {
// Non-keyed ICs don't track the name explicitly. // Non-keyed ICs don't track the name explicitly.
if (!is_keyed()) name = Handle<Name>::null(); if (!is_keyed()) name = Handle<Name>::null();
...@@ -408,7 +413,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, ...@@ -408,7 +413,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps, void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
ObjectHandles* handlers) { ObjectHandles* handlers) {
DCHECK(!IsLoadGlobalIC()); DCHECK(!IsGlobalIC());
// Non-keyed ICs don't track the name explicitly. // Non-keyed ICs don't track the name explicitly.
if (!is_keyed()) name = Handle<Name>::null(); if (!is_keyed()) name = Handle<Name>::null();
nexus()->ConfigurePolymorphic(name, maps, handlers); nexus()->ConfigurePolymorphic(name, maps, handlers);
...@@ -623,7 +628,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { ...@@ -623,7 +628,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
break; break;
case RECOMPUTE_HANDLER: case RECOMPUTE_HANDLER:
case MONOMORPHIC: case MONOMORPHIC:
if (IsLoadGlobalIC()) { if (IsGlobalIC()) {
UpdateMonomorphicIC(handler, name); UpdateMonomorphicIC(handler, name);
break; break;
} }
...@@ -1285,15 +1290,13 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, ...@@ -1285,15 +1290,13 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
return it->IsCacheableTransition(); return it->IsCacheableTransition();
} }
MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object, MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
Handle<Name> name,
Handle<Object> value) { Handle<Object> value) {
DCHECK(object->IsJSGlobalObject());
DCHECK(name->IsString()); DCHECK(name->IsString());
// Look up in script context table. // Look up in script context table.
Handle<String> str_name = Handle<String>::cast(name); 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( Handle<ScriptContextTable> script_contexts(
global->native_context()->script_context_table()); global->native_context()->script_context_table());
...@@ -1302,7 +1305,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object, ...@@ -1302,7 +1305,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
Handle<Context> script_context = ScriptContextTable::GetContext( Handle<Context> script_context = ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index); script_contexts, lookup_result.context_index);
if (lookup_result.mode == CONST) { if (lookup_result.mode == CONST) {
return TypeError(MessageTemplate::kConstAssign, object, name); return TypeError(MessageTemplate::kConstAssign, global, name);
} }
Handle<Object> previous_value = Handle<Object> previous_value =
...@@ -1324,7 +1327,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object, ...@@ -1324,7 +1327,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
return value; return value;
} }
return StoreIC::Store(object, name, value); return StoreIC::Store(global, name, value);
} }
MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
...@@ -1379,7 +1382,7 @@ 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, void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode, JSReceiver::StoreFromKeyed store_mode,
MaybeHandle<Object> cached_handler) { 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 // This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state. // the pre monomorphic stub to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic); TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
...@@ -1392,6 +1395,17 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, ...@@ -1392,6 +1395,17 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
if (!cached_handler.is_null()) { if (!cached_handler.is_null()) {
handler = cached_handler.ToHandleChecked(); handler = cached_handler.ToHandleChecked();
} else if (LookupForWrite(lookup, value, store_mode)) { } 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_) { if (created_new_transition_) {
// The first time a transition is performed, there's a good chance that // 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. // it won't be taken again, so don't bother creating a handler.
...@@ -2170,10 +2184,12 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { ...@@ -2170,10 +2184,12 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
ic.UpdateState(receiver, key); ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else if (IsStoreGlobalICKind(kind)) { } 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); StoreGlobalIC ic(isolate, &nexus);
ic.UpdateState(receiver, key); ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
} else { } else {
DCHECK(IsKeyedStoreICKind(kind)); DCHECK(IsKeyedStoreICKind(kind));
KeyedStoreICNexus nexus(vector, vector_slot); KeyedStoreICNexus nexus(vector, vector_slot);
...@@ -2183,6 +2199,22 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { ...@@ -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) { RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(5, args.length()); DCHECK_EQ(5, args.length());
...@@ -2190,9 +2222,19 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { ...@@ -2190,9 +2222,19 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
Handle<Object> value = args.at(0); Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1); Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> object = args.at(3);
CONVERT_ARG_HANDLE_CHECKED(String, name, 4); 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<Context> native_context = isolate->native_context();
Handle<ScriptContextTable> script_contexts( Handle<ScriptContextTable> script_contexts(
native_context->script_context_table()); native_context->script_context_table());
...@@ -2203,7 +2245,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { ...@@ -2203,7 +2245,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
script_contexts, lookup_result.context_index); script_contexts, lookup_result.context_index);
if (lookup_result.mode == CONST) { if (lookup_result.mode == CONST) {
THROW_NEW_ERROR_RETURN_FAILURE( THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstAssign, object, name)); isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
} }
Handle<Object> previous_value = Handle<Object> previous_value =
...@@ -2222,7 +2264,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { ...@@ -2222,7 +2264,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
LanguageMode language_mode = vector->GetLanguageMode(vector_slot); LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(
isolate, isolate,
Runtime::SetObjectProperty(isolate, object, name, value, language_mode)); Runtime::SetObjectProperty(isolate, global, name, value, language_mode));
} }
// Used from ic-<arch>.cc. // Used from ic-<arch>.cc.
...@@ -2387,8 +2429,19 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { ...@@ -2387,8 +2429,19 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
FeedbackSlot vector_slot = vector->ToSlot(slot->value()); FeedbackSlot vector_slot = vector->ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot); LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
DCHECK(receiver->HasNamedInterceptor()); // TODO(ishell): Cache interceptor_holder in the store handler like we do
Handle<InterceptorInfo> interceptor(receiver->GetNamedInterceptor(), isolate); // 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()); DCHECK(!interceptor->non_masking());
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
*receiver, kDontThrow); *receiver, kDontThrow);
......
...@@ -119,6 +119,7 @@ class IC { ...@@ -119,6 +119,7 @@ class IC {
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map); bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
void PatchCache(Handle<Name> name, Handle<Object> code); void PatchCache(Handle<Name> name, Handle<Object> code);
FeedbackSlotKind kind() const { return kind_; } FeedbackSlotKind kind() const { return kind_; }
bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
bool IsLoadIC() const { return IsLoadICKind(kind_); } bool IsLoadIC() const { return IsLoadICKind(kind_); }
bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); } bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); } bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
...@@ -339,8 +340,7 @@ class StoreGlobalIC : public StoreIC { ...@@ -339,8 +340,7 @@ class StoreGlobalIC : public StoreIC {
StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus) StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
: StoreIC(isolate, nexus) {} : StoreIC(isolate, nexus) {}
MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object, MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Name> name,
Handle<Name> name,
Handle<Object> value); Handle<Object> value);
protected: protected:
......
...@@ -170,6 +170,42 @@ void LoadGlobalWithVectorDescriptor::InitializePlatformSpecific( ...@@ -170,6 +170,42 @@ void LoadGlobalWithVectorDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); 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( void StoreDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// kReceiver, kName, kValue, kSlot // kReceiver, kName, kValue, kSlot
......
...@@ -29,6 +29,8 @@ class PlatformInterfaceDescriptor; ...@@ -29,6 +29,8 @@ class PlatformInterfaceDescriptor;
V(StoreWithVector) \ V(StoreWithVector) \
V(StoreNamedTransition) \ V(StoreNamedTransition) \
V(StoreTransition) \ V(StoreTransition) \
V(StoreGlobal) \
V(StoreGlobalWithVector) \
V(FastNewClosure) \ V(FastNewClosure) \
V(FastNewFunctionContext) \ V(FastNewFunctionContext) \
V(FastNewObject) \ V(FastNewObject) \
...@@ -455,6 +457,44 @@ class StoreWithVectorDescriptor : public StoreDescriptor { ...@@ -455,6 +457,44 @@ class StoreWithVectorDescriptor : public StoreDescriptor {
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0; 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 { class LoadWithVectorDescriptor : public LoadDescriptor {
public: public:
DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector) DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector)
......
...@@ -254,8 +254,6 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler { ...@@ -254,8 +254,6 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
void StaGlobal(Callable ic) { void StaGlobal(Callable ic) {
// Get the global object. // Get the global object.
Node* context = GetContext(); Node* context = GetContext();
Node* native_context = LoadNativeContext(context);
Node* global = LoadContextElement(native_context, Context::EXTENSION_INDEX);
// Store the global via the StoreIC. // Store the global via the StoreIC.
Node* code_target = HeapConstant(ic.code()); Node* code_target = HeapConstant(ic.code());
...@@ -265,8 +263,8 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler { ...@@ -265,8 +263,8 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
Node* raw_slot = BytecodeOperandIdx(1); Node* raw_slot = BytecodeOperandIdx(1);
Node* smi_slot = SmiTag(raw_slot); Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector(); Node* feedback_vector = LoadFeedbackVector();
CallStub(ic.descriptor(), code_target, context, global, name, value, CallStub(ic.descriptor(), code_target, context, name, value, smi_slot,
smi_slot, feedback_vector); feedback_vector);
Dispatch(); Dispatch();
} }
}; };
...@@ -276,8 +274,7 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler { ...@@ -276,8 +274,7 @@ class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
// Store the value in the accumulator into the global with name in constant pool // Store the value in the accumulator into the global with name in constant pool
// entry <name_index> using FeedBackVector slot <slot> in sloppy mode. // entry <name_index> using FeedBackVector slot <slot> in sloppy mode.
IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) { IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) {
Callable ic = CodeFactory::StoreGlobalICInOptimizedCode( Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
isolate(), LanguageMode::kSloppy);
StaGlobal(ic); StaGlobal(ic);
} }
...@@ -286,8 +283,7 @@ IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) { ...@@ -286,8 +283,7 @@ IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) {
// Store the value in the accumulator into the global with name in constant pool // Store the value in the accumulator into the global with name in constant pool
// entry <name_index> using FeedBackVector slot <slot> in strict mode. // entry <name_index> using FeedBackVector slot <slot> in strict mode.
IGNITION_HANDLER(StaGlobalStrict, InterpreterStoreGlobalAssembler) { IGNITION_HANDLER(StaGlobalStrict, InterpreterStoreGlobalAssembler) {
Callable ic = CodeFactory::StoreGlobalICInOptimizedCode( Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
isolate(), LanguageMode::kStrict);
StaGlobal(ic); StaGlobal(ic);
} }
......
...@@ -19135,6 +19135,14 @@ Handle<PropertyCell> PropertyCell::PrepareForValue( ...@@ -19135,6 +19135,14 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
details = details.set_cell_type(new_type); details = details.set_cell_type(new_type);
cell->set_property_details(details); 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. // Deopt when transitioning from a constant type.
if (!invalidate && (old_type != new_type || if (!invalidate && (old_type != new_type ||
original_details.IsReadOnly() != details.IsReadOnly())) { original_details.IsReadOnly() != details.IsReadOnly())) {
......
...@@ -684,6 +684,7 @@ namespace internal { ...@@ -684,6 +684,7 @@ namespace internal {
F(LoadIC_Miss, 4, 1) \ F(LoadIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \ F(LoadPropertyWithInterceptor, 5, 1) \
F(StoreCallbackProperty, 6, 1) \ F(StoreCallbackProperty, 6, 1) \
F(StoreGlobalIC_Miss, 4, 1) \
F(StoreGlobalIC_Slow, 5, 1) \ F(StoreGlobalIC_Slow, 5, 1) \
F(StoreIC_Miss, 5, 1) \ F(StoreIC_Miss, 5, 1) \
F(StorePropertyWithInterceptor, 5, 1) \ F(StorePropertyWithInterceptor, 5, 1) \
......
...@@ -647,10 +647,32 @@ THREADED_TEST(GlobalObjectAccessor) { ...@@ -647,10 +647,32 @@ THREADED_TEST(GlobalObjectAccessor) {
" set : function() { set_value = this; }" " set : function() { set_value = this; }"
"});" "});"
"function getter() { return x; }" "function getter() { return x; }"
"function setter() { x = 1; }" "function setter() { x = 1; }");
"for (var i = 0; i < 4; i++) { getter(); setter(); }");
CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy()); Local<Script> check_getter = v8_compile("getter()");
CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy()); 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