Commit e1591bbd authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Support multiple receiver maps in Array.prototype.pop/shift

Bug: v8:7205
Change-Id: I3de97ca0990ca4d791c990eee7e23f29a75eff31
Reviewed-on: https://chromium-review.googlesource.com/856558
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50534}
parent 557e79ca
......@@ -3703,99 +3703,126 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
// ES6 section 22.1.3.17 Array.prototype.pop ( )
Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
Handle<Map> receiver_map;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
if (NodeProperties::GetMapWitness(node).ToHandle(&receiver_map) &&
CanInlineArrayResizeOperation(receiver_map) &&
receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
// Load the "length" property of the {receiver}.
Node* length = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
receiver, effect, control);
// Check if the {receiver} has any elements.
Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
jsgraph()->ZeroConstant());
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
Node* vfalse;
{
// TODO(tebbi): We should trim the backing store if the capacity is too
// big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> receiver_map : receiver_maps) {
if (!CanInlineArrayResizeOperation(receiver_map)) return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
return NoChange();
if (!UnionElementsKindUptoPackedness(&kind, receiver_map->elements_kind()))
return NoChange();
}
// Load the elements backing store from the {receiver}.
Node* elements = efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
receiver, efalse, if_false);
// Install code dependencies on the {receiver} global array protector cell.
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
// Ensure that we aren't popping from a copy-on-write backing store.
if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
elements = efalse =
graph()->NewNode(simplified()->EnsureWritableFastElements(),
receiver, elements, efalse, if_false);
}
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
if (result == NodeProperties::kUnreliableReceiverMaps) {
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
}
// Compute the new {length}.
length = graph()->NewNode(simplified()->NumberSubtract(), length,
jsgraph()->OneConstant());
// Load the "length" property of the {receiver}.
Node* length = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
effect, control);
// Store the new {length} to the {receiver}.
efalse = graph()->NewNode(
simplified()->StoreField(
AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
receiver, length, efalse, if_false);
// Check if the {receiver} has any elements.
Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
jsgraph()->ZeroConstant());
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
// Load the last entry from the {elements}.
vfalse = efalse = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
receiver_map->elements_kind())),
elements, length, efalse, if_false);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->UndefinedConstant();
// Store a hole to the element we just removed from the {receiver}.
efalse = graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
GetHoleyElementsKind(receiver_map->elements_kind()))),
elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
}
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
Node* vfalse;
{
// TODO(tebbi): We should trim the backing store if the capacity is too
// big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control);
// Load the elements backing store from the {receiver}.
Node* elements = efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
efalse, if_false);
// Convert the hole to undefined. Do this last, so that we can optimize
// conversion operator via some smart strength reduction in many cases.
if (IsHoleyElementsKind(receiver_map->elements_kind())) {
value =
graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
// Ensure that we aren't popping from a copy-on-write backing store.
if (IsSmiOrObjectElementsKind(kind)) {
elements = efalse =
graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver,
elements, efalse, if_false);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
// Compute the new {length}.
length = graph()->NewNode(simplified()->NumberSubtract(), length,
jsgraph()->OneConstant());
// Store the new {length} to the {receiver}.
efalse = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
receiver, length, efalse, if_false);
// Load the last entry from the {elements}.
vfalse = efalse = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
elements, length, efalse, if_false);
// Store a hole to the element we just removed from the {receiver}.
efalse = graph()->NewNode(
simplified()->StoreElement(
AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
}
return NoChange();
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
Node* value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
// Convert the hole to undefined. Do this last, so that we can optimize
// conversion operator via some smart strength reduction in many cases.
if (IsHoleyElementsKind(kind)) {
value =
graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// ES6 section 22.1.3.22 Array.prototype.shift ( )
Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
Node* target = NodeProperties::GetValueInput(node, 0);
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -3804,151 +3831,165 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
Handle<Map> receiver_map;
if (NodeProperties::GetMapWitness(node).ToHandle(&receiver_map) &&
CanInlineArrayResizeOperation(receiver_map) &&
receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
// Load length of the {receiver}.
Node* length = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
receiver, effect, control);
// Return undefined if {receiver} has no elements.
Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
jsgraph()->ZeroConstant());
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
Node* vtrue0 = jsgraph()->UndefinedConstant();
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0 = effect;
Node* vfalse0;
{
// Check if we should take the fast-path.
Node* check1 =
graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
jsgraph()->Constant(JSArray::kMaxCopyElements));
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* etrue1 = efalse0;
Node* vtrue1;
{
Node* elements = etrue1 = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
receiver, etrue1, if_true1);
// Load the first element here, which we return below.
vtrue1 = etrue1 = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
receiver_map->elements_kind())),
elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
// Ensure that we aren't shifting a copy-on-write backing store.
if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
elements = etrue1 =
graph()->NewNode(simplified()->EnsureWritableFastElements(),
receiver, elements, etrue1, if_true1);
}
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
// Shift the remaining {elements} by one towards the start.
Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
Node* eloop =
graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
Node* index = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2),
jsgraph()->OneConstant(),
jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
{
Node* check2 =
graph()->NewNode(simplified()->NumberLessThan(), index, length);
Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
etrue1 = eloop;
Node* control = graph()->NewNode(common()->IfTrue(), branch2);
Node* effect = etrue1;
ElementAccess const access = AccessBuilder::ForFixedArrayElement(
receiver_map->elements_kind());
Node* value = effect =
graph()->NewNode(simplified()->LoadElement(access), elements,
index, effect, control);
effect = graph()->NewNode(
simplified()->StoreElement(access), elements,
graph()->NewNode(simplified()->NumberSubtract(), index,
jsgraph()->OneConstant()),
value, effect, control);
loop->ReplaceInput(1, control);
eloop->ReplaceInput(1, effect);
index->ReplaceInput(1,
graph()->NewNode(simplified()->NumberAdd(), index,
jsgraph()->OneConstant()));
}
ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> receiver_map : receiver_maps) {
if (!CanInlineArrayResizeOperation(receiver_map)) return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
return NoChange();
if (!UnionElementsKindUptoPackedness(&kind, receiver_map->elements_kind()))
return NoChange();
}
// Compute the new {length}.
length = graph()->NewNode(simplified()->NumberSubtract(), length,
jsgraph()->OneConstant());
// Install code dependencies on the {receiver} global array protector cell.
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
// Store the new {length} to the {receiver}.
etrue1 = graph()->NewNode(
simplified()->StoreField(
AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
receiver, length, etrue1, if_true1);
// Store a hole to the element we just removed from the {receiver}.
etrue1 = graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
GetHoleyElementsKind(receiver_map->elements_kind()))),
elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
if (result == NodeProperties::kUnreliableReceiverMaps) {
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
}
// Load length of the {receiver}.
Node* length = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
effect, control);
// Return undefined if {receiver} has no elements.
Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
jsgraph()->ZeroConstant());
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
Node* vtrue0 = jsgraph()->UndefinedConstant();
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0 = effect;
Node* vfalse0;
{
// Check if we should take the fast-path.
Node* check1 =
graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
jsgraph()->Constant(JSArray::kMaxCopyElements));
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* etrue1 = efalse0;
Node* vtrue1;
{
Node* elements = etrue1 = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
receiver, etrue1, if_true1);
// Load the first element here, which we return below.
vtrue1 = etrue1 = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
// Ensure that we aren't shifting a copy-on-write backing store.
if (IsSmiOrObjectElementsKind(kind)) {
elements = etrue1 =
graph()->NewNode(simplified()->EnsureWritableFastElements(),
receiver, elements, etrue1, if_true1);
}
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* efalse1 = efalse0;
Node* vfalse1;
// Shift the remaining {elements} by one towards the start.
Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
Node* eloop =
graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
Node* index = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2),
jsgraph()->OneConstant(),
jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
{
// Call the generic C++ implementation.
const int builtin_index = Builtins::kArrayShift;
CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor(
graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
Builtins::name(builtin_index), node->op()->properties(),
CallDescriptor::kNeedsFrameState);
Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs,
kArgvOnStack, true);
Address builtin_entry = Builtins::CppEntryOf(builtin_index);
Node* entry = jsgraph()->ExternalConstant(
ExternalReference(builtin_entry, isolate()));
Node* argc =
jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
if_false1 = efalse1 = vfalse1 =
graph()->NewNode(common()->Call(desc), stub_code, receiver,
jsgraph()->PaddingConstant(), argc, target,
jsgraph()->UndefinedConstant(), entry, argc,
context, frame_state, efalse1, if_false1);
Node* check2 =
graph()->NewNode(simplified()->NumberLessThan(), index, length);
Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
etrue1 = eloop;
Node* control = graph()->NewNode(common()->IfTrue(), branch2);
Node* effect = etrue1;
ElementAccess const access = AccessBuilder::ForFixedArrayElement(kind);
Node* value = effect =
graph()->NewNode(simplified()->LoadElement(access), elements, index,
effect, control);
effect =
graph()->NewNode(simplified()->StoreElement(access), elements,
graph()->NewNode(simplified()->NumberSubtract(),
index, jsgraph()->OneConstant()),
value, effect, control);
loop->ReplaceInput(1, control);
eloop->ReplaceInput(1, effect);
index->ReplaceInput(1,
graph()->NewNode(simplified()->NumberAdd(), index,
jsgraph()->OneConstant()));
}
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
efalse0 =
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
vfalse0 =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue1, vfalse1, if_false0);
// Compute the new {length}.
length = graph()->NewNode(simplified()->NumberSubtract(), length,
jsgraph()->OneConstant());
// Store the new {length} to the {receiver}.
etrue1 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
receiver, length, etrue1, if_true1);
// Store a hole to the element we just removed from the {receiver}.
etrue1 = graph()->NewNode(
simplified()->StoreElement(
AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
}
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* efalse1 = efalse0;
Node* vfalse1;
{
// Call the generic C++ implementation.
const int builtin_index = Builtins::kArrayShift;
CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor(
graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
Builtins::name(builtin_index), node->op()->properties(),
CallDescriptor::kNeedsFrameState);
Node* stub_code =
jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack, true);
Address builtin_entry = Builtins::CppEntryOf(builtin_index);
Node* entry = jsgraph()->ExternalConstant(
ExternalReference(builtin_entry, isolate()));
Node* argc =
jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
if_false1 = efalse1 = vfalse1 =
graph()->NewNode(common()->Call(desc), stub_code, receiver,
jsgraph()->PaddingConstant(), argc, target,
jsgraph()->UndefinedConstant(), entry, argc, context,
frame_state, efalse1, if_false1);
}
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
efalse0 =
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue1, vfalse1, if_false0);
}
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
......@@ -3959,15 +4000,13 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
// Convert the hole to undefined. Do this last, so that we can optimize
// conversion operator via some smart strength reduction in many cases.
if (IsHoleyElementsKind(receiver_map->elements_kind())) {
if (IsHoleyElementsKind(kind)) {
value =
graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
......
......@@ -66,7 +66,7 @@ function runTest(f, message, mkICTraining, deoptArg) {
let checks = {
smiReceiver:
{ mkTrainingArguments : () => [{arr:[1], el:3}],
deoptingArguments : [{arr:[1], el:true}, {arr:[0.1], el:1}, {arr:[{}], el:1}]
deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}]
},
objectReceiver:
{ mkTrainingArguments : () => [{arr:[{}], el:0.1}],
......@@ -74,19 +74,19 @@ let checks = {
},
multipleSmiReceivers:
{ mkTrainingArguments : () => { let b = [1]; b.x=3; return [{arr:[1], el:3}, {arr:b, el:3}] },
deoptingArguments : [{arr:[1], el:true}, {arr:[0.1], el:1}, {arr:[{}], el:1}]
deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}]
},
multipleSmiReceiversPackedUnpacked:
{ mkTrainingArguments : () => { let b = [1]; b[100] = 3; return [{arr:[1], el:3}, {arr:b, el:3}] },
deoptingArguments : [ {arr:[1], el:true} ]
deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}]
},
multipleDoubleReceivers:
{ mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] },
deoptingArguments : [{arr:[{}], el:true}, {arr:[0.1], el:true}]
deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}]
},
multipleDoubleReceiversPackedUnpacked:
{ mkTrainingArguments : () => { let b = [0.1]; b[100] = 0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] },
deoptingArguments : [{arr:[{}], el:true}, {arr:[0.1], el:true}]
deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}]
},
multipleMixedReceivers:
{ mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[1], el:0.3}, {arr:[{}], el:true}, {arr:b, el:0.3}] },
......@@ -98,10 +98,13 @@ let checks = {
},
};
const functions = {
push_reliable: (a,g) => { let b = g(); return a.push(2, b); },
push_unreliable: (a,g) => { return a.push(2, g()); },
pop_reliable: (a,g) => { let b = g(); return a.pop(2, b); },
pop_unreliable: (a,g) => { return a.pop(2, g()); },
shift_reliable: (a,g) => { let b = g(); return a.shift(2, b); },
shift_unreliable: (a,g) => { return a.shift(2, g()); }
}
Object.keys(checks).forEach(
......
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