[ic] Update Clone/StoreInArrayLiteral builtins to handle no feedback case
Updates CloneIC builtin to take the CloneIC_slow path when there is no feedback vector. Also fixes the CloneIC_Slow to handle proxies correctly. StoreInArrayLiteralIC doesn't change the behaviour but just makes it consistent with other ICs. Bug: v8:8293 Change-Id: Ib824b3ef06db1595ce06f04669857bb957cbe072 Reviewed-on: https://chromium-review.googlesource.com/c/1475750 Commit-Queue: Mythri Alle <mythria@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#59682}
This commit is contained in:
parent
e4ca64ded6
commit
a508efa61d
@ -297,6 +297,8 @@ Node* ConstructorBuiltinsAssembler::EmitCreateRegExpLiteral(
|
||||
Node* context) {
|
||||
Label call_runtime(this, Label::kDeferred), end(this);
|
||||
|
||||
GotoIf(IsUndefined(feedback_vector), &call_runtime);
|
||||
|
||||
VARIABLE(result, MachineRepresentation::kTagged);
|
||||
TNode<Object> literal_site =
|
||||
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
|
||||
|
@ -3092,6 +3092,9 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
|
||||
|
||||
Node* array_map = LoadReceiverMap(p->receiver);
|
||||
GotoIf(IsDeprecatedMap(array_map), &miss);
|
||||
|
||||
GotoIf(IsUndefined(p->vector), &miss);
|
||||
|
||||
TNode<MaybeObject> feedback =
|
||||
TryMonomorphicCase(p->slot, p->vector, array_map, &if_handler,
|
||||
&var_handler, &try_polymorphic);
|
||||
@ -3497,6 +3500,7 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() {
|
||||
{
|
||||
Label cont(this);
|
||||
GotoIf(IsJSObjectInstanceType(type), &cont);
|
||||
GotoIf(InstanceTypeEqual(type, JS_PROXY_TYPE), &call_runtime);
|
||||
GotoIfNot(IsStringInstanceType(type), &done);
|
||||
Branch(SmiEqual(LoadStringLengthAsSmi(CAST(source)), SmiConstant(0)), &done,
|
||||
&call_runtime);
|
||||
@ -3531,10 +3535,13 @@ void AccessorAssembler::GenerateCloneObjectIC() {
|
||||
TVARIABLE(MaybeObject, var_handler);
|
||||
Label if_handler(this, &var_handler);
|
||||
Label miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
|
||||
try_megamorphic(this, Label::kDeferred);
|
||||
try_megamorphic(this, Label::kDeferred), slow(this, Label::kDeferred);
|
||||
|
||||
TNode<Map> source_map = LoadMap(UncheckedCast<HeapObject>(source));
|
||||
GotoIf(IsDeprecatedMap(source_map), &miss);
|
||||
|
||||
GotoIf(IsUndefined(vector), &slow);
|
||||
|
||||
TNode<MaybeObject> feedback = TryMonomorphicCase(
|
||||
slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
|
||||
|
||||
@ -3651,6 +3658,11 @@ void AccessorAssembler::GenerateCloneObjectIC() {
|
||||
GotoIfNot(
|
||||
WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
|
||||
&miss);
|
||||
Goto(&slow);
|
||||
}
|
||||
|
||||
BIND(&slow);
|
||||
{
|
||||
TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot,
|
||||
vector);
|
||||
}
|
||||
|
@ -694,19 +694,8 @@ IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
|
||||
Node* context = GetContext();
|
||||
|
||||
VARIABLE(var_result, MachineRepresentation::kTagged);
|
||||
Label no_feedback(this, Label::kDeferred), end(this);
|
||||
GotoIf(IsUndefined(feedback_vector), &no_feedback);
|
||||
|
||||
var_result.Bind(CallBuiltin(Builtins::kStoreInArrayLiteralIC, context, array,
|
||||
index, value, smi_slot, feedback_vector));
|
||||
Goto(&end);
|
||||
|
||||
BIND(&no_feedback);
|
||||
var_result.Bind(CallRuntime(Runtime::kStoreInArrayLiteralIC_Miss, context,
|
||||
value, smi_slot, feedback_vector, array, index));
|
||||
Goto(&end);
|
||||
|
||||
BIND(&end);
|
||||
// To avoid special logic in the deoptimizer to re-materialize the value in
|
||||
// the accumulator, we overwrite the accumulator after the IC call. It
|
||||
// doesn't really matter what we write to the accumulator here, since we
|
||||
@ -2432,22 +2421,10 @@ IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
|
||||
Node* context = GetContext();
|
||||
|
||||
VARIABLE(result, MachineRepresentation::kTagged);
|
||||
Label no_feedback(this, Label::kDeferred), end(this);
|
||||
GotoIf(IsUndefined(feedback_vector), &no_feedback);
|
||||
|
||||
ConstructorBuiltinsAssembler constructor_assembler(state());
|
||||
result.Bind(constructor_assembler.EmitCreateRegExpLiteral(
|
||||
feedback_vector, slot_id, pattern, flags, context));
|
||||
Goto(&end);
|
||||
|
||||
BIND(&no_feedback);
|
||||
{
|
||||
result.Bind(CallRuntime(Runtime::kCreateRegExpLiteral, context,
|
||||
feedback_vector, SmiTag(slot_id), pattern, flags));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
SetAccumulator(result.value());
|
||||
Dispatch();
|
||||
}
|
||||
@ -2613,18 +2590,8 @@ IGNITION_HANDLER(CloneObject, InterpreterAssembler) {
|
||||
Node* context = GetContext();
|
||||
|
||||
Variable var_result(this, MachineRepresentation::kTagged);
|
||||
Label no_feedback(this), end(this);
|
||||
GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
|
||||
var_result.Bind(CallBuiltin(Builtins::kCloneObjectIC, context, source,
|
||||
smi_flags, smi_slot, maybe_feedback_vector));
|
||||
Goto(&end);
|
||||
|
||||
BIND(&no_feedback);
|
||||
var_result.Bind(CallRuntime(Runtime::kCloneObjectIC_Miss, context, source,
|
||||
smi_flags, smi_slot, maybe_feedback_vector));
|
||||
Goto(&end);
|
||||
|
||||
BIND(&end);
|
||||
SetAccumulator(var_result.value());
|
||||
Dispatch();
|
||||
}
|
||||
|
25
test/mjsunit/es6/proxies-ownkeys-clone.js
Normal file
25
test/mjsunit/es6/proxies-ownkeys-clone.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
var p = new Proxy({a: 1, b: 2}, {
|
||||
ownKeys() { return ['a', 'b']; }
|
||||
});
|
||||
|
||||
// clone and return a
|
||||
function f(a) {
|
||||
var y = {...a}
|
||||
return y;
|
||||
}
|
||||
|
||||
// Call with different maps to force it into megamorphic state
|
||||
f({a: 1, b: 2});
|
||||
f({a1: 1, b1: 3});
|
||||
f({a2: 1, b2: 3});
|
||||
f({a3: 1, b3: 4});
|
||||
f({a4: 1, b4: 5});
|
||||
|
||||
// Test that y was initialized correctly in the slow path
|
||||
var clone = f(p);
|
||||
assertEquals(clone.a, 1);
|
||||
assertEquals(clone.b, 2);
|
Loading…
Reference in New Issue
Block a user