diff options
author | Ali Ijaz Sheikh <ofrobots@google.com> | 2016-04-07 14:06:55 -0700 |
---|---|---|
committer | Ali Ijaz Sheikh <ofrobots@google.com> | 2016-04-14 10:03:39 -0700 |
commit | 52af5c4eebf4de8638aef0338bd826656312a02a (patch) | |
tree | 628dc9fb0b558c3a73a2160706fef368876fe548 /deps/v8/test/unittests | |
parent | 6e3e8acc7cc7ebd3d67db5ade1247b8b558efe09 (diff) | |
download | android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.gz android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.bz2 android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.zip |
deps: upgrade V8 to 5.0.71.32
* Pick up the branch head for V8 5.0 stable [1]
* Edit v8 gitignore to allow trace_event copy
* Update V8 DEP trace_event as per deps/v8/DEPS [2]
[1] https://chromium.googlesource.com/v8/v8.git/+/3c67831
[2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/4b09207e447ae5bd34643b4c6321bee7b76d35f9
Ref: https://github.com/nodejs/node/pull/5945
PR-URL: https://github.com/nodejs/node/pull/6111
Reviewed-By: targos - Michaƫl Zasso <mic.besace@gmail.com>
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'deps/v8/test/unittests')
36 files changed, 3412 insertions, 2417 deletions
diff --git a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc index 62abeda1b5..72cfc51d58 100644 --- a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc @@ -1584,7 +1584,7 @@ TEST_P(InstructionSelectorF32ComparisonTest, NegatedWithParameters) { StreamBuilder m(this, MachineType::Int32(), MachineType::Float32(), MachineType::Float32()); m.Return( - m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); + m.Word32BinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); Stream const s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode()); @@ -1667,7 +1667,7 @@ TEST_P(InstructionSelectorF64ComparisonTest, NegatedWithParameters) { StreamBuilder m(this, MachineType::Int32(), MachineType::Float64(), MachineType::Float64()); m.Return( - m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); + m.Word32BinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); Stream const s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode()); @@ -2544,8 +2544,28 @@ TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIVAndMLS) { } +TEST_F(InstructionSelectorTest, Word32ShlWord32SarForSbfx) { + TRACED_FORRANGE(int32_t, shl, 1, 31) { + TRACED_FORRANGE(int32_t, sar, shl, 31) { + if ((shl == sar) && (sar == 16)) continue; // Sxth. + if ((shl == sar) && (sar == 24)) continue; // Sxtb. + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(shl)), + m.Int32Constant(sar))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmSbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(sar - shl, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(32 - sar, s.ToInt32(s[0]->InputAt(2))); + } + } +} + + TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { - TRACED_FORRANGE(int32_t, width, 1, 32) { + TRACED_FORRANGE(int32_t, width, 9, 23) { + if (width == 16) continue; // Uxth. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(0xffffffffu >> (32 - width)))); @@ -2556,7 +2576,8 @@ TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); } - TRACED_FORRANGE(int32_t, width, 1, 32) { + TRACED_FORRANGE(int32_t, width, 9, 23) { + if (width == 16) continue; // Uxth. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), m.Parameter(0))); @@ -2572,7 +2593,7 @@ TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { TRACED_FORRANGE(int32_t, lsb, 0, 31) { - TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) { + TRACED_FORRANGE(int32_t, width, 9, (24 - lsb) - 1) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And( m.Parameter(0), @@ -2589,7 +2610,7 @@ TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { } } TRACED_FORRANGE(int32_t, lsb, 0, 31) { - TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) { + TRACED_FORRANGE(int32_t, width, 9, (24 - lsb) - 1) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return( m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)), @@ -2828,8 +2849,11 @@ TEST_F(InstructionSelectorTest, Word32NotWithParameter) { TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { - TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, lsb, 1, 31) { TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + if (((width == 8) || (width == 16)) && + ((lsb == 8) || (lsb == 16) || (lsb == 24))) + continue; // Uxtb/h ror. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), m.Int32Constant(0xffffffffu >> (32 - width)))); @@ -2841,8 +2865,11 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, lsb, 1, 31) { TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + if (((width == 8) || (width == 16)) && + ((lsb == 8) || (lsb == 16) || (lsb == 24))) + continue; // Uxtb/h ror. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); @@ -2857,6 +2884,62 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { } +TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrAnd0xff) { + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Word32Shr(p0, m.Int32Constant(shr * 8)), + m.Int32Constant(0xff)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxtb, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Int32Constant(0xff), + m.Word32Shr(p0, m.Int32Constant(shr * 8))); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxtb, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } +} + + +TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrAnd0xffff) { + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Word32Shr(p0, m.Int32Constant(shr * 8)), + m.Int32Constant(0xffff)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxth, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Int32Constant(0xffff), + m.Word32Shr(p0, m.Int32Constant(shr * 8))); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxth, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } +} + + TEST_F(InstructionSelectorTest, Word32Clz) { StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32()); Node* const p0 = m.Parameter(0); diff --git a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc index b088367a58..d5e12ba0db 100644 --- a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc +++ b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc @@ -9,7 +9,7 @@ #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" -#include "src/types-inl.h" +#include "src/types.h" #include "src/zone-containers.h" #include "test/unittests/compiler/graph-unittest.h" @@ -85,6 +85,20 @@ class EscapeAnalysisTest : public GraphTest { allocation, value, effect, control); } + Node* StoreElement(const ElementAccess& access, Node* allocation, Node* index, + Node* value, Node* effect = nullptr, + Node* control = nullptr) { + if (!effect) { + effect = effect_; + } + if (!control) { + control = control_; + } + return effect_ = + graph()->NewNode(simplified()->StoreElement(access), allocation, + index, value, effect, control); + } + Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr, Node* control = nullptr) { if (!effect) { @@ -131,12 +145,18 @@ class EscapeAnalysisTest : public GraphTest { return control_ = graph()->NewNode(common()->Merge(2), control1, control2); } - FieldAccess AccessAtIndex(int offset) { + FieldAccess FieldAccessAtIndex(int offset) { FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(), MachineType::AnyTagged()}; return access; } + ElementAccess MakeElementAccess(int header_size) { + ElementAccess access = {kTaggedBase, header_size, Type::Any(), + MachineType::AnyTagged()}; + return access; + } + // ---------------------------------Assertion Helper-------------------------- void ExpectReplacement(Node* node, Node* rep) { @@ -166,6 +186,7 @@ class EscapeAnalysisTest : public GraphTest { SimplifiedOperatorBuilder* simplified() { return &simplified_; } Node* effect() { return effect_; } + Node* control() { return control_; } private: SimplifiedOperatorBuilder simplified_; @@ -185,9 +206,9 @@ TEST_F(EscapeAnalysisTest, StraightNonEscape) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* load = Load(AccessAtIndex(0), finish); + Node* load = Load(FieldAccessAtIndex(0), finish); Node* result = Return(load); EndGraph(); @@ -202,13 +223,39 @@ TEST_F(EscapeAnalysisTest, StraightNonEscape) { } +TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + Node* index = + graph()->NewNode(common()->Select(MachineRepresentation::kTagged), + object1, object2, control()); + StoreElement(MakeElementAccess(0), allocation, index, object1); + Node* finish = FinishRegion(allocation); + Node* load = Load(FieldAccessAtIndex(0), finish); + Node* result = Return(load); + EndGraph(); + + Analysis(); + + ExpectEscaped(allocation); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); +} + + TEST_F(EscapeAnalysisTest, StraightEscape) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* load = Load(AccessAtIndex(0), finish); + Node* load = Load(FieldAccessAtIndex(0), finish); Node* result = Return(allocation); EndGraph(); graph()->end()->AppendInput(zone(), load); @@ -229,15 +276,15 @@ TEST_F(EscapeAnalysisTest, StoreLoadEscape) { BeginRegion(); Node* allocation1 = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation1, object1); + Store(FieldAccessAtIndex(0), allocation1, object1); Node* finish1 = FinishRegion(allocation1); BeginRegion(); Node* allocation2 = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation2, finish1); + Store(FieldAccessAtIndex(0), allocation2, finish1); Node* finish2 = FinishRegion(allocation2); - Node* load = Load(AccessAtIndex(0), finish2); + Node* load = Load(FieldAccessAtIndex(0), finish2); Node* result = Return(load); EndGraph(); Analysis(); @@ -257,16 +304,18 @@ TEST_F(EscapeAnalysisTest, BranchNonEscape) { Node* object2 = Constant(2); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); Branch(); Node* ifFalse = IfFalse(); Node* ifTrue = IfTrue(); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse); - Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse); + Node* effect2 = + Store(FieldAccessAtIndex(0), allocation, object2, finish, ifTrue); Node* merge = Merge2(ifFalse, ifTrue); Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); - Node* load = Load(AccessAtIndex(0), finish, phi, merge); + Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge); Node* result = Return(load, phi); EndGraph(); graph()->end()->AppendInput(zone(), result); @@ -283,14 +332,81 @@ TEST_F(EscapeAnalysisTest, BranchNonEscape) { } +TEST_F(EscapeAnalysisTest, BranchEscapeOne) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + Node* index = graph()->NewNode(common()->Parameter(0), start()); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + Node* finish = FinishRegion(allocation); + Branch(); + Node* ifFalse = IfFalse(); + Node* ifTrue = IfTrue(); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse); + Node* effect2 = StoreElement(MakeElementAccess(0), allocation, index, object2, + finish, ifTrue); + Node* merge = Merge2(ifFalse, ifTrue); + Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); + Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge); + Node* result = Return(load, phi); + EndGraph(); + + Analysis(); + + ExpectEscaped(allocation); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); +} + + +TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + FinishRegion(allocation); + BeginRegion(); + Node* allocation2 = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object2); + Node* finish2 = FinishRegion(allocation2); + Branch(); + Node* ifFalse = IfFalse(); + Node* ifTrue = IfTrue(); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, allocation2, finish2, ifFalse); + Node* merge = Merge2(ifFalse, ifTrue); + Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, finish2, merge); + Node* load = Load(FieldAccessAtIndex(0), finish2, phi, merge); + Node* result = Return(allocation, phi); + EndGraph(); + graph()->end()->AppendInput(zone(), load); + + Analysis(); + + ExpectEscaped(allocation); + ExpectEscaped(allocation2); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); +} + + TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { Node* object1 = Constant(1); Node* object2 = Constant(2); Node* allocation = Allocate(Constant(kPointerSize)); - Node* store1 = Store(AccessAtIndex(0), allocation, object1); - Node* load1 = Load(AccessAtIndex(0), allocation); - Node* store2 = Store(AccessAtIndex(0), allocation, object2); - Node* load2 = Load(AccessAtIndex(0), allocation, store1); + Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1); + Node* load1 = Load(FieldAccessAtIndex(0), allocation); + Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2); + Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1); Node* result = Return(load2); EndGraph(); graph()->end()->AppendInput(zone(), store2); @@ -312,9 +428,9 @@ TEST_F(EscapeAnalysisTest, DeoptReplacement) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish); + Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); Branch(); Node* ifFalse = IfFalse(); Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish); @@ -328,7 +444,7 @@ TEST_F(EscapeAnalysisTest, DeoptReplacement) { Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), frame_state, effect1, ifFalse); Node* ifTrue = IfTrue(); - Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue); + Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue); Node* result = Return(load, effect1, ifTrue); EndGraph(); graph()->end()->AppendInput(zone(), deopt); @@ -351,10 +467,10 @@ TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize * 2)); - Store(AccessAtIndex(0), allocation, object1); - Store(AccessAtIndex(kPointerSize), allocation, allocation); + Store(FieldAccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(kPointerSize), allocation, allocation); Node* finish = FinishRegion(allocation); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish); + Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); Branch(); Node* ifFalse = IfFalse(); Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish); @@ -368,7 +484,7 @@ TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) { Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), frame_state, effect1, ifFalse); Node* ifTrue = IfTrue(); - Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue); + Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue); Node* result = Return(load, effect1, ifTrue); EndGraph(); graph()->end()->AppendInput(zone(), deopt); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc index 89c0a654e9..16030f80d7 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc @@ -40,7 +40,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( instruction_blocks); SourcePositionTable source_position_table(graph()); InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence, - schedule, &source_position_table, + schedule, &source_position_table, nullptr, source_position_mode, features); selector.SelectInstructions(); if (FLAG_trace_turbo) { @@ -148,7 +148,7 @@ InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( int parameter_count, int local_count) { return common()->CreateFrameStateFunctionInfo( FrameStateType::kJavaScriptFunction, parameter_count, local_count, - Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT); + Handle<SharedFunctionInfo>()); } diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h index fc7c144939..f1397faa06 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h @@ -92,7 +92,7 @@ class InstructionSelectorTest : public TestWithContext, CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) { MachineSignature::Builder builder(zone, 1, 0); builder.AddReturn(return_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -100,7 +100,7 @@ class InstructionSelectorTest : public TestWithContext, MachineSignature::Builder builder(zone, 1, 1); builder.AddReturn(return_type); builder.AddParam(parameter0_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -110,7 +110,7 @@ class InstructionSelectorTest : public TestWithContext, builder.AddReturn(return_type); builder.AddParam(parameter0_type); builder.AddParam(parameter1_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -122,11 +122,48 @@ class InstructionSelectorTest : public TestWithContext, builder.AddParam(parameter0_type); builder.AddParam(parameter1_type); builder.AddParam(parameter2_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } private: InstructionSelectorTest* test_; + + // Create a simple call descriptor for testing. + CallDescriptor* MakeSimpleCallDescriptor(Zone* zone, + MachineSignature* msig) { + LocationSignature::Builder locations(zone, msig->return_count(), + msig->parameter_count()); + + // Add return location(s). + const int return_count = static_cast<int>(msig->return_count()); + for (int i = 0; i < return_count; i++) { + locations.AddReturn(LinkageLocation::ForCallerFrameSlot(-1 - i)); + } + + // Just put all parameters on the stack. + const int parameter_count = static_cast<int>(msig->parameter_count()); + for (int i = 0; i < parameter_count; i++) { + locations.AddParam(LinkageLocation::ForCallerFrameSlot(-1 - i)); + } + + const RegList kCalleeSaveRegisters = 0; + const RegList kCalleeSaveFPRegisters = 0; + + MachineType target_type = MachineType::Pointer(); + LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallAddress, // kind + target_type, // target MachineType + target_loc, // target location + msig, // machine_sig + locations.Build(), // location_sig + 0, // stack_parameter_count + Operator::kNoProperties, // properties + kCalleeSaveRegisters, // callee-saved registers + kCalleeSaveFPRegisters, // callee-saved fp regs + CallDescriptor::kNoFlags, // flags + "iselect-test-call"); + } }; class Stream final { diff --git a/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc new file mode 100644 index 0000000000..eff6d4a931 --- /dev/null +++ b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc @@ -0,0 +1,299 @@ +// Copyright 2016 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. + +#include "src/compiler/int64-lowering.h" +#include "src/compiler/common-operator.h" +#include "src/compiler/linkage.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" + +#include "src/compiler/node-properties.h" + +#include "src/signature.h" + +#include "src/wasm/wasm-module.h" + +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::AllOf; +using testing::Capture; +using testing::CaptureEq; + +namespace v8 { +namespace internal { +namespace compiler { + +class Int64LoweringTest : public GraphTest { + public: + Int64LoweringTest() : GraphTest(), machine_(zone()) { + value_[0] = 0x1234567890abcdef; + value_[1] = 0x1edcba098765432f; + value_[2] = 0x1133557799886644; + } + + MachineOperatorBuilder* machine() { return &machine_; } + + void LowerGraph(Node* node, Signature<MachineRepresentation>* signature) { + Node* ret = graph()->NewNode(common()->Return(), node, graph()->start(), + graph()->start()); + NodeProperties::MergeControlToEnd(graph(), common(), ret); + + Int64Lowering lowering(graph(), machine(), common(), zone(), signature); + lowering.LowerGraph(); + } + + void LowerGraph(Node* node, MachineRepresentation return_type, + MachineRepresentation rep = MachineRepresentation::kWord32, + int num_params = 0) { + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, + num_params); + sig_builder.AddReturn(return_type); + for (int i = 0; i < num_params; i++) { + sig_builder.AddParam(rep); + } + LowerGraph(node, sig_builder.Build()); + } + + void CompareCallDescriptors(const CallDescriptor* lhs, + const CallDescriptor* rhs) { + EXPECT_THAT(lhs->CalleeSavedFPRegisters(), rhs->CalleeSavedFPRegisters()); + EXPECT_THAT(lhs->CalleeSavedRegisters(), rhs->CalleeSavedRegisters()); + EXPECT_THAT(lhs->FrameStateCount(), rhs->FrameStateCount()); + EXPECT_THAT(lhs->InputCount(), rhs->InputCount()); + for (size_t i = 0; i < lhs->InputCount(); i++) { + EXPECT_THAT(lhs->GetInputLocation(i), rhs->GetInputLocation(i)); + EXPECT_THAT(lhs->GetInputType(i), rhs->GetInputType(i)); + } + EXPECT_THAT(lhs->ReturnCount(), rhs->ReturnCount()); + for (size_t i = 0; i < lhs->ReturnCount(); i++) { + EXPECT_THAT(lhs->GetReturnLocation(i), rhs->GetReturnLocation(i)); + EXPECT_THAT(lhs->GetReturnType(i), rhs->GetReturnType(i)); + } + EXPECT_THAT(lhs->flags(), rhs->flags()); + EXPECT_THAT(lhs->kind(), rhs->kind()); + } + + int64_t value(int i) { return value_[i]; } + + int32_t low_word_value(int i) { + return static_cast<int32_t>(value_[i] & 0xffffffff); + } + + int32_t high_word_value(int i) { + return static_cast<int32_t>(value_[i] >> 32); + } + + private: + MachineOperatorBuilder machine_; + int64_t value_[3]; +}; + +TEST_F(Int64LoweringTest, Int64Constant) { + if (4 != kPointerSize) return; + + LowerGraph(Int64Constant(value(0)), MachineRepresentation::kWord64); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsInt32Constant(low_word_value(0)), + IsInt32Constant(high_word_value(0)), start(), start())); +} + +TEST_F(Int64LoweringTest, Int64Load) { + if (4 != kPointerSize) return; + + int32_t base = 0x1234; + int32_t index = 0x5678; + + LowerGraph(graph()->NewNode(machine()->Load(MachineType::Int64()), + Int32Constant(base), Int32Constant(index), + start(), start()), + MachineRepresentation::kWord64); + + Capture<Node*> high_word_load; + Matcher<Node*> high_word_load_matcher = + IsLoad(MachineType::Int32(), IsInt32Constant(base), + IsInt32Add(IsInt32Constant(index), IsInt32Constant(0x4)), start(), + start()); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn2(IsLoad(MachineType::Int32(), IsInt32Constant(base), + IsInt32Constant(index), AllOf(CaptureEq(&high_word_load), + high_word_load_matcher), + start()), + AllOf(CaptureEq(&high_word_load), high_word_load_matcher), + start(), start())); +} + +TEST_F(Int64LoweringTest, Int64Store) { + if (4 != kPointerSize) return; + + // We have to build the TF graph explicitly here because Store does not return + // a value. + + int32_t base = 1111; + int32_t index = 2222; + int32_t return_value = 0x5555; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0); + sig_builder.AddReturn(MachineRepresentation::kWord32); + + Node* store = graph()->NewNode( + machine()->Store(StoreRepresentation(MachineRepresentation::kWord64, + WriteBarrierKind::kNoWriteBarrier)), + Int32Constant(base), Int32Constant(index), Int64Constant(value(0)), + start(), start()); + + Node* ret = graph()->NewNode(common()->Return(), Int32Constant(return_value), + store, start()); + + NodeProperties::MergeControlToEnd(graph(), common(), ret); + + Int64Lowering lowering(graph(), machine(), common(), zone(), + sig_builder.Build()); + lowering.LowerGraph(); + + const StoreRepresentation rep(MachineRepresentation::kWord32, + kNoWriteBarrier); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn( + IsInt32Constant(return_value), + IsStore( + rep, IsInt32Constant(base), IsInt32Constant(index), + IsInt32Constant(low_word_value(0)), + IsStore(rep, IsInt32Constant(base), + IsInt32Add(IsInt32Constant(index), IsInt32Constant(4)), + IsInt32Constant(high_word_value(0)), start(), start()), + start()), + start())); +} + +TEST_F(Int64LoweringTest, Int64And) { + if (4 != kPointerSize) return; + + LowerGraph(graph()->NewNode(machine()->Word64And(), Int64Constant(value(0)), + Int64Constant(value(1))), + MachineRepresentation::kWord64); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsWord32And(IsInt32Constant(low_word_value(0)), + IsInt32Constant(low_word_value(1))), + IsWord32And(IsInt32Constant(high_word_value(0)), + IsInt32Constant(high_word_value(1))), + start(), start())); +} + +TEST_F(Int64LoweringTest, TruncateInt64ToInt32) { + if (4 != kPointerSize) return; + + LowerGraph(graph()->NewNode(machine()->TruncateInt64ToInt32(), + Int64Constant(value(0))), + MachineRepresentation::kWord32); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn(IsInt32Constant(low_word_value(0)), start(), start())); +} + +TEST_F(Int64LoweringTest, Parameter) { + if (4 != kPointerSize) return; + + LowerGraph(Parameter(0), MachineRepresentation::kWord64, + MachineRepresentation::kWord64, 1); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsParameter(0), IsParameter(1), start(), start())); +} + +TEST_F(Int64LoweringTest, Parameter2) { + if (4 != kPointerSize) return; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 5); + sig_builder.AddReturn(MachineRepresentation::kWord32); + + sig_builder.AddParam(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kFloat64); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kWord32); + + int start_parameter = start()->op()->ValueOutputCount(); + LowerGraph(Parameter(4), sig_builder.Build()); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn(IsParameter(6), start(), start())); + // The parameter of the start node should increase by 2, because we lowered + // two parameter nodes. + EXPECT_THAT(start()->op()->ValueOutputCount(), start_parameter + 2); +} + +TEST_F(Int64LoweringTest, CallI64Return) { + if (4 != kPointerSize) return; + + int32_t function = 0x9999; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0); + sig_builder.AddReturn(MachineRepresentation::kWord64); + + compiler::CallDescriptor* desc = + wasm::ModuleEnv::GetWasmCallDescriptor(zone(), sig_builder.Build()); + + LowerGraph(graph()->NewNode(common()->Call(desc), Int32Constant(function), + start(), start()), + MachineRepresentation::kWord64); + + Capture<Node*> call; + Matcher<Node*> call_matcher = + IsCall(testing::_, IsInt32Constant(function), start(), start()); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsProjection(0, AllOf(CaptureEq(&call), call_matcher)), + IsProjection(1, AllOf(CaptureEq(&call), call_matcher)), + start(), start())); + + CompareCallDescriptors( + OpParameter<const CallDescriptor*>( + graph()->end()->InputAt(1)->InputAt(0)->InputAt(0)), + wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), desc)); +} + +TEST_F(Int64LoweringTest, CallI64Parameter) { + if (4 != kPointerSize) return; + + int32_t function = 0x9999; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 3); + sig_builder.AddReturn(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + + compiler::CallDescriptor* desc = + wasm::ModuleEnv::GetWasmCallDescriptor(zone(), sig_builder.Build()); + + LowerGraph(graph()->NewNode(common()->Call(desc), Int32Constant(function), + Int64Constant(value(0)), + Int32Constant(low_word_value(1)), + Int64Constant(value(2)), start(), start()), + MachineRepresentation::kWord32); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn(IsCall(testing::_, IsInt32Constant(function), + IsInt32Constant(low_word_value(0)), + IsInt32Constant(high_word_value(0)), + IsInt32Constant(low_word_value(1)), + IsInt32Constant(low_word_value(2)), + IsInt32Constant(high_word_value(2)), start(), start()), + start(), start())); + + CompareCallDescriptors( + OpParameter<const CallDescriptor*>( + graph()->end()->InputAt(1)->InputAt(0)), + wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), desc)); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h deleted file mode 100644 index 15fa38b1be..0000000000 --- a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 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. - -#ifndef V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ -#define V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ - -#include "src/compiler/interpreter-assembler.h" -#include "src/compiler/linkage.h" -#include "src/compiler/machine-operator.h" -#include "test/unittests/test-utils.h" -#include "testing/gmock-support.h" - -namespace v8 { -namespace internal { -namespace compiler { - -using ::testing::Matcher; - -class InterpreterAssemblerTest : public TestWithIsolateAndZone { - public: - InterpreterAssemblerTest() {} - ~InterpreterAssemblerTest() override {} - - class InterpreterAssemblerForTest final : public InterpreterAssembler { - public: - InterpreterAssemblerForTest(InterpreterAssemblerTest* test, - interpreter::Bytecode bytecode) - : InterpreterAssembler(test->isolate(), test->zone(), bytecode) {} - ~InterpreterAssemblerForTest() override {} - - Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher); - Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher, - const Matcher<Node*>& value_matcher); - - Matcher<Node*> IsBytecodeOperand(int offset); - Matcher<Node*> IsBytecodeOperandSignExtended(int offset); - Matcher<Node*> IsBytecodeOperandShort(int offset); - Matcher<Node*> IsBytecodeOperandShortSignExtended(int offset); - - using InterpreterAssembler::call_descriptor; - using InterpreterAssembler::graph; - - private: - DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest); - }; -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ diff --git a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc index 78e9253a17..9e14cda7fb 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -64,10 +64,6 @@ Type* const kIntegral32Types[] = {Type::UnsignedSmall(), Type::Negative32(), Type::Integral32()}; -const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG}; - - -// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering. Type* const kNumberTypes[] = { Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(), Type::SignedSmall(), Type::Signed32(), Type::Unsigned32(), @@ -88,15 +84,13 @@ TEST_F(JSBuiltinReducerTest, MathMax0) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Node* call = graph()->NewNode(javascript()->CallFunction(2, language_mode), - function, UndefinedConstant(), context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + Node* call = graph()->NewNode(javascript()->CallFunction(2), function, + UndefinedConstant(), context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); } @@ -107,18 +101,15 @@ TEST_F(JSBuiltinReducerTest, MathMax1) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, language_mode), - function, UndefinedConstant(), p0, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), p0); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), p0); } } @@ -130,22 +121,18 @@ TEST_F(JSBuiltinReducerTest, MathMax2) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kIntegral32Types) { - TRACED_FOREACH(Type*, t1, kIntegral32Types) { - Node* p0 = Parameter(t0, 0); - Node* p1 = Parameter(t1, 1); - Node* call = - graph()->NewNode(javascript()->CallFunction(4, language_mode), - function, UndefinedConstant(), p0, p1, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsSelect(MachineRepresentation::kNone, - IsNumberLessThan(p1, p0), p0, p1)); - } + TRACED_FOREACH(Type*, t0, kIntegral32Types) { + TRACED_FOREACH(Type*, t1, kIntegral32Types) { + Node* p0 = Parameter(t0, 0); + Node* p1 = Parameter(t1, 1); + Node* call = graph()->NewNode(javascript()->CallFunction(4), function, + UndefinedConstant(), p0, p1, context, + frame_state, frame_state, effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone, + IsNumberLessThan(p1, p0), p0, p1)); } } } @@ -162,20 +149,17 @@ TEST_F(JSBuiltinReducerTest, MathImul) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kIntegral32Types) { - TRACED_FOREACH(Type*, t1, kIntegral32Types) { - Node* p0 = Parameter(t0, 0); - Node* p1 = Parameter(t1, 1); - Node* call = - graph()->NewNode(javascript()->CallFunction(4, language_mode), - function, UndefinedConstant(), p0, p1, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); - } + TRACED_FOREACH(Type*, t0, kIntegral32Types) { + TRACED_FOREACH(Type*, t1, kIntegral32Types) { + Node* p0 = Parameter(t0, 0); + Node* p1 = Parameter(t1, 1); + Node* call = graph()->NewNode(javascript()->CallFunction(4), function, + UndefinedConstant(), p0, p1, context, + frame_state, frame_state, effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); } } } @@ -192,18 +176,15 @@ TEST_F(JSBuiltinReducerTest, MathFround) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, language_mode), - function, UndefinedConstant(), p0, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0)); } } diff --git a/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc b/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc deleted file mode 100644 index a44bd0278d..0000000000 --- a/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2015 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. - -#include "src/compiler/js-context-relaxation.h" -#include "src/compiler/js-graph.h" -#include "test/unittests/compiler/graph-unittest.h" -#include "test/unittests/compiler/node-test-utils.h" - -namespace v8 { -namespace internal { -namespace compiler { - -class JSContextRelaxationTest : public GraphTest { - public: - JSContextRelaxationTest() : GraphTest(3), javascript_(zone()) {} - ~JSContextRelaxationTest() override {} - - protected: - Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = - MachineOperatorBuilder::kNoFlags) { - MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(), - flags); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr, - &machine); - // TODO(titzer): mock the GraphReducer here for better unit testing. - GraphReducer graph_reducer(zone(), graph()); - JSContextRelaxation reducer; - return reducer.Reduce(node); - } - - Node* EmptyFrameState() { - MachineOperatorBuilder machine(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr, - &machine); - return jsgraph.EmptyFrameState(); - } - - Node* ShallowFrameStateChain(Node* outer_context, - ContextCallingMode context_calling_mode) { - const FrameStateFunctionInfo* const frame_state_function_info = - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 3, 0, - Handle<SharedFunctionInfo>(), context_calling_mode); - const Operator* op = common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - frame_state_function_info); - return graph()->NewNode(op, graph()->start(), graph()->start(), - graph()->start(), outer_context, graph()->start(), - graph()->start()); - } - - Node* DeepFrameStateChain(Node* outer_context, - ContextCallingMode context_calling_mode) { - const FrameStateFunctionInfo* const frame_state_function_info = - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 3, 0, - Handle<SharedFunctionInfo>(), context_calling_mode); - const Operator* op = common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - frame_state_function_info); - Node* shallow_frame_state = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - return graph()->NewNode(op, graph()->start(), graph()->start(), - graph()->start(), graph()->start(), - graph()->start(), shallow_frame_state); - } - - JSOperatorBuilder* javascript() { return &javascript_; } - - private: - JSOperatorBuilder javascript_; -}; - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionShallowFrameStateChainNoCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionShallowFrameStateChainCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - ShallowFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepFrameStateChainNoCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - DeepFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepFrameStateChainCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - DeepFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForCatch) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateCatchContext(Handle<String>()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForWith) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateWithContext(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForBlock) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null(); - const Operator* op = javascript()->CreateBlockContext(scope_info); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = - graph()->NewNode(op, graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialRelaxForScript) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null(); - const Operator* op = javascript()->CreateScriptContext(scope_info); - Node* const frame_state_1 = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode(op, graph()->start(), outer_context, - frame_state_1, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialRelaxForModule) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateModuleContext(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialNoRelax) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateFunctionContext(0); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = - graph()->NewNode(op, graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc new file mode 100644 index 0000000000..837c5742d9 --- /dev/null +++ b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc @@ -0,0 +1,236 @@ +// Copyright 2016 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. + +#include "src/compiler/js-create-lowering.h" +#include "src/code-factory.h" +#include "src/compiler/access-builder.h" +#include "src/compiler/js-graph.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node-properties.h" +#include "src/compiler/operator-properties.h" +#include "src/isolate-inl.h" +#include "test/unittests/compiler/compiler-test-utils.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::_; +using testing::BitEq; +using testing::IsNaN; + +namespace v8 { +namespace internal { +namespace compiler { + +class JSCreateLoweringTest : public TypedGraphTest { + public: + JSCreateLoweringTest() + : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {} + ~JSCreateLoweringTest() override {} + + protected: + Reduction Reduce(Node* node) { + MachineOperatorBuilder machine(zone()); + SimplifiedOperatorBuilder simplified(zone()); + JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, + &machine); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, + MaybeHandle<LiteralsArray>(), zone()); + return reducer.Reduce(node); + } + + Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) { + Node* state_values = graph()->NewNode(common()->StateValues(0)); + return graph()->NewNode( + common()->FrameState( + BailoutId::None(), OutputFrameStateCombine::Ignore(), + common()->CreateFrameStateFunctionInfo( + FrameStateType::kJavaScriptFunction, 1, 0, shared)), + state_values, state_values, state_values, NumberConstant(0), + UndefinedConstant(), outer_frame_state); + } + + JSOperatorBuilder* javascript() { return &javascript_; } + + private: + JSOperatorBuilder javascript_; + CompilationDependencies deps_; +}; + +TEST_F(JSCreateLoweringTest, JSCreate) { + Handle<JSFunction> function = isolate()->object_function(); + Node* const target = Parameter(Type::Constant(function, graph()->zone())); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, + context, EmptyFrameState(), effect)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), + IsBeginRegion(effect), _), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateArguments + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsViaStub) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state = FrameState(shared, graph()->start()); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments), + closure, context, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsCall(_, IsHeapConstant( + CodeFactory::FastNewStrictArguments(isolate()).code()), + closure, context, frame_state, effect, control)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsRestParameterViaStub) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state = FrameState(shared, graph()->start()); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kRestParameter), + closure, context, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsCall(_, IsHeapConstant( + CodeFactory::FastNewRestParameter(isolate()).code()), + closure, context, frame_state, effect, control)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kMappedArguments), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), + _, control), + _)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), + _, control), + _)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kRestParameter), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateFunctionContext + +TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { + Node* const closure = Parameter(Type::Any()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = + Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + 8 + Context::MIN_CONTEXT_SLOTS)), + IsBeginRegion(_), control), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateWithContext + +TEST_F(JSCreateLoweringTest, JSCreateWithContext) { + Node* const object = Parameter(Type::Receiver()); + Node* const closure = Parameter(Type::Function()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction r = + Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, + closure, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + Context::MIN_CONTEXT_SLOTS)), + IsBeginRegion(_), control), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateCatchContext + +TEST_F(JSCreateLoweringTest, JSCreateCatchContext) { + Handle<String> name = factory()->length_string(); + Node* const exception = Parameter(Type::Receiver()); + Node* const closure = Parameter(Type::Function()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction r = + Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception, + closure, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + Context::MIN_CONTEXT_SLOTS + 1)), + IsBeginRegion(_), control), + _)); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index f38f8eaac7..919c1b2237 100644 --- a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -7,7 +7,6 @@ #include "src/compiler/js-graph.h" #include "src/compiler/js-intrinsic-lowering.h" #include "src/compiler/js-operator.h" -#include "src/types-inl.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" #include "testing/gmock-support.h" @@ -24,9 +23,9 @@ namespace v8 { namespace internal { namespace compiler { -class JSIntrinsicLoweringTest : public TypedGraphTest { +class JSIntrinsicLoweringTest : public GraphTest { public: - JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {} + JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {} ~JSIntrinsicLoweringTest() override {} protected: @@ -162,37 +161,6 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsArray) { // ----------------------------------------------------------------------------- -// %_IsDate - - -TEST_F(JSIntrinsicLoweringTest, InlineIsDate) { - Node* const input = Parameter(0); - Node* const context = Parameter(1); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsDate, 1), - input, context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node*> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, - effect, CaptureEq(&if_false)), - effect, _), - IsInt32Constant(JS_DATE_TYPE)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -// ----------------------------------------------------------------------------- // %_IsTypedArray @@ -224,38 +192,6 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) { // ----------------------------------------------------------------------------- -// %_IsFunction - - -TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) { - Node* const input = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1), - input, context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node*> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsUint32LessThanOrEqual( - IsInt32Constant(FIRST_FUNCTION_TYPE), - IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, effect, - CaptureEq(&if_false)), - effect, _)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -// ----------------------------------------------------------------------------- // %_IsRegExp @@ -290,75 +226,16 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) { // %_IsJSReceiver -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) { - Node* const input = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node *> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsUint32LessThanOrEqual( - IsInt32Constant(FIRST_JS_RECEIVER_TYPE), - IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, effect, - CaptureEq(&if_false)), - effect, _)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithReceiver) { - Node* const input = Parameter(Type::Receiver()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTrueConstant()); -} - - -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithUndefined) { - Node* const input = Parameter(Type::Undefined()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFalseConstant()); -} - - -// ----------------------------------------------------------------------------- -// %_JSValueGetValue - - -TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) { +TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) { Node* const input = Parameter(0); Node* const context = Parameter(1); Node* const effect = graph()->start(); Node* const control = graph()->start(); Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input, + javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsLoadField(AccessBuilder::ForValue(), input, effect, control)); + EXPECT_THAT(r.replacement(), IsObjectIsReceiver(input)); } diff --git a/deps/v8/test/unittests/compiler/js-operator-unittest.cc b/deps/v8/test/unittests/compiler/js-operator-unittest.cc index e0db771458..15b1427871 100644 --- a/deps/v8/test/unittests/compiler/js-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-operator-unittest.cc @@ -12,34 +12,8 @@ namespace v8 { namespace internal { namespace compiler { -namespace { - -const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG}; - - -#if GTEST_HAS_COMBINE - -template <typename T> -class JSOperatorTestWithLanguageModeAndParam - : public TestWithZone, - public ::testing::WithParamInterface<::testing::tuple<LanguageMode, T>> { - protected: - LanguageMode language_mode() const { - return ::testing::get<0>(B::GetParam()); - } - const T& GetParam() const { return ::testing::get<1>(B::GetParam()); } - - private: - typedef ::testing::WithParamInterface<::testing::tuple<LanguageMode, T>> B; -}; - -#endif // GTEST_HAS_COMBINE - -} // namespace - - // ----------------------------------------------------------------------------- -// Shared operators without language mode. +// Shared operators. namespace { @@ -56,7 +30,6 @@ struct SharedOperator { int control_output_count; }; - const SharedOperator kSharedOperators[] = { #define SHARED(Name, properties, value_input_count, frame_state_input_count, \ effect_input_count, control_input_count, value_output_count, \ @@ -71,6 +44,10 @@ const SharedOperator kSharedOperators[] = { SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(StrictEqual, Operator::kNoThrow, 2, 0, 1, 1, 1, 1, 0), SHARED(StrictNotEqual, Operator::kNoThrow, 2, 0, 1, 1, 1, 1, 0), + SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), @@ -148,123 +125,6 @@ TEST_P(JSSharedOperatorTest, Properties) { INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest, ::testing::ValuesIn(kSharedOperators)); - -// ----------------------------------------------------------------------------- -// Shared operators with language mode. - - -#if GTEST_HAS_COMBINE - -namespace { - -struct SharedOperatorWithLanguageMode { - const Operator* (JSOperatorBuilder::*constructor)(LanguageMode); - IrOpcode::Value opcode; - Operator::Properties properties; - int value_input_count; - int frame_state_input_count; - int effect_input_count; - int control_input_count; - int value_output_count; - int effect_output_count; - int control_output_count; -}; - - -const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = { -#define SHARED(Name, properties, value_input_count, frame_state_input_count, \ - effect_input_count, control_input_count, value_output_count, \ - effect_output_count, control_output_count) \ - { \ - &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties, \ - value_input_count, frame_state_input_count, effect_input_count, \ - control_input_count, value_output_count, effect_output_count, \ - control_output_count \ - } - SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), -#undef SHARED -}; - - -std::ostream& operator<<(std::ostream& os, - const SharedOperatorWithLanguageMode& sop) { - return os << IrOpcode::Mnemonic(sop.opcode); -} - -} // namespace - - -class JSSharedOperatorWithLanguageModeTest - : public JSOperatorTestWithLanguageModeAndParam< - SharedOperatorWithLanguageMode> {}; - - -TEST_P(JSSharedOperatorWithLanguageModeTest, InstancesAreGloballyShared) { - const SharedOperatorWithLanguageMode& sop = GetParam(); - JSOperatorBuilder javascript1(zone()); - JSOperatorBuilder javascript2(zone()); - EXPECT_EQ((javascript1.*sop.constructor)(language_mode()), - (javascript2.*sop.constructor)(language_mode())); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, NumberOfInputsAndOutputs) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - - const int context_input_count = 1; - EXPECT_EQ(sop.value_input_count, op->ValueInputCount()); - EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op)); - EXPECT_EQ(sop.frame_state_input_count, - OperatorProperties::GetFrameStateInputCount(op)); - EXPECT_EQ(sop.effect_input_count, op->EffectInputCount()); - EXPECT_EQ(sop.control_input_count, op->ControlInputCount()); - EXPECT_EQ(sop.value_input_count + context_input_count + - sop.frame_state_input_count + sop.effect_input_count + - sop.control_input_count, - OperatorProperties::GetTotalInputCount(op)); - - EXPECT_EQ(sop.value_output_count, op->ValueOutputCount()); - EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount()); - EXPECT_EQ(sop.control_output_count, op->ControlOutputCount()); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, OpcodeIsCorrect) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(sop.opcode, op->opcode()); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, Parameter) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(language_mode(), OpParameter<LanguageMode>(op)); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, Properties) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(sop.properties, op->properties()); -} - - -INSTANTIATE_TEST_CASE_P( - JSOperatorTest, JSSharedOperatorWithLanguageModeTest, - ::testing::Combine(::testing::ValuesIn(kLanguageModes), - ::testing::ValuesIn(kSharedOperatorsWithLanguageMode))); - -#endif // GTEST_HAS_COMBINE - } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc index 6fc89bb0ea..e37d4a2913 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -92,18 +92,6 @@ class JSTypedLoweringTest : public TypedGraphTest { return reducer.Reduce(node); } - Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) { - Node* state_values = graph()->NewNode(common()->StateValues(0)); - return graph()->NewNode( - common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 1, 0, - shared, CALL_MAINTAINS_NATIVE_CONTEXT)), - state_values, state_values, state_values, NumberConstant(0), - UndefinedConstant(), outer_frame_state); - } - Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) { Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer(); JSArrayBuffer::Setup(buffer, isolate(), true, bytes, byte_length); @@ -435,15 +423,12 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce( - graph()->NewNode(javascript()->ShiftLeft(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftLeft(hints), lhs, NumberConstant(rhs), context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -455,13 +440,11 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftLeft(language_mode, hints), lhs, rhs, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs, + rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); } @@ -476,15 +459,12 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce( - graph()->NewNode(javascript()->ShiftRight(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRight(hints), lhs, NumberConstant(rhs), context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -496,13 +476,11 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRight(language_mode, hints), lhs, rhs, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs, + rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); } @@ -518,15 +496,12 @@ TEST_F(JSTypedLoweringTest, Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRightLogical(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), EmptyFrameState(), - effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRightLogical(hints), lhs, NumberConstant(rhs), + context, EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -538,13 +513,11 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRightLogical(language_mode, hints), lhs, rhs, - context, EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints), + lhs, rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); } @@ -627,37 +600,34 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { NewArrayBuffer(backing_store, sizeof(backing_store)); VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - int const element_size = static_cast<int>(array->element_size()); - - Node* key = Parameter( - Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->LoadProperty(language_mode, feedback), - base, key, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + int const element_size = static_cast<int>(array->element_size()); + + Node* key = Parameter( + Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadProperty(feedback), base, key, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); - Matcher<Node*> offset_matcher = - element_size == 1 - ? key - : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); + Matcher<Node*> offset_matcher = + element_size == 1 + ? key + : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadBuffer(BufferAccess(type), - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - offset_matcher, - IsNumberConstant(array->byte_length()->Number()), effect, - control)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadBuffer(BufferAccess(type), + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + offset_matcher, + IsNumberConstant(array->byte_length()->Number()), effect, + control)); } } @@ -669,32 +639,29 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) { NewArrayBuffer(backing_store, sizeof(backing_store)); VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - - int min = random_number_generator()->NextInt(static_cast<int>(kLength)); - int max = random_number_generator()->NextInt(static_cast<int>(kLength)); - if (min > max) std::swap(min, max); - Node* key = Parameter(Type::Range(min, max, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->LoadProperty(language_mode, feedback), - base, key, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); + + int min = random_number_generator()->NextInt(static_cast<int>(kLength)); + int max = random_number_generator()->NextInt(static_cast<int>(kLength)); + if (min > max) std::swap(min, max); + Node* key = Parameter(Type::Range(min, max, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadProperty(feedback), base, key, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadElement(access, - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - key, effect, control)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadElement(access, + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + key, effect, control)); } } @@ -847,15 +814,12 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction const r = Reduce( - graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback), - receiver, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(), - receiver, effect, control)); - } + Reduction const r = Reduce(graph()->NewNode( + javascript()->LoadNamed(name, feedback), receiver, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(), + receiver, effect, control)); } @@ -869,14 +833,11 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) { Node* const context = Parameter(Type::Internal(), 2); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction const r = Reduce( - graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback), - receiver, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype)); - } + Reduction const r = Reduce(graph()->NewNode( + javascript()->LoadNamed(name, feedback), receiver, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype)); } @@ -886,7 +847,6 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) { TEST_F(JSTypedLoweringTest, JSAddWithString) { BinaryOperationHints const hints = BinaryOperationHints::Any(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { Node* lhs = Parameter(Type::String(), 0); Node* rhs = Parameter(Type::String(), 1); Node* context = Parameter(Type::Any(), 2); @@ -894,300 +854,15 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) { Node* frame_state1 = EmptyFrameState(); Node* effect = graph()->start(); Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->Add(language_mode, hints), lhs, rhs, - context, frame_state0, frame_state1, effect, control)); + Reduction r = + Reduce(graph()->NewNode(javascript()->Add(hints), lhs, rhs, context, + frame_state0, frame_state1, effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsCall(_, IsHeapConstant(CodeFactory::StringAdd( isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED).code()), lhs, rhs, context, frame_state0, effect, control)); - } -} - - -// ----------------------------------------------------------------------------- -// JSCreate - - -TEST_F(JSTypedLoweringTest, JSCreate) { - Handle<JSFunction> function = isolate()->object_function(); - Node* const target = Parameter(Type::Constant(function, graph()->zone())); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, - context, EmptyFrameState(), effect)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), - IsBeginRegion(effect), _), - _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateArguments - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state = FrameState(shared, graph()->start()); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kMappedArguments, 0), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant(CodeFactory::ArgumentsAccess( - isolate(), false, false) - .code()), - closure, IsNumberConstant(0), _, effect, control)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsRestArrayViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state = FrameState(shared, graph()->start()); - Reduction r = Reduce(graph()->NewNode( - javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, - IsHeapConstant(CodeFactory::RestArgumentsAccess(isolate()).code()), - IsNumberConstant(0), _, IsNumberConstant(0), _, effect, control)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedMapped) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kMappedArguments, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(Heap::kSloppyArgumentsObjectSize), - _, control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedUnmapped) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kUnmappedArguments, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(Heap::kStrictArgumentsObjectSize), - _, control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedRestArray) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce(graph()->NewNode( - javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateClosure - - -TEST_F(JSTypedLoweringTest, JSCreateClosure) { - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED), - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant(CodeFactory::FastNewClosure( - isolate(), shared->language_mode(), - shared->kind()).code()), - IsHeapConstant(shared), effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateLiteralArray - - -TEST_F(JSTypedLoweringTest, JSCreateLiteralArray) { - Handle<FixedArray> const constant_elements = factory()->NewFixedArray(12); - int const literal_flags = ArrayLiteral::kShallowElements; - int const literal_index = 1; - Node* const closure = Parameter(0); - Node* const context = Parameter(1); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CreateLiteralArray( - constant_elements, literal_flags, literal_index), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastCloneShallowArray(isolate()).code()), - closure, IsNumberConstant(literal_index), - IsHeapConstant(constant_elements), context, frame_state, effect, - control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateLiteralObject - - -TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) { - Handle<FixedArray> const constant_properties = - factory()->NewFixedArray(6 * 2); - int const literal_flags = ObjectLiteral::kShallowProperties; - int const literal_index = 1; - Node* const closure = Parameter(0); - Node* const context = Parameter(1); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CreateLiteralObject( - constant_properties, literal_flags, literal_index), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastCloneShallowObject(isolate(), 6).code()), - closure, IsNumberConstant(literal_index), - IsHeapConstant(constant_properties), _, context, frame_state, - effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateFunctionContext - - -TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { - Node* const closure = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = - Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - 8 + Context::MIN_CONTEXT_SLOTS)), - IsBeginRegion(_), control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = - Reduce(graph()->NewNode(javascript()->CreateFunctionContext(32), closure, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastNewContext(isolate(), 32).code()), - closure, context, effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateWithContext - - -TEST_F(JSTypedLoweringTest, JSCreateWithContext) { - Node* const object = Parameter(Type::Receiver()); - Node* const closure = Parameter(Type::Function()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, - closure, context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - Context::MIN_CONTEXT_SLOTS)), - IsBeginRegion(_), control), - _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateCatchContext - - -TEST_F(JSTypedLoweringTest, JSCreateCatchContext) { - Handle<String> name = factory()->length_string(); - Node* const exception = Parameter(Type::Receiver()); - Node* const closure = Parameter(Type::Function()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception, - closure, context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - Context::MIN_CONTEXT_SLOTS + 1)), - IsBeginRegion(_), control), - _)); } diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc index b77830aa5e..efc823dba6 100644 --- a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc +++ b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc @@ -61,7 +61,7 @@ class LivenessAnalysisTest : public GraphTest { const FrameStateFunctionInfo* state_info = common()->CreateFrameStateFunctionInfo( FrameStateType::kJavaScriptFunction, 0, locals_count_, - Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT); + Handle<SharedFunctionInfo>()); const Operator* op = common()->FrameState( BailoutId(ast_num), OutputFrameStateCombine::Ignore(), state_info); diff --git a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc index 413c58b6fe..5ccd0c6727 100644 --- a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/compiler/move-optimizer.h" +#include "src/compiler/pipeline.h" #include "test/unittests/compiler/instruction-sequence-unittest.h" namespace v8 { @@ -227,8 +228,8 @@ TEST_F(MoveOptimizerTest, GapsCanMoveOverInstruction) { ctant_def->GetParallelMove(Instruction::GapPosition::END); ParallelMove* last_start = last->GetParallelMove(Instruction::GapPosition::START); - CHECK(inst1_start == nullptr || inst1_start->size() == 0); - CHECK(inst1_end == nullptr || inst1_end->size() == 0); + CHECK(inst1_start == nullptr || NonRedundantSize(inst1_start) == 0); + CHECK(inst1_end == nullptr || NonRedundantSize(inst1_end) == 0); CHECK(last_start->size() == 2); int redundants = 0; int assignment = 0; @@ -246,6 +247,98 @@ TEST_F(MoveOptimizerTest, GapsCanMoveOverInstruction) { } +TEST_F(MoveOptimizerTest, SubsetMovesMerge) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + Instruction* last_move_b1 = LastInstruction(); + AddMove(last_move_b1, Reg(0), Reg(1)); + AddMove(last_move_b1, Reg(2), Reg(3)); + + StartBlock(); + EndBlock(Jump(1)); + Instruction* last_move_b2 = LastInstruction(); + AddMove(last_move_b2, Reg(0), Reg(1)); + AddMove(last_move_b2, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Last()); + + Instruction* last = LastInstruction(); + + Optimize(); + + ParallelMove* last_move = last->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(last_move)); + CHECK(Contains(last_move, Reg(0), Reg(1))); + + ParallelMove* b1_move = last_move_b1->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b1_move)); + CHECK(Contains(b1_move, Reg(2), Reg(3))); + + ParallelMove* b2_move = last_move_b2->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b2_move)); + CHECK(Contains(b2_move, Reg(4), Reg(5))); +} + + +TEST_F(MoveOptimizerTest, GapConflictSubsetMovesDoNotMerge) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + Instruction* last_move_b1 = LastInstruction(); + AddMove(last_move_b1, Reg(0), Reg(1)); + AddMove(last_move_b1, Reg(2), Reg(0)); + AddMove(last_move_b1, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Jump(1)); + Instruction* last_move_b2 = LastInstruction(); + AddMove(last_move_b2, Reg(0), Reg(1)); + AddMove(last_move_b2, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Last()); + + Instruction* last = LastInstruction(); + + Optimize(); + + ParallelMove* last_move = last->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(last_move)); + CHECK(Contains(last_move, Reg(4), Reg(5))); + + ParallelMove* b1_move = last_move_b1->parallel_moves()[0]; + CHECK_EQ(2, NonRedundantSize(b1_move)); + CHECK(Contains(b1_move, Reg(0), Reg(1))); + CHECK(Contains(b1_move, Reg(2), Reg(0))); + + ParallelMove* b2_move = last_move_b2->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b2_move)); + CHECK(Contains(b1_move, Reg(0), Reg(1))); +} + +TEST_F(MoveOptimizerTest, ClobberedDestinationsAreEliminated) { + StartBlock(); + EmitNop(); + Instruction* first_instr = LastInstruction(); + AddMove(first_instr, Reg(0), Reg(1)); + EmitOI(Reg(1), 0, nullptr); + Instruction* last_instr = LastInstruction(); + EndBlock(); + Optimize(); + + ParallelMove* first_move = first_instr->parallel_moves()[0]; + CHECK_EQ(0, NonRedundantSize(first_move)); + + ParallelMove* last_move = last_instr->parallel_moves()[0]; + CHECK_EQ(0, NonRedundantSize(last_move)); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 54168ee70b..ee4cf5446e 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -323,13 +323,30 @@ class IsReturnMatcher final : public NodeMatcher { const Matcher<Node*>& control_matcher) : NodeMatcher(IrOpcode::kReturn), value_matcher_(value_matcher), + value2_matcher_(_), effect_matcher_(effect_matcher), - control_matcher_(control_matcher) {} + control_matcher_(control_matcher), + has_second_return_value_(false) {} + + IsReturnMatcher(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) + : NodeMatcher(IrOpcode::kReturn), + value_matcher_(value_matcher), + value2_matcher_(value2_matcher), + effect_matcher_(effect_matcher), + control_matcher_(control_matcher), + has_second_return_value_(true) {} void DescribeTo(std::ostream* os) const final { NodeMatcher::DescribeTo(os); *os << " whose value ("; value_matcher_.DescribeTo(os); + if (has_second_return_value_) { + *os << ") and second value ("; + value2_matcher_.DescribeTo(os); + } *os << ") and effect ("; effect_matcher_.DescribeTo(os); *os << ") and control ("; @@ -341,6 +358,9 @@ class IsReturnMatcher final : public NodeMatcher { return (NodeMatcher::MatchAndExplain(node, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "value", value_matcher_, listener) && + (!has_second_return_value_ || + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), + "value2", value2_matcher_, listener)) && PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", effect_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetControlInput(node), @@ -349,8 +369,10 @@ class IsReturnMatcher final : public NodeMatcher { private: const Matcher<Node*> value_matcher_; + const Matcher<Node*> value2_matcher_; const Matcher<Node*> effect_matcher_; const Matcher<Node*> control_matcher_; + bool has_second_return_value_; }; @@ -1467,7 +1489,6 @@ Matcher<Node*> IsDead() { return MakeMatcher(new NodeMatcher(IrOpcode::kDead)); } - Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher) { return MakeMatcher(new IsControl1Matcher(IrOpcode::kEnd, control0_matcher)); } @@ -1577,6 +1598,13 @@ Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher, new IsReturnMatcher(value_matcher, effect_matcher, control_matcher)); } +Matcher<Node*> IsReturn2(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) { + return MakeMatcher(new IsReturnMatcher(value_matcher, value2_matcher, + effect_matcher, control_matcher)); +} Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher) { @@ -1675,6 +1703,15 @@ Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher, return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher)); } +Matcher<Node*> IsCall(const Matcher<const CallDescriptor*>& descriptor_matcher, + const Matcher<Node*>& value0_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) { + std::vector<Matcher<Node*>> value_matchers; + value_matchers.push_back(value0_matcher); + return MakeMatcher(new IsCallMatcher(descriptor_matcher, value_matchers, + effect_matcher, control_matcher)); +} Matcher<Node*> IsCall(const Matcher<const CallDescriptor*>& descriptor_matcher, const Matcher<Node*>& value0_matcher, @@ -2106,6 +2143,7 @@ IS_UNOP_MATCHER(Float64ExtractLowWord32) IS_UNOP_MATCHER(Float64ExtractHighWord32) IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToUint32) +IS_UNOP_MATCHER(ObjectIsReceiver) IS_UNOP_MATCHER(ObjectIsSmi) IS_UNOP_MATCHER(Word32Clz) #undef IS_UNOP_MATCHER diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 8592f30566..03f2a3b88f 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -17,11 +17,8 @@ class ExternalReference; template <typename T> class Handle; class HeapObject; -template <class> -class TypeImpl; +class Type; enum TypeofMode : int; -struct ZoneTypeConfig; -typedef TypeImpl<ZoneTypeConfig> Type; namespace compiler { @@ -70,6 +67,10 @@ Matcher<Node*> IsFinishRegion(const Matcher<Node*>& value_matcher, Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsReturn2(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher); Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsExternalConstant( @@ -246,6 +247,7 @@ Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher, const Matcher<Node*>& value_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsObjectIsReceiver(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsSmi(const Matcher<Node*>& value_matcher); Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, diff --git a/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc new file mode 100644 index 0000000000..713ee6e742 --- /dev/null +++ b/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc @@ -0,0 +1,533 @@ +// Copyright 2015 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. + +#include "src/compiler/schedule.h" +#include "src/compiler/scheduler.h" +#include "test/unittests/compiler/compiler-test-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::AnyOf; + +namespace v8 { +namespace internal { +namespace compiler { + +class SchedulerRPOTest : public TestWithZone { + public: + SchedulerRPOTest() {} + + void CheckRPONumbers(BasicBlockVector* order, size_t expected, + bool loops_allowed) { + CHECK(expected == order->size()); + for (int i = 0; i < static_cast<int>(order->size()); i++) { + CHECK(order->at(i)->rpo_number() == i); + if (!loops_allowed) { + CHECK(!order->at(i)->loop_end()); + CHECK(!order->at(i)->loop_header()); + } + } + } + + void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) { + BasicBlock* header = blocks[0]; + BasicBlock* end = header->loop_end(); + CHECK(end); + CHECK_GT(end->rpo_number(), 0); + CHECK_EQ(body_size, end->rpo_number() - header->rpo_number()); + for (int i = 0; i < body_size; i++) { + CHECK_GE(blocks[i]->rpo_number(), header->rpo_number()); + CHECK_LT(blocks[i]->rpo_number(), end->rpo_number()); + CHECK(header->LoopContains(blocks[i])); + CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header); + } + if (header->rpo_number() > 0) { + CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header); + } + if (end->rpo_number() < static_cast<int>(order->size())) { + CHECK_NE(order->at(end->rpo_number())->loop_header(), header); + } + } + + struct TestLoop { + int count; + BasicBlock** nodes; + BasicBlock* header() { return nodes[0]; } + BasicBlock* last() { return nodes[count - 1]; } + ~TestLoop() { delete[] nodes; } + }; + + TestLoop* CreateLoop(Schedule* schedule, int count) { + TestLoop* loop = new TestLoop(); + loop->count = count; + loop->nodes = new BasicBlock*[count]; + for (int i = 0; i < count; i++) { + loop->nodes[i] = schedule->NewBasicBlock(); + if (i > 0) { + schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]); + } + } + schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]); + return loop; + } +}; + +TEST_F(SchedulerRPOTest, Degenerate1) { + Schedule schedule(zone()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1, false); + EXPECT_EQ(schedule.start(), order->at(0)); +} + +TEST_F(SchedulerRPOTest, Degenerate2) { + Schedule schedule(zone()); + + schedule.AddGoto(schedule.start(), schedule.end()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 2, false); + EXPECT_EQ(schedule.start(), order->at(0)); + EXPECT_EQ(schedule.end(), order->at(1)); +} + +TEST_F(SchedulerRPOTest, Line) { + for (int i = 0; i < 10; i++) { + Schedule schedule(zone()); + + BasicBlock* last = schedule.start(); + for (int j = 0; j < i; j++) { + BasicBlock* block = schedule.NewBasicBlock(); + block->set_deferred(i & 1); + schedule.AddGoto(last, block); + last = block; + } + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1 + i, false); + + for (size_t i = 0; i < schedule.BasicBlockCount(); i++) { + BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i)); + if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) { + EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number()); + } + } + } +} + +TEST_F(SchedulerRPOTest, SelfLoop) { + Schedule schedule(zone()); + schedule.AddSuccessorForTesting(schedule.start(), schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1, true); + BasicBlock* loop[] = {schedule.start()}; + CheckLoop(order, loop, 1); +} + +TEST_F(SchedulerRPOTest, EntryLoop) { + Schedule schedule(zone()); + BasicBlock* body = schedule.NewBasicBlock(); + schedule.AddSuccessorForTesting(schedule.start(), body); + schedule.AddSuccessorForTesting(body, schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 2, true); + BasicBlock* loop[] = {schedule.start(), body}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, EndLoop) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 3, true); + CheckLoop(order, loop1->nodes, loop1->count); +} + +TEST_F(SchedulerRPOTest, EndLoopNested) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 3, true); + CheckLoop(order, loop1->nodes, loop1->count); +} + +TEST_F(SchedulerRPOTest, Diamond) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(A, C); + schedule.AddSuccessorForTesting(B, D); + schedule.AddSuccessorForTesting(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, false); + + EXPECT_EQ(0, A->rpo_number()); + EXPECT_THAT(B->rpo_number(), AnyOf(1, 2)); + EXPECT_THAT(C->rpo_number(), AnyOf(1, 2)); + EXPECT_EQ(3, D->rpo_number()); +} + +TEST_F(SchedulerRPOTest, Loop1) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, Loop2) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(B, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, LoopN) { + for (int i = 0; i < 11; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, F); + schedule.AddSuccessorForTesting(F, B); + schedule.AddSuccessorForTesting(B, G); + + // Throw in extra backedges from time to time. + if (i == 1) schedule.AddSuccessorForTesting(B, B); + if (i == 2) schedule.AddSuccessorForTesting(C, B); + if (i == 3) schedule.AddSuccessorForTesting(D, B); + if (i == 4) schedule.AddSuccessorForTesting(E, B); + if (i == 5) schedule.AddSuccessorForTesting(F, B); + + // Throw in extra loop exits from time to time. + if (i == 6) schedule.AddSuccessorForTesting(B, G); + if (i == 7) schedule.AddSuccessorForTesting(C, G); + if (i == 8) schedule.AddSuccessorForTesting(D, G); + if (i == 9) schedule.AddSuccessorForTesting(E, G); + if (i == 10) schedule.AddSuccessorForTesting(F, G); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 7, true); + BasicBlock* loop[] = {B, C, D, E, F}; + CheckLoop(order, loop, 5); + } +} + +TEST_F(SchedulerRPOTest, LoopNest1) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, C); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, B); + schedule.AddSuccessorForTesting(E, F); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 6, true); + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoop(order, loop1, 4); + + BasicBlock* loop2[] = {C, D}; + CheckLoop(order, loop2, 2); +} + +TEST_F(SchedulerRPOTest, LoopNest2) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.NewBasicBlock(); + BasicBlock* H = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, F); + schedule.AddSuccessorForTesting(F, G); + schedule.AddSuccessorForTesting(G, H); + + schedule.AddSuccessorForTesting(E, D); + schedule.AddSuccessorForTesting(F, C); + schedule.AddSuccessorForTesting(G, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 8, true); + BasicBlock* loop1[] = {B, C, D, E, F, G}; + CheckLoop(order, loop1, 6); + + BasicBlock* loop2[] = {C, D, E, F}; + CheckLoop(order, loop2, 4); + + BasicBlock* loop3[] = {D, E}; + CheckLoop(order, loop3, 2); +} + +TEST_F(SchedulerRPOTest, LoopFollow1) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); +} + +TEST_F(SchedulerRPOTest, LoopFollow2) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* S = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), S); + schedule.AddSuccessorForTesting(S, loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); +} + +TEST_F(SchedulerRPOTest, LoopFollowN) { + for (int size = 1; size < 5; size++) { + for (int exit = 0; exit < size; exit++) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header()); + schedule.AddSuccessorForTesting(loop2->nodes[exit], E); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); + } + } +} + +TEST_F(SchedulerRPOTest, NestedLoopFollow1) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), C); + schedule.AddSuccessorForTesting(C, E); + schedule.AddSuccessorForTesting(C, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); + + BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C}; + CheckLoop(order, loop3, 4); +} + +TEST_F(SchedulerRPOTest, LoopBackedges1) { + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[j], E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } + } +} + +TEST_F(SchedulerRPOTest, LoopOutedges1) { + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[j], D); + schedule.AddSuccessorForTesting(D, E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } + } +} + +TEST_F(SchedulerRPOTest, LoopOutedges2) { + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + for (int j = 0; j < size; j++) { + BasicBlock* O = schedule.NewBasicBlock(); + schedule.AddSuccessorForTesting(loop1->nodes[j], O); + schedule.AddSuccessorForTesting(O, E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } +} + +TEST_F(SchedulerRPOTest, LoopOutloops1) { + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + TestLoop** loopN = new TestLoop*[size]; + for (int j = 0; j < size; j++) { + loopN[j] = CreateLoop(&schedule, 2); + schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header()); + schedule.AddSuccessorForTesting(loopN[j]->last(), E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + + for (int j = 0; j < size; j++) { + CheckLoop(order, loopN[j]->nodes, loopN[j]->count); + delete loopN[j]; + } + delete[] loopN; + } +} + +TEST_F(SchedulerRPOTest, LoopMultibackedge) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(B, D); + schedule.AddSuccessorForTesting(B, E); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(D, B); + schedule.AddSuccessorForTesting(E, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 5, true); + + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoop(order, loop1, 4); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/scheduler-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-unittest.cc index 523c8ce9d4..6cf07345a2 100644 --- a/deps/v8/test/unittests/compiler/scheduler-unittest.cc +++ b/deps/v8/test/unittests/compiler/scheduler-unittest.cc @@ -71,67 +71,6 @@ class SchedulerTest : public TestWithIsolateAndZone { }; -class SchedulerRPOTest : public SchedulerTest { - public: - SchedulerRPOTest() {} - - // TODO(titzer): pull RPO tests out to their own file. - void CheckRPONumbers(BasicBlockVector* order, size_t expected, - bool loops_allowed) { - CHECK(expected == order->size()); - for (int i = 0; i < static_cast<int>(order->size()); i++) { - CHECK(order->at(i)->rpo_number() == i); - if (!loops_allowed) { - CHECK(!order->at(i)->loop_end()); - CHECK(!order->at(i)->loop_header()); - } - } - } - - void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) { - BasicBlock* header = blocks[0]; - BasicBlock* end = header->loop_end(); - CHECK(end); - CHECK_GT(end->rpo_number(), 0); - CHECK_EQ(body_size, end->rpo_number() - header->rpo_number()); - for (int i = 0; i < body_size; i++) { - CHECK_GE(blocks[i]->rpo_number(), header->rpo_number()); - CHECK_LT(blocks[i]->rpo_number(), end->rpo_number()); - CHECK(header->LoopContains(blocks[i])); - CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header); - } - if (header->rpo_number() > 0) { - CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header); - } - if (end->rpo_number() < static_cast<int>(order->size())) { - CHECK_NE(order->at(end->rpo_number())->loop_header(), header); - } - } - - struct TestLoop { - int count; - BasicBlock** nodes; - BasicBlock* header() { return nodes[0]; } - BasicBlock* last() { return nodes[count - 1]; } - ~TestLoop() { delete[] nodes; } - }; - - TestLoop* CreateLoop(Schedule* schedule, int count) { - TestLoop* loop = new TestLoop(); - loop->count = count; - loop->nodes = new BasicBlock* [count]; - for (int i = 0; i < count; i++) { - loop->nodes[i] = schedule->NewBasicBlock(); - if (i > 0) { - schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]); - } - } - schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]); - return loop; - } -}; - - namespace { const Operator kHeapConstant(IrOpcode::kHeapConstant, Operator::kPure, @@ -146,491 +85,6 @@ const Operator kMockTailCall(IrOpcode::kTailCall, Operator::kNoProperties, } // namespace -// ----------------------------------------------------------------------------- -// Special reverse-post-order block ordering. - - -TEST_F(SchedulerRPOTest, Degenerate1) { - Schedule schedule(zone()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1, false); - EXPECT_EQ(schedule.start(), order->at(0)); -} - - -TEST_F(SchedulerRPOTest, Degenerate2) { - Schedule schedule(zone()); - - schedule.AddGoto(schedule.start(), schedule.end()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 2, false); - EXPECT_EQ(schedule.start(), order->at(0)); - EXPECT_EQ(schedule.end(), order->at(1)); -} - - -TEST_F(SchedulerRPOTest, Line) { - for (int i = 0; i < 10; i++) { - Schedule schedule(zone()); - - BasicBlock* last = schedule.start(); - for (int j = 0; j < i; j++) { - BasicBlock* block = schedule.NewBasicBlock(); - block->set_deferred(i & 1); - schedule.AddGoto(last, block); - last = block; - } - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1 + i, false); - - for (size_t i = 0; i < schedule.BasicBlockCount(); i++) { - BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i)); - if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) { - EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number()); - } - } - } -} - - -TEST_F(SchedulerRPOTest, SelfLoop) { - Schedule schedule(zone()); - schedule.AddSuccessorForTesting(schedule.start(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1, true); - BasicBlock* loop[] = {schedule.start()}; - CheckLoop(order, loop, 1); -} - - -TEST_F(SchedulerRPOTest, EntryLoop) { - Schedule schedule(zone()); - BasicBlock* body = schedule.NewBasicBlock(); - schedule.AddSuccessorForTesting(schedule.start(), body); - schedule.AddSuccessorForTesting(body, schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 2, true); - BasicBlock* loop[] = {schedule.start(), body}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, EndLoop) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); - schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 3, true); - CheckLoop(order, loop1->nodes, loop1->count); -} - - -TEST_F(SchedulerRPOTest, EndLoopNested) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); - schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 3, true); - CheckLoop(order, loop1->nodes, loop1->count); -} - - -TEST_F(SchedulerRPOTest, Diamond) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(A, C); - schedule.AddSuccessorForTesting(B, D); - schedule.AddSuccessorForTesting(C, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, false); - - EXPECT_EQ(0, A->rpo_number()); - EXPECT_THAT(B->rpo_number(), AnyOf(1, 2)); - EXPECT_THAT(C->rpo_number(), AnyOf(1, 2)); - EXPECT_EQ(3, D->rpo_number()); -} - - -TEST_F(SchedulerRPOTest, Loop1) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(C, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, true); - BasicBlock* loop[] = {B, C}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, Loop2) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(B, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, true); - BasicBlock* loop[] = {B, C}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, LoopN) { - for (int i = 0; i < 11; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.NewBasicBlock(); - BasicBlock* G = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, F); - schedule.AddSuccessorForTesting(F, B); - schedule.AddSuccessorForTesting(B, G); - - // Throw in extra backedges from time to time. - if (i == 1) schedule.AddSuccessorForTesting(B, B); - if (i == 2) schedule.AddSuccessorForTesting(C, B); - if (i == 3) schedule.AddSuccessorForTesting(D, B); - if (i == 4) schedule.AddSuccessorForTesting(E, B); - if (i == 5) schedule.AddSuccessorForTesting(F, B); - - // Throw in extra loop exits from time to time. - if (i == 6) schedule.AddSuccessorForTesting(B, G); - if (i == 7) schedule.AddSuccessorForTesting(C, G); - if (i == 8) schedule.AddSuccessorForTesting(D, G); - if (i == 9) schedule.AddSuccessorForTesting(E, G); - if (i == 10) schedule.AddSuccessorForTesting(F, G); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 7, true); - BasicBlock* loop[] = {B, C, D, E, F}; - CheckLoop(order, loop, 5); - } -} - - -TEST_F(SchedulerRPOTest, LoopNest1) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, C); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, B); - schedule.AddSuccessorForTesting(E, F); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 6, true); - BasicBlock* loop1[] = {B, C, D, E}; - CheckLoop(order, loop1, 4); - - BasicBlock* loop2[] = {C, D}; - CheckLoop(order, loop2, 2); -} - - -TEST_F(SchedulerRPOTest, LoopNest2) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.NewBasicBlock(); - BasicBlock* G = schedule.NewBasicBlock(); - BasicBlock* H = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, F); - schedule.AddSuccessorForTesting(F, G); - schedule.AddSuccessorForTesting(G, H); - - schedule.AddSuccessorForTesting(E, D); - schedule.AddSuccessorForTesting(F, C); - schedule.AddSuccessorForTesting(G, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 8, true); - BasicBlock* loop1[] = {B, C, D, E, F, G}; - CheckLoop(order, loop1, 6); - - BasicBlock* loop2[] = {C, D, E, F}; - CheckLoop(order, loop2, 4); - - BasicBlock* loop3[] = {D, E}; - CheckLoop(order, loop3, 2); -} - - -TEST_F(SchedulerRPOTest, LoopFollow1) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); -} - - -TEST_F(SchedulerRPOTest, LoopFollow2) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* S = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), S); - schedule.AddSuccessorForTesting(S, loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); -} - - -TEST_F(SchedulerRPOTest, LoopFollowN) { - for (int size = 1; size < 5; size++) { - for (int exit = 0; exit < size; exit++) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header()); - schedule.AddSuccessorForTesting(loop2->nodes[exit], E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); - } - } -} - - -TEST_F(SchedulerRPOTest, NestedLoopFollow1) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), C); - schedule.AddSuccessorForTesting(C, E); - schedule.AddSuccessorForTesting(C, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); - - BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C}; - CheckLoop(order, loop3, 4); -} - - -TEST_F(SchedulerRPOTest, LoopBackedges1) { - int size = 8; - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[j], E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } - } -} - - -TEST_F(SchedulerRPOTest, LoopOutedges1) { - int size = 8; - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[j], D); - schedule.AddSuccessorForTesting(D, E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } - } -} - - -TEST_F(SchedulerRPOTest, LoopOutedges2) { - int size = 8; - for (int i = 0; i < size; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - for (int j = 0; j < size; j++) { - BasicBlock* O = schedule.NewBasicBlock(); - schedule.AddSuccessorForTesting(loop1->nodes[j], O); - schedule.AddSuccessorForTesting(O, E); - } - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } -} - - -TEST_F(SchedulerRPOTest, LoopOutloops1) { - int size = 8; - for (int i = 0; i < size; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - TestLoop** loopN = new TestLoop* [size]; - for (int j = 0; j < size; j++) { - loopN[j] = CreateLoop(&schedule, 2); - schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header()); - schedule.AddSuccessorForTesting(loopN[j]->last(), E); - } - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - - for (int j = 0; j < size; j++) { - CheckLoop(order, loopN[j]->nodes, loopN[j]->count); - delete loopN[j]; - } - delete[] loopN; - } -} - - -TEST_F(SchedulerRPOTest, LoopMultibackedge) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(B, D); - schedule.AddSuccessorForTesting(B, E); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(D, B); - schedule.AddSuccessorForTesting(E, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 5, true); - - BasicBlock* loop1[] = {B, C, D, E}; - CheckLoop(order, loop1, 4); -} - - -// ----------------------------------------------------------------------------- -// Graph end-to-end scheduling. - - TEST_F(SchedulerTest, BuildScheduleEmpty) { graph()->SetStart(graph()->NewNode(common()->Start(0))); graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index 871189ad79..bd8509ff97 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -6,7 +6,7 @@ #include "src/compiler/operator.h" #include "src/compiler/operator-properties.h" #include "src/compiler/simplified-operator.h" -#include "src/types-inl.h" +#include "src/types.h" #include "test/unittests/test-utils.h" namespace v8 { @@ -65,6 +65,8 @@ const PureOperator kPureOperators[] = { PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1), PURE(ChangeBoolToBit, Operator::kNoProperties, 1), PURE(ChangeBitToBool, Operator::kNoProperties, 1), + PURE(ObjectIsNumber, Operator::kNoProperties, 1), + PURE(ObjectIsReceiver, Operator::kNoProperties, 1), PURE(ObjectIsSmi, Operator::kNoProperties, 1) #undef PURE }; diff --git a/deps/v8/test/unittests/compiler/typer-unittest.cc b/deps/v8/test/unittests/compiler/typer-unittest.cc index 6e4d4d589f..9d664a6d3a 100644 --- a/deps/v8/test/unittests/compiler/typer-unittest.cc +++ b/deps/v8/test/unittests/compiler/typer-unittest.cc @@ -49,7 +49,7 @@ class TyperTest : public TypedGraphTest { } } - Types<Type, Type*, Zone> types_; + Types types_; JSOperatorBuilder javascript_; BinaryOperationHints const hints_ = BinaryOperationHints::Any(); Node* context_node_; @@ -115,7 +115,7 @@ class TyperTest : public TypedGraphTest { return result; } - double RandomInt(Type::RangeType* range) { + double RandomInt(RangeType* range) { return RandomInt(range->Min(), range->Max()); } @@ -149,12 +149,12 @@ class TyperTest : public TypedGraphTest { void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { TestBinaryArithOpCloseToZero(op, opfun, 8); for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange()->AsRange(); - Type::RangeType* r2 = RandomRange()->AsRange(); + Type* r1 = RandomRange(); + Type* r2 = RandomRange(); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - double x1 = RandomInt(r1); - double x2 = RandomInt(r2); + double x1 = RandomInt(r1->AsRange()); + double x2 = RandomInt(r2->AsRange()); double result_value = opfun(x1, x2); Type* result_type = Type::Constant( isolate()->factory()->NewNumber(result_value), zone()); @@ -166,12 +166,12 @@ class TyperTest : public TypedGraphTest { template <class BinaryFunction> void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange()->AsRange(); - Type::RangeType* r2 = RandomRange()->AsRange(); + Type* r1 = RandomRange(); + Type* r2 = RandomRange(); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - double x1 = RandomInt(r1); - double x2 = RandomInt(r2); + double x1 = RandomInt(r1->AsRange()); + double x2 = RandomInt(r2->AsRange()); bool result_value = opfun(x1, x2); Type* result_type = Type::Constant(result_value ? isolate()->factory()->true_value() @@ -185,12 +185,12 @@ class TyperTest : public TypedGraphTest { template <class BinaryFunction> void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange(true)->AsRange(); - Type::RangeType* r2 = RandomRange(true)->AsRange(); + Type* r1 = RandomRange(true); + Type* r2 = RandomRange(true); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - int32_t x1 = static_cast<int32_t>(RandomInt(r1)); - int32_t x2 = static_cast<int32_t>(RandomInt(r2)); + int32_t x1 = static_cast<int32_t>(RandomInt(r1->AsRange())); + int32_t x2 = static_cast<int32_t>(RandomInt(r2->AsRange())); double result_value = opfun(x1, x2); Type* result_type = Type::Constant( isolate()->factory()->NewNumber(result_value), zone()); @@ -240,109 +240,72 @@ int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } TEST_F(TyperTest, TypeJSAdd) { - TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY, hints_), - std::plus<double>()); - TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG, hints_), - std::plus<double>()); + TestBinaryArithOp(javascript_.Add(hints_), std::plus<double>()); } TEST_F(TyperTest, TypeJSSubtract) { - TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY, hints_), - std::minus<double>()); - TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG, hints_), - std::minus<double>()); + TestBinaryArithOp(javascript_.Subtract(hints_), std::minus<double>()); } TEST_F(TyperTest, TypeJSMultiply) { - TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY, hints_), - std::multiplies<double>()); - TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG, hints_), - std::multiplies<double>()); + TestBinaryArithOp(javascript_.Multiply(hints_), std::multiplies<double>()); } TEST_F(TyperTest, TypeJSDivide) { - TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY, hints_), - std::divides<double>()); - TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG, hints_), - std::divides<double>()); + TestBinaryArithOp(javascript_.Divide(hints_), std::divides<double>()); } TEST_F(TyperTest, TypeJSModulus) { - TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY, hints_), modulo); - TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG, hints_), modulo); + TestBinaryArithOp(javascript_.Modulus(hints_), modulo); } TEST_F(TyperTest, TypeJSBitwiseOr) { - TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY, hints_), bit_or); - TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG, hints_), bit_or); + TestBinaryBitOp(javascript_.BitwiseOr(hints_), bit_or); } TEST_F(TyperTest, TypeJSBitwiseAnd) { - TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY, hints_), - bit_and); - TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG, hints_), - bit_and); + TestBinaryBitOp(javascript_.BitwiseAnd(hints_), bit_and); } TEST_F(TyperTest, TypeJSBitwiseXor) { - TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY, hints_), - bit_xor); - TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG, hints_), - bit_xor); + TestBinaryBitOp(javascript_.BitwiseXor(hints_), bit_xor); } TEST_F(TyperTest, TypeJSShiftLeft) { - TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY, hints_), - shift_left); - TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG, hints_), - shift_left); + TestBinaryBitOp(javascript_.ShiftLeft(hints_), shift_left); } TEST_F(TyperTest, TypeJSShiftRight) { - TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY, hints_), - shift_right); - TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG, hints_), - shift_right); + TestBinaryBitOp(javascript_.ShiftRight(hints_), shift_right); } TEST_F(TyperTest, TypeJSLessThan) { - TestBinaryCompareOp(javascript_.LessThan(LanguageMode::SLOPPY), - std::less<double>()); - TestBinaryCompareOp(javascript_.LessThan(LanguageMode::STRONG), - std::less<double>()); + TestBinaryCompareOp(javascript_.LessThan(), std::less<double>()); } TEST_F(TyperTest, TypeJSLessThanOrEqual) { - TestBinaryCompareOp(javascript_.LessThanOrEqual(LanguageMode::SLOPPY), - std::less_equal<double>()); - TestBinaryCompareOp(javascript_.LessThanOrEqual(LanguageMode::STRONG), - std::less_equal<double>()); + TestBinaryCompareOp(javascript_.LessThanOrEqual(), std::less_equal<double>()); } TEST_F(TyperTest, TypeJSGreaterThan) { - TestBinaryCompareOp(javascript_.GreaterThan(LanguageMode::SLOPPY), - std::greater<double>()); - TestBinaryCompareOp(javascript_.GreaterThan(LanguageMode::STRONG), - std::greater<double>()); + TestBinaryCompareOp(javascript_.GreaterThan(), std::greater<double>()); } TEST_F(TyperTest, TypeJSGreaterThanOrEqual) { - TestBinaryCompareOp(javascript_.GreaterThanOrEqual(LanguageMode::SLOPPY), - std::greater_equal<double>()); - TestBinaryCompareOp(javascript_.GreaterThanOrEqual(LanguageMode::STRONG), + TestBinaryCompareOp(javascript_.GreaterThanOrEqual(), std::greater_equal<double>()); } @@ -381,27 +344,15 @@ TEST_BINARY_MONOTONICITY(Equal) TEST_BINARY_MONOTONICITY(NotEqual) TEST_BINARY_MONOTONICITY(StrictEqual) TEST_BINARY_MONOTONICITY(StrictNotEqual) -#undef TEST_BINARY_MONOTONICITY - - -#define TEST_BINARY_MONOTONICITY(name) \ - TEST_F(TyperTest, Monotonicity_##name) { \ - TestBinaryMonotonicity(javascript_.name(LanguageMode::SLOPPY)); \ - TestBinaryMonotonicity(javascript_.name(LanguageMode::STRONG)); \ - } TEST_BINARY_MONOTONICITY(LessThan) TEST_BINARY_MONOTONICITY(GreaterThan) TEST_BINARY_MONOTONICITY(LessThanOrEqual) TEST_BINARY_MONOTONICITY(GreaterThanOrEqual) #undef TEST_BINARY_MONOTONICITY - -#define TEST_BINARY_MONOTONICITY(name) \ - TEST_F(TyperTest, Monotonicity_##name) { \ - TestBinaryMonotonicity( \ - javascript_.name(LanguageMode::SLOPPY, BinaryOperationHints::Any())); \ - TestBinaryMonotonicity( \ - javascript_.name(LanguageMode::STRONG, BinaryOperationHints::Any())); \ +#define TEST_BINARY_MONOTONICITY(name) \ + TEST_F(TyperTest, Monotonicity_##name) { \ + TestBinaryMonotonicity(javascript_.name(BinaryOperationHints::Any())); \ } TEST_BINARY_MONOTONICITY(BitwiseOr) TEST_BINARY_MONOTONICITY(BitwiseXor) diff --git a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc index 1088f0127d..4787bc66d2 100644 --- a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc +++ b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc @@ -74,10 +74,9 @@ MemoryReducer::Event TimerEventPendingGC(double time_ms) { return TimerEvent(time_ms, true, false); } - -MemoryReducer::Event ContextDisposedEvent(double time_ms) { +MemoryReducer::Event PossibleGarbageEvent(double time_ms) { MemoryReducer::Event event; - event.type = MemoryReducer::kContextDisposed; + event.type = MemoryReducer::kPossibleGarbage; event.time_ms = time_ms; return event; } @@ -114,7 +113,7 @@ TEST(MemoryReducer, FromDoneToWait) { EXPECT_EQ(0, state1.started_gcs); EXPECT_EQ(2, state1.last_gc_time_ms); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(0)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(0)); EXPECT_EQ(MemoryReducer::kWait, state1.action); EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); EXPECT_EQ(0, state1.started_gcs); @@ -127,7 +126,7 @@ TEST(MemoryReducer, FromWaitToWait) { MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState()); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); EXPECT_EQ(MemoryReducer::kWait, state1.action); EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); EXPECT_EQ(state0.started_gcs, state1.started_gcs); @@ -250,7 +249,7 @@ TEST(MemoryReducer, FromRunToRun) { EXPECT_EQ(state0.started_gcs, state1.started_gcs); EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); EXPECT_EQ(MemoryReducer::kRun, state1.action); EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); EXPECT_EQ(state0.started_gcs, state1.started_gcs); diff --git a/deps/v8/test/unittests/heap/slot-set-unittest.cc b/deps/v8/test/unittests/heap/slot-set-unittest.cc new file mode 100644 index 0000000000..376188915a --- /dev/null +++ b/deps/v8/test/unittests/heap/slot-set-unittest.cc @@ -0,0 +1,143 @@ +// Copyright 2016 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. + +#include <limits> + +#include "src/globals.h" +#include "src/heap/slot-set.h" +#include "src/heap/spaces.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +TEST(SlotSet, InsertAndLookup1) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + set.Insert(i); + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_TRUE(set.Lookup(i)); + } +} + +TEST(SlotSet, InsertAndLookup2) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +TEST(SlotSet, Iterate) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + + set.Iterate([](Address slot_address) { + uintptr_t intaddr = reinterpret_cast<uintptr_t>(slot_address); + if (intaddr % 3 == 0) { + return SlotSet::KEEP_SLOT; + } else { + return SlotSet::REMOVE_SLOT; + } + }); + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 21 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +TEST(SlotSet, Remove) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 3 != 0) { + set.Remove(i); + } + } + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 21 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +void CheckRemoveRangeOn(uint32_t start, uint32_t end) { + SlotSet set; + set.SetPageStart(0); + uint32_t first = start == 0 ? 0 : start - kPointerSize; + uint32_t last = end == Page::kPageSize ? end - kPointerSize : end; + for (uint32_t i = first; i <= last; i += kPointerSize) { + set.Insert(i); + } + set.RemoveRange(start, end); + if (first != start) { + EXPECT_TRUE(set.Lookup(first)); + } + if (last == end) { + EXPECT_TRUE(set.Lookup(last)); + } + for (uint32_t i = start; i < end; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } +} + +TEST(SlotSet, RemoveRange) { + CheckRemoveRangeOn(0, Page::kPageSize); + CheckRemoveRangeOn(1 * kPointerSize, 1023 * kPointerSize); + for (uint32_t start = 0; start <= 32; start++) { + CheckRemoveRangeOn(start * kPointerSize, (start + 1) * kPointerSize); + CheckRemoveRangeOn(start * kPointerSize, (start + 2) * kPointerSize); + const uint32_t kEnds[] = {32, 64, 100, 128, 1024, 1500, 2048}; + for (int i = 0; i < sizeof(kEnds) / sizeof(uint32_t); i++) { + for (int k = -3; k <= 3; k++) { + uint32_t end = (kEnds[i] + k); + if (start < end) { + CheckRemoveRangeOn(start * kPointerSize, end * kPointerSize); + } + } + } + } + SlotSet set; + set.SetPageStart(0); + set.Insert(Page::kPageSize / 2); + set.RemoveRange(0, Page::kPageSize); + for (uint32_t i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 2140aa83c7..839215f743 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -21,14 +21,16 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { - BytecodeArrayBuilder builder(isolate(), zone()); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131); - builder.set_locals_count(200); - builder.set_context_count(1); - builder.set_parameter_count(0); - CHECK_EQ(builder.locals_count(), 200); + CHECK_EQ(builder.locals_count(), 131); CHECK_EQ(builder.context_count(), 1); - CHECK_EQ(builder.fixed_register_count(), 201); + CHECK_EQ(builder.fixed_register_count(), 132); + + // Emit argument creation operations. + builder.CreateArguments(CreateArgumentsType::kMappedArguments) + .CreateArguments(CreateArgumentsType::kUnmappedArguments) + .CreateArguments(CreateArgumentsType::kRestParameter); // Emit constant loads. builder.LoadLiteral(Smi::FromInt(0)) @@ -40,32 +42,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .LoadTrue() .LoadFalse(); - // Emit accumulator transfers. Stores followed by loads to the same register - // are not generated. Hence, a dummy instruction in between. Register reg(0); + Register other(reg.index() + 1); + Register wide(128); + builder.LoadAccumulatorWithRegister(reg) .LoadNull() .StoreAccumulatorInRegister(reg); // Emit register-register transfer. - Register other(1); builder.MoveRegister(reg, other); - - // Emit register-register exchanges. - Register wide(150); - builder.ExchangeRegisters(reg, wide); - builder.ExchangeRegisters(wide, reg); - Register wider(151); - builder.ExchangeRegisters(wide, wider); + builder.MoveRegister(reg, wide); // Emit global load / store operations. Factory* factory = isolate()->factory(); Handle<String> name = factory->NewStringFromStaticChars("var_name"); - builder.LoadGlobal(name, 1, LanguageMode::SLOPPY, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) + builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF) + .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF) .StoreGlobal(name, 1, LanguageMode::SLOPPY) .StoreGlobal(name, 1, LanguageMode::STRICT); @@ -76,12 +69,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .StoreContextSlot(reg, 1); // Emit load / store property operations. - builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY) - .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY) + builder.LoadNamedProperty(reg, name, 0) + .LoadKeyedProperty(reg, 0) .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY) .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY) - .LoadNamedProperty(reg, name, 0, LanguageMode::STRICT) - .LoadKeyedProperty(reg, 0, LanguageMode::STRICT) .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT) .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); @@ -97,65 +88,64 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { false); builder.CreateClosure(shared_info, NOT_TENURED); - // Emit argument creation operations. - builder.CreateArguments(CreateArgumentsType::kMappedArguments) - .CreateArguments(CreateArgumentsType::kUnmappedArguments); - // Emit literal creation operations. builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0) .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0) .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0); // Call operations. - builder.Call(reg, reg, 0, 0) - .Call(reg, reg, 0, 1024) + builder.Call(reg, other, 1, 0) + .Call(reg, wide, 1, 0) + .TailCall(reg, other, 1, 0) + .TailCall(reg, wide, 1, 0) .CallRuntime(Runtime::kIsArray, reg, 1) - .CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg) - .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1); + .CallRuntime(Runtime::kIsArray, wide, 1) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other) + .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1) + .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1); // Emit binary operator invocations. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SUB, reg, Strength::WEAK) - .BinaryOperation(Token::Value::MUL, reg, Strength::WEAK) - .BinaryOperation(Token::Value::DIV, reg, Strength::WEAK) - .BinaryOperation(Token::Value::MOD, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::ADD, reg) + .BinaryOperation(Token::Value::SUB, reg) + .BinaryOperation(Token::Value::MUL, reg) + .BinaryOperation(Token::Value::DIV, reg) + .BinaryOperation(Token::Value::MOD, reg); // Emit bitwise operator invocations - builder.BinaryOperation(Token::Value::BIT_OR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::BIT_XOR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::BIT_AND, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::BIT_OR, reg) + .BinaryOperation(Token::Value::BIT_XOR, reg) + .BinaryOperation(Token::Value::BIT_AND, reg); // Emit shift operator invocations - builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SAR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SHR, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::SHL, reg) + .BinaryOperation(Token::Value::SAR, reg) + .BinaryOperation(Token::Value::SHR, reg); // Emit count operatior invocations - builder.CountOperation(Token::Value::ADD, Strength::WEAK) - .CountOperation(Token::Value::SUB, Strength::WEAK); + builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB); // Emit unary operator invocations. builder.LogicalNot().TypeOf(); // Emit delete - builder.Delete(reg, LanguageMode::SLOPPY) - .Delete(reg, LanguageMode::STRICT) - .DeleteLookupSlot(); + builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); // Emit new. builder.New(reg, reg, 0); + builder.New(wide, wide, 0); // Emit test operator invocations. - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .CompareOperation(Token::Value::NE, reg, Strength::WEAK) - .CompareOperation(Token::Value::EQ_STRICT, reg, Strength::WEAK) - .CompareOperation(Token::Value::NE_STRICT, reg, Strength::WEAK) - .CompareOperation(Token::Value::LT, reg, Strength::WEAK) - .CompareOperation(Token::Value::GT, reg, Strength::WEAK) - .CompareOperation(Token::Value::LTE, reg, Strength::WEAK) - .CompareOperation(Token::Value::GTE, reg, Strength::WEAK) - .CompareOperation(Token::Value::INSTANCEOF, reg, Strength::WEAK) - .CompareOperation(Token::Value::IN, reg, Strength::WEAK); + builder.CompareOperation(Token::Value::EQ, reg) + .CompareOperation(Token::Value::NE, reg) + .CompareOperation(Token::Value::EQ_STRICT, reg) + .CompareOperation(Token::Value::NE_STRICT, reg) + .CompareOperation(Token::Value::LT, reg) + .CompareOperation(Token::Value::GT, reg) + .CompareOperation(Token::Value::LTE, reg) + .CompareOperation(Token::Value::GTE, reg) + .CompareOperation(Token::Value::INSTANCEOF, reg) + .CompareOperation(Token::Value::IN, reg); // Emit cast operator invocations. builder.CastAccumulatorToNumber() @@ -168,50 +158,58 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { // Short jumps with Imm8 operands builder.Jump(&start) .JumpIfNull(&start) - .JumpIfUndefined(&start); + .JumpIfUndefined(&start) + .JumpIfNotHole(&start); + // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); // Insert dummy ops to force longer jumps for (int i = 0; i < 128; i++) { builder.LoadTrue(); } // Longer jumps requiring Constant operand - builder.Jump(&start) - .JumpIfNull(&start) - .JumpIfUndefined(&start); + builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole( + &start); // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); - // Emit throw in it's own basic block so that the rest of the code isn't - // omitted due to being dead. + // Emit stack check bytecode. + builder.StackCheck(); + + // Emit throw and re-throw in it's own basic block so that the rest of the + // code isn't omitted due to being dead. BytecodeLabel after_throw; - builder.Jump(&after_throw) - .Throw() - .Bind(&after_throw); + builder.Jump(&after_throw).Throw().Bind(&after_throw); + BytecodeLabel after_rethrow; + builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow); - builder.ForInPrepare(reg, reg, reg) + builder.ForInPrepare(reg) .ForInDone(reg, reg) - .ForInNext(reg, reg, reg, reg) + .ForInNext(reg, reg, reg) + .ForInStep(reg); + builder.ForInPrepare(wide) + .ForInDone(reg, other) + .ForInNext(wide, wide, wide) .ForInStep(reg); // Wide constant pool loads @@ -223,28 +221,21 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name"); // Emit wide global load / store operations. - builder.LoadGlobal(name, 1024, LanguageMode::SLOPPY, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(wide_name, 1, LanguageMode::STRICT, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) - .LoadGlobal(wide_name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) + builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF) + .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF) .StoreGlobal(name, 1024, LanguageMode::SLOPPY) .StoreGlobal(wide_name, 1, LanguageMode::STRICT); // Emit wide load / store property operations. - builder.LoadNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) - .LoadKeyedProperty(reg, 2056, LanguageMode::SLOPPY) + builder.LoadNamedProperty(reg, wide_name, 0) + .LoadKeyedProperty(reg, 2056) .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY) - .LoadNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) - .LoadKeyedProperty(reg, 2056, LanguageMode::STRICT) .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT); // Emit wide context operations. - builder.LoadContextSlot(reg, 1024) - .StoreContextSlot(reg, 1024); + builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024); // Emit wide load / store lookup slots. builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF) @@ -265,26 +256,31 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0); // Longer jumps requiring ConstantWide operand - builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start); + builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole( + &start); // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); + builder.Debugger(); + builder.Return(); // Generate BytecodeArray. Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); CHECK_EQ(the_array->frame_size(), - builder.fixed_register_count() * kPointerSize); + (builder.fixed_and_temporary_register_count() + + builder.translation_register_count()) * + kPointerSize); // Build scorecard of bytecodes encountered in the BytecodeArray. std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); @@ -301,9 +297,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { CHECK_EQ(final_bytecode, Bytecode::kReturn); CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1); -#define CHECK_BYTECODE_PRESENT(Name, ...) \ - /* Check Bytecode is marked in scorecard */ \ - CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); +#define CHECK_BYTECODE_PRESENT(Name, ...) \ + /* Check Bytecode is marked in scorecard, unless it's a debug break */ \ + if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) { \ + CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); \ + } BYTECODE_LIST(CHECK_BYTECODE_PRESENT) #undef CHECK_BYTECODE_PRESENT } @@ -313,12 +311,9 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { for (int locals = 0; locals < 5; locals++) { for (int contexts = 0; contexts < 4; contexts++) { for (int temps = 0; temps < 3; temps++) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(locals); - builder.set_context_count(contexts); - - BytecodeRegisterAllocator temporaries(&builder); + BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals); + BytecodeRegisterAllocator temporaries( + zone(), builder.temporary_register_allocator()); for (int i = 0; i < temps; i++) { builder.StoreAccumulatorInRegister(temporaries.NewRegister()); } @@ -349,11 +344,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) { TEST_F(BytecodeArrayBuilderTest, Parameters) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(10); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0); Register param0(builder.Parameter(0)); Register param9(builder.Parameter(9)); CHECK_EQ(param9.index() - param0.index(), 9); @@ -361,12 +352,9 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { TEST_F(BytecodeArrayBuilderTest, RegisterType) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(10); - builder.set_locals_count(3); - builder.set_context_count(0); - - BytecodeRegisterAllocator register_allocator(&builder); + BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3); + BytecodeRegisterAllocator register_allocator( + zone(), builder.temporary_register_allocator()); Register temp0 = register_allocator.NewRegister(); Register param0(builder.Parameter(0)); Register param9(builder.Parameter(9)); @@ -387,11 +375,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterType) { TEST_F(BytecodeArrayBuilderTest, Constants) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); Factory* factory = isolate()->factory(); Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); @@ -402,7 +386,8 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { .LoadLiteral(large_smi) .LoadLiteral(heap_num_1) .LoadLiteral(heap_num_1) - .LoadLiteral(heap_num_2_copy); + .LoadLiteral(heap_num_2_copy) + .Return(); Handle<BytecodeArray> array = builder.ToBytecodeArray(); // Should only have one entry for each identical constant. @@ -413,23 +398,19 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { static const int kFarJumpDistance = 256; - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(1); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); Register reg(0); BytecodeLabel far0, far1, far2, far3, far4; BytecodeLabel near0, near1, near2, near3, near4; builder.Jump(&near0) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&near1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&near2) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&near3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&near4) .Bind(&near0) .Bind(&near1) @@ -437,13 +418,13 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { .Bind(&near3) .Bind(&near4) .Jump(&far0) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&far1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&far2) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&far3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&far4); for (int i = 0; i < kFarJumpDistance - 18; i++) { builder.LoadUndefined(); @@ -529,38 +510,31 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(1); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); Register reg(0); BytecodeLabel label0, label1, label2, label3, label4; builder.Bind(&label0) .Jump(&label0) .Bind(&label1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&label1) .Bind(&label2) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&label2) .Bind(&label3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&label3) .Bind(&label4) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&label4); for (int i = 0; i < 63; i++) { builder.Jump(&label4); } - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .JumpIfFalse(&label4); - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .JumpIfTrue(&label3); - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .JumpIfFalse(&label2); - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .JumpIfTrue(&label1); + builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4); + builder.BinaryOperation(Token::Value::ADD, reg).JumpIfTrue(&label3); + builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2); + builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1); builder.Jump(&label0); builder.Return(); @@ -625,10 +599,7 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { TEST_F(BytecodeArrayBuilderTest, LabelReuse) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); // Labels can only have 1 forward reference, but // can be referred to mulitple times once bound. @@ -656,16 +627,11 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) { TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { static const int kRepeats = 3; - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); for (int i = 0; i < kRepeats; i++) { BytecodeLabel label; builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); } - builder.Return(); Handle<BytecodeArray> array = builder.ToBytecodeArray(); @@ -686,7 +652,6 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { CHECK(iterator.done()); } - } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc index cd9f120cad..f2dcd7107c 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc @@ -22,11 +22,7 @@ class BytecodeArrayIteratorTest : public TestWithIsolateAndZone { TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { // Use a builder to create an array with containing multiple bytecodes // with 0, 1 and 2 operands. - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(3); - builder.set_locals_count(2); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 3, 2, 0); Factory* factory = isolate()->factory(); Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718); Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(2147483647); @@ -46,9 +42,10 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { .LoadLiteral(smi_0) .LoadLiteral(smi_1) .LoadAccumulatorWithRegister(reg_0) - .LoadNamedProperty(reg_1, name, feedback_slot, LanguageMode::SLOPPY) + .LoadNamedProperty(reg_1, name, feedback_slot) .StoreAccumulatorInRegister(reg_2) .CallRuntime(Runtime::kLoadIC_Miss, reg_0, 1) + .Debugger() .Return(); // Test iterator sees the expected output from the builder. @@ -82,7 +79,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { CHECK(!iterator.done()); iterator.Advance(); - CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadICSloppy); + CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadIC); CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); CHECK_EQ(iterator.GetIndexOperand(1), name_index); CHECK_EQ(iterator.GetIndexOperand(2), feedback_slot); @@ -98,7 +95,11 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { CHECK_EQ(static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0)), Runtime::kLoadIC_Miss); CHECK_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); - CHECK_EQ(iterator.GetCountOperand(2), 1); + CHECK_EQ(iterator.GetRegisterCountOperand(2), 1); + CHECK(!iterator.done()); + iterator.Advance(); + + CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger); CHECK(!iterator.done()); iterator.Advance(); diff --git a/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc index 0620322162..ec29935b2f 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc @@ -12,51 +12,219 @@ namespace v8 { namespace internal { namespace interpreter { +class TemporaryRegisterAllocatorTest : public TestWithIsolateAndZone { + public: + TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {} + ~TemporaryRegisterAllocatorTest() override {} + TemporaryRegisterAllocator* allocator() { return &allocator_; } + + private: + TemporaryRegisterAllocator allocator_; +}; + +TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) { + CHECK_EQ(allocator()->allocation_count(), 0); + int reg0_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg0_index, 0); + CHECK_EQ(allocator()->allocation_count(), 1); + CHECK(allocator()->RegisterIsLive(Register(reg0_index))); + allocator()->ReturnTemporaryRegister(reg0_index); + CHECK(!allocator()->RegisterIsLive(Register(reg0_index))); + CHECK_EQ(allocator()->allocation_count(), 1); + CHECK(allocator()->first_temporary_register() == Register(0)); + CHECK(allocator()->last_temporary_register() == Register(0)); +} + +TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) { + for (int i = 0; i < 13; i++) { + int reg_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg_index, i); + CHECK_EQ(allocator()->allocation_count(), i + 1); + } + for (int i = 0; i < 13; i++) { + CHECK(allocator()->RegisterIsLive(Register(i))); + allocator()->ReturnTemporaryRegister(i); + CHECK(!allocator()->RegisterIsLive(Register(i))); + int reg_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg_index, i); + CHECK_EQ(allocator()->allocation_count(), 13); + } + for (int i = 0; i < 13; i++) { + CHECK(allocator()->RegisterIsLive(Register(i))); + allocator()->ReturnTemporaryRegister(i); + CHECK(!allocator()->RegisterIsLive(Register(i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) { + static const int kRunLength = 7; + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) { + static const int kFreeCount = 3; + static const int kRunLength = 6; + + for (int i = 0; i < kFreeCount; i++) { + int to_free = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(to_free, i); + } + for (int i = 0; i < kFreeCount; i++) { + allocator()->ReturnTemporaryRegister(i); + } + + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingHole) { + static const int kPreAllocatedCount = 7; + static const int kPreAllocatedFreeCount = 6; + static const int kRunLength = 8; + + for (int i = 0; i < kPreAllocatedCount; i++) { + int to_free = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(to_free, i); + } + for (int i = 0; i < kPreAllocatedFreeCount; i++) { + allocator()->ReturnTemporaryRegister(i); + } + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + CHECK_EQ(start, kPreAllocatedCount); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAvailableInTemporaries) { + static const int kNotRunLength = 13; + static const int kRunLength = 8; + + // Allocate big batch + for (int i = 0; i < kNotRunLength * 2 + kRunLength; i++) { + int allocated = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(allocated, i); + } + // Free every other register either side of target. + for (int i = 0; i < kNotRunLength; i++) { + if ((i & 2) == 1) { + allocator()->ReturnTemporaryRegister(i); + allocator()->ReturnTemporaryRegister(kNotRunLength + kRunLength + i); + } + } + // Free all registers for target. + for (int i = kNotRunLength; i < kNotRunLength + kRunLength; i++) { + allocator()->ReturnTemporaryRegister(i); + } + + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK_EQ(start, kNotRunLength); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAvoidsTranslationBoundary) { + int boundary = RegisterTranslator::DistanceToTranslationWindow(Register(0)); + int limit = boundary + 64; + + for (int run_length = 2; run_length < 32; run_length += 7) { + ZoneVector<int> run_starts(zone()); + for (int start = 0; start < limit; start += run_length) { + int run_start = + allocator()->PrepareForConsecutiveTemporaryRegisters(run_length); + run_starts.push_back(run_start); + for (int i = 0; i < run_length; i++) { + allocator()->BorrowConsecutiveTemporaryRegister(run_start + i); + } + CHECK(run_start >= boundary || run_start + run_length <= boundary); + } + for (size_t batch = 0; batch < run_starts.size(); batch++) { + for (int i = run_starts[batch]; i < run_starts[batch] + run_length; i++) { + allocator()->ReturnTemporaryRegister(i); + } + } + } +} + +TEST_F(TemporaryRegisterAllocatorTest, NotInRange) { + for (int i = 0; i < 10; i++) { + int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5); + CHECK(reg == i || (reg > 2 && reg == i + 4)); + } + for (int i = 0; i < 10; i++) { + if (i < 2) { + allocator()->ReturnTemporaryRegister(i); + } else { + allocator()->ReturnTemporaryRegister(i + 4); + } + } + int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3); + CHECK_EQ(reg0, 4); + int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10); + CHECK_EQ(reg1, 2); + int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6); + CHECK_EQ(reg2, 1); + allocator()->ReturnTemporaryRegister(reg0); + allocator()->ReturnTemporaryRegister(reg1); + allocator()->ReturnTemporaryRegister(reg2); +} + class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { public: BytecodeRegisterAllocatorTest() {} ~BytecodeRegisterAllocatorTest() override {} }; - TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); int first; { - BytecodeRegisterAllocator temporaries(&builder); - first = temporaries.NewRegister().index(); - temporaries.NewRegister(); - temporaries.NewRegister(); - temporaries.NewRegister(); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + first = allocator.NewRegister().index(); + allocator.NewRegister(); + allocator.NewRegister(); + allocator.NewRegister(); } int second; { - BytecodeRegisterAllocator temporaries(&builder); - second = temporaries.NewRegister().index(); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + second = allocator.NewRegister().index(); } CHECK_EQ(first, second); } - TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - - BytecodeRegisterAllocator temporaries(&builder); - temporaries.PrepareForConsecutiveAllocations(4); - Register reg0 = temporaries.NextConsecutiveRegister(); - Register other = temporaries.NewRegister(); - Register reg1 = temporaries.NextConsecutiveRegister(); - Register reg2 = temporaries.NextConsecutiveRegister(); - Register reg3 = temporaries.NextConsecutiveRegister(); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + allocator.PrepareForConsecutiveAllocations(4); + Register reg0 = allocator.NextConsecutiveRegister(); + Register other = allocator.NewRegister(); + Register reg1 = allocator.NextConsecutiveRegister(); + Register reg2 = allocator.NextConsecutiveRegister(); + Register reg3 = allocator.NextConsecutiveRegister(); USE(other); CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); diff --git a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc index 812ee46c9c..212e02996b 100644 --- a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc @@ -9,19 +9,39 @@ #include "src/interpreter/bytecodes.h" #include "test/unittests/test-utils.h" - namespace v8 { namespace internal { namespace interpreter { TEST(OperandConversion, Registers) { - for (int i = 0; i < 128; i++) { - uint8_t operand_value = Register(i).ToOperand(); - Register r = Register::FromOperand(operand_value); - CHECK_EQ(i, r.index()); + int register_count = Register::MaxRegisterIndex() + 1; + int step = register_count / 7; + for (int i = 0; i < register_count; i += step) { + if (i <= kMaxInt8) { + uint8_t operand0 = Register(i).ToOperand(); + Register reg0 = Register::FromOperand(operand0); + CHECK_EQ(i, reg0.index()); + } + + uint16_t operand1 = Register(i).ToWideOperand(); + Register reg1 = Register::FromWideOperand(operand1); + CHECK_EQ(i, reg1.index()); + + uint32_t operand2 = Register(i).ToRawOperand(); + Register reg2 = Register::FromRawOperand(operand2); + CHECK_EQ(i, reg2.index()); } -} + for (int i = 0; i <= kMaxUInt8; i++) { + uint8_t operand = static_cast<uint8_t>(i); + Register reg = Register::FromOperand(operand); + if (i > 0 && i < -kMinInt8) { + CHECK(reg.is_parameter()); + } else { + CHECK(!reg.is_parameter()); + } + } +} TEST(OperandConversion, Parameters) { int parameter_counts[] = {7, 13, 99}; @@ -38,26 +58,115 @@ TEST(OperandConversion, Parameters) { } } - TEST(OperandConversion, RegistersParametersNoOverlap) { - std::vector<uint8_t> operand_count(256); + int register_count = Register::MaxRegisterIndex() + 1; + int parameter_count = Register::MaxParameterIndex() + 1; + int32_t register_space_size = base::bits::RoundUpToPowerOfTwo32( + static_cast<uint32_t>(register_count + parameter_count)); + uint32_t range = static_cast<uint32_t>(register_space_size); + std::vector<uint8_t> operand_count(range); - for (int i = 0; i <= kMaxInt8; i++) { + for (int i = 0; i < register_count; i += 1) { Register r = Register(i); - uint8_t operand = r.ToOperand(); + uint32_t operand = r.ToWideOperand(); + CHECK_LT(operand, operand_count.size()); operand_count[operand] += 1; CHECK_EQ(operand_count[operand], 1); } - int parameter_count = Register::MaxParameterIndex() + 1; - for (int i = 0; i < parameter_count; i++) { + for (int i = 0; i < parameter_count; i += 1) { Register r = Register::FromParameterIndex(i, parameter_count); - uint8_t operand = r.ToOperand(); + uint32_t operand = r.ToWideOperand(); + CHECK_LT(operand, operand_count.size()); operand_count[operand] += 1; CHECK_EQ(operand_count[operand], 1); } } +TEST(Bytecodes, HasAnyRegisterOperands) { + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kAdd), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCall), 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntime), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeWide), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeForPair), + 2); + CHECK_EQ( + Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeForPairWide), + 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kDeletePropertyStrict), + 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kForInPrepare), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kForInPrepareWide), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kInc), 0); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kJumpIfTrue), 0); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kNew), 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kToName), 0); +} + +TEST(Bytecodes, RegisterOperandBitmaps) { + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kAdd), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kCallRuntimeForPair), + 10); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kStar), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kMov), 3); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kTestIn), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInPrepare), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInDone), 3); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInNext), 7); +} + +TEST(Bytecodes, RegisterOperands) { + CHECK(Bytecodes::IsRegisterOperandType(OperandType::kReg8)); + CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::kReg8)); + CHECK(!Bytecodes::IsRegisterOutputOperandType(OperandType::kReg8)); + CHECK(!Bytecodes::IsRegisterInputOperandType(OperandType::kRegOut8)); + CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::kRegOut8)); + +#define IS_REGISTER_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterOperandType(OperandType::k##Name)); + REGISTER_OPERAND_TYPE_LIST(IS_REGISTER_OPERAND_TYPE) +#undef IS_REGISTER_OPERAND_TYPE + +#define IS_NOT_REGISTER_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OPERAND_TYPE) +#undef IS_NOT_REGISTER_OPERAND_TYPE + +#define IS_REGISTER_INPUT_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::k##Name)); + REGISTER_INPUT_OPERAND_TYPE_LIST(IS_REGISTER_INPUT_OPERAND_TYPE) +#undef IS_REGISTER_INPUT_OPERAND_TYPE + +#define IS_NOT_REGISTER_INPUT_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterInputOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_INPUT_OPERAND_TYPE); + REGISTER_OUTPUT_OPERAND_TYPE_LIST(IS_NOT_REGISTER_INPUT_OPERAND_TYPE) +#undef IS_NOT_REGISTER_INPUT_OPERAND_TYPE + +#define IS_REGISTER_OUTPUT_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::k##Name)); + REGISTER_OUTPUT_OPERAND_TYPE_LIST(IS_REGISTER_OUTPUT_OPERAND_TYPE) +#undef IS_REGISTER_OUTPUT_OPERAND_TYPE + +#define IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterOutputOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE) + REGISTER_INPUT_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE) +#undef IS_NOT_REGISTER_INPUT_OPERAND_TYPE +} + +TEST(Bytecodes, DebugBreak) { + for (uint32_t i = 0; i < Bytecodes::ToByte(Bytecode::kLast); i++) { + Bytecode bytecode = Bytecodes::FromByte(i); + Bytecode debugbreak = Bytecodes::GetDebugBreak(bytecode); + if (!Bytecodes::IsDebugBreak(debugbreak)) { + PrintF("Bytecode %s has no matching debug break with length %d\n", + Bytecodes::ToString(bytecode), Bytecodes::Size(bytecode)); + CHECK(false); + } + } +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc index ea5d1bb8c3..b3ec5ff668 100644 --- a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc @@ -33,13 +33,11 @@ STATIC_CONST_MEMBER_DEFINITION const size_t TEST_F(ConstantArrayBuilderTest, AllocateAllEntries) { ConstantArrayBuilder builder(isolate(), zone()); for (size_t i = 0; i < kMaxCapacity; i++) { - Handle<Object> object = isolate()->factory()->NewNumberFromSize(i); - builder.Insert(object); - CHECK_EQ(builder.size(), i + 1); - CHECK(builder.At(i)->SameValue(*object)); + builder.Insert(handle(Smi::FromInt(static_cast<int>(i)), isolate())); } + CHECK_EQ(builder.size(), kMaxCapacity); for (size_t i = 0; i < kMaxCapacity; i++) { - CHECK_EQ(Handle<Smi>::cast(builder.At(i))->value(), static_cast<double>(i)); + CHECK_EQ(Handle<Smi>::cast(builder.At(i))->value(), i); } } @@ -158,8 +156,7 @@ TEST_F(ConstantArrayBuilderTest, ToFixedArray) { builder.Insert(object); CHECK(builder.At(i)->SameValue(*object)); } - Handle<FixedArray> constant_array = - builder.ToFixedArray(isolate()->factory()); + Handle<FixedArray> constant_array = builder.ToFixedArray(); CHECK_EQ(constant_array->length(), kNumberOfElements); for (size_t i = 0; i < kNumberOfElements; i++) { CHECK(constant_array->get(static_cast<int>(i))->SameValue(*builder.At(i))); diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc index f57ca05b3f..3375a6b817 100644 --- a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc +++ b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/interpreter-assembler-unittest.h" +#include "test/unittests/interpreter/interpreter-assembler-unittest.h" #include "src/code-factory.h" #include "src/compiler/graph.h" @@ -16,7 +16,10 @@ using ::testing::_; namespace v8 { namespace internal { -namespace compiler { + +using namespace compiler; + +namespace interpreter { const interpreter::Bytecode kBytecodes[] = { #define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name, @@ -24,55 +27,47 @@ const interpreter::Bytecode kBytecodes[] = { #undef DEFINE_BYTECODE }; - Matcher<Node*> IsIntPtrConstant(const intptr_t value) { return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value)) : IsInt32Constant(static_cast<int32_t>(value)); } - Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher) : IsInt32Add(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher) : IsInt32Sub(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) : IsWord32Shl(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher) : IsWord32Sar(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher) : IsWord32Or(lhs_matcher, rhs_matcher); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad( const Matcher<LoadRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) { return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( const Matcher<StoreRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, @@ -81,52 +76,57 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( value_matcher, _, _); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand( int offset) { return IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: IsBytecodeOperandSignExtended(int offset) { Matcher<Node*> load_matcher = IsLoad( MachineType::Int8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); if (kPointerSize == 8) { load_matcher = IsChangeInt32ToInt64(load_matcher); } return load_matcher; } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( int offset) { if (TargetSupportsUnalignedAccess()) { return IsLoad( MachineType::Uint16(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } else { Matcher<Node*> first_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); Matcher<Node*> second_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset + 1))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset + 1))); #if V8_TARGET_LITTLE_ENDIAN return IsWordOr(IsWordShl(second_byte, IsInt32Constant(kBitsPerByte)), first_byte); @@ -139,16 +139,17 @@ InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( } } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: IsBytecodeOperandShortSignExtended(int offset) { Matcher<Node*> load_matcher; if (TargetSupportsUnalignedAccess()) { load_matcher = IsLoad( MachineType::Int16(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } else { #if V8_TARGET_LITTLE_ENDIAN int hi_byte_offset = offset + 1; @@ -162,15 +163,19 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: #endif Matcher<Node*> hi_byte = IsLoad( MachineType::Int8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(hi_byte_offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(hi_byte_offset))); hi_byte = IsWord32Shl(hi_byte, IsInt32Constant(kBitsPerByte)); Matcher<Node*> lo_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(lo_byte_offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(lo_byte_offset))); load_matcher = IsWord32Or(hi_byte, lo_byte); } @@ -180,7 +185,6 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: return load_matcher; } - TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -191,35 +195,37 @@ TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(interpreter::Bytecodes::Size(bytecode))); - Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); - - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(interpreter::Bytecodes::Size(bytecode))); + Matcher<Node*> target_bytecode_matcher = m.IsLoad( + MachineType::Uint8(), + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); + EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, Jump) { + // If debug code is enabled we emit extra code in Jump. + if (FLAG_debug_code) return; + int jump_offsets[] = {-9710, -77, 0, +3, +97109}; TRACED_FOREACH(int, jump_offset, jump_offsets) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -230,38 +236,39 @@ TARGET_TEST_F(InterpreterAssemblerTest, Jump) { EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(jump_offset)); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(jump_offset)); Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); - - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); + m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); + EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter( + InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, _, + IsParameter( + InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } } - TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) { static const int kJumpIfTrueOffset = 73; + // If debug code is enabled we emit extra code in Jump. + if (FLAG_debug_code) return; + MachineOperatorBuilder machine(zone()); TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -276,61 +283,64 @@ TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) { int jump_offsets[] = {kJumpIfTrueOffset, interpreter::Bytecodes::Size(bytecode)}; for (int i = 0; i < static_cast<int>(arraysize(jump_offsets)); i++) { - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(jump_offsets[i])); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(jump_offsets[i])); Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); + m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); EXPECT_THAT( end->InputAt(i), - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter( + InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, _, + IsParameter( + InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } // TODO(oth): test control flow paths. } } +TARGET_TEST_F(InterpreterAssemblerTest, InterpreterReturn) { + // If debug code is enabled we emit extra code in InterpreterReturn. + if (FLAG_debug_code) return; -TARGET_TEST_F(InterpreterAssemblerTest, Return) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); - m.Return(); + m.InterpreterReturn(); Graph* graph = m.graph(); Node* end = graph->end(); EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); Handle<HeapObject> exit_trampoline = isolate()->builtins()->InterpreterExitTrampoline(); EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline), - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, IsHeapConstant(exit_trampoline), + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + _, + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -338,7 +348,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { for (int i = 0; i < number_of_operands; i++) { int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i); switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { - case interpreter::OperandType::kCount8: + case interpreter::OperandType::kRegCount8: EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(offset)); break; case interpreter::OperandType::kIdx8: @@ -350,11 +360,14 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { break; case interpreter::OperandType::kMaybeReg8: case interpreter::OperandType::kReg8: + case interpreter::OperandType::kRegOut8: + case interpreter::OperandType::kRegOutPair8: + case interpreter::OperandType::kRegOutTriple8: case interpreter::OperandType::kRegPair8: EXPECT_THAT(m.BytecodeOperandReg(i), m.IsBytecodeOperandSignExtended(offset)); break; - case interpreter::OperandType::kCount16: + case interpreter::OperandType::kRegCount16: EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperandShort(offset)); break; @@ -362,7 +375,12 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperandShort(offset)); break; + case interpreter::OperandType::kMaybeReg16: case interpreter::OperandType::kReg16: + case interpreter::OperandType::kRegOut16: + case interpreter::OperandType::kRegOutPair16: + case interpreter::OperandType::kRegOutTriple16: + case interpreter::OperandType::kRegPair16: EXPECT_THAT(m.BytecodeOperandReg(i), m.IsBytecodeOperandShortSignExtended(offset)); break; @@ -374,15 +392,15 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { } } - TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); // Should be incoming accumulator if not set. - EXPECT_THAT(m.GetAccumulator(), - IsParameter(Linkage::kInterpreterAccumulatorParameter)); + EXPECT_THAT( + m.GetAccumulator(), + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter)); - // Should be set by SedtAccumulator. + // Should be set by SetAccumulator. Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef); m.SetAccumulator(accumulator_value_1); EXPECT_THAT(m.GetAccumulator(), accumulator_value_1); @@ -399,11 +417,18 @@ TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { Node* tail_call_node = end->InputAt(0); EXPECT_THAT(tail_call_node, - IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _, - _, _, _)); + IsTailCall(_, _, accumulator_value_2, _, _, _, _, _, _)); } } +TARGET_TEST_F(InterpreterAssemblerTest, GetSetContext) { + TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { + InterpreterAssemblerForTest m(this, bytecode); + Node* context_node = m.Int32Constant(100); + m.SetContext(context_node); + EXPECT_THAT(m.GetContext(), context_node); + } +} TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -413,12 +438,11 @@ TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { EXPECT_THAT( reg_location_node, IsIntPtrAdd( - IsParameter(Linkage::kInterpreterRegisterFileParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -426,13 +450,13 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { Node* load_reg_node = m.LoadRegister(reg_index_node); EXPECT_THAT( load_reg_node, - m.IsLoad(MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); + m.IsLoad( + MachineType::AnyTagged(), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); } } - TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -441,15 +465,15 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { Node* store_reg_node = m.StoreRegister(store_value, reg_index_node); EXPECT_THAT( store_reg_node, - m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, - kNoWriteBarrier), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)), - store_value)); + m.IsStore( + StoreRepresentation(MachineRepresentation::kTagged, + kNoWriteBarrier), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)), + store_value)); } } - TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -461,7 +485,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { } } - TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -472,7 +495,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { } } - TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -483,7 +505,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { } } - TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -493,7 +514,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -501,7 +521,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { Node* load_constant = m.LoadConstantPoolEntry(index); Matcher<Node*> constant_pool_matcher = m.IsLoad( MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag)); EXPECT_THAT( load_constant, @@ -512,7 +532,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadFixedArrayElement) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -529,7 +548,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadFixedArrayElement) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -542,7 +560,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -558,7 +575,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { } } - TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -577,21 +593,22 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { } } - TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); Node* arg1 = m.Int32Constant(2); Node* arg2 = m.Int32Constant(3); - Node* call_runtime = m.CallRuntime(Runtime::kAdd, arg1, arg2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); + Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2); EXPECT_THAT( call_runtime, IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { const int kResultSizes[] = {1, 2}; TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -602,6 +619,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { Node* function_id = m.Int32Constant(0); Node* first_arg = m.Int32Constant(1); Node* arg_count = m.Int32Constant(2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); Matcher<Node*> function_table = IsExternalConstant( ExternalReference::runtime_function_table_address(isolate())); @@ -612,63 +631,53 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { m.IsLoad(MachineType::Pointer(), function, IsInt32Constant(offsetof(Runtime::Function, entry))); - Node* call_runtime = - m.CallRuntime(function_id, first_arg, arg_count, result_size); + Node* call_runtime = m.CallRuntimeN(function_id, context, first_arg, + arg_count, result_size); EXPECT_THAT( call_runtime, IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, function_entry, - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsParameter(InterpreterDispatchDescriptor::kContextParameter), + _, _)); } } } - -TARGET_TEST_F(InterpreterAssemblerTest, CallIC) { - TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { - InterpreterAssemblerForTest m(this, bytecode); - LoadWithVectorDescriptor descriptor(isolate()); - Node* target = m.Int32Constant(1); - Node* arg1 = m.Int32Constant(2); - Node* arg2 = m.Int32Constant(3); - Node* arg3 = m.Int32Constant(4); - Node* arg4 = m.Int32Constant(5); - Node* call_ic = m.CallIC(descriptor, target, arg1, arg2, arg3, arg4); - EXPECT_THAT( - call_ic, - IsCall(_, target, arg1, arg2, arg3, arg4, - IsParameter(Linkage::kInterpreterContextParameter), _, _)); - } -} - - TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { - TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { - InterpreterAssemblerForTest m(this, bytecode); - Callable builtin = CodeFactory::InterpreterPushArgsAndCall(isolate()); - Node* function = m.Int32Constant(0); - Node* first_arg = m.Int32Constant(1); - Node* arg_count = m.Int32Constant(2); - Node* call_js = m.CallJS(function, first_arg, arg_count); - EXPECT_THAT( - call_js, - IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, - function, IsParameter(Linkage::kInterpreterContextParameter), _, - _)); + TailCallMode tail_call_modes[] = {TailCallMode::kDisallow, + TailCallMode::kAllow}; + TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) { + TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { + InterpreterAssemblerForTest m(this, bytecode); + Callable builtin = + CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode); + Node* function = m.Int32Constant(0); + Node* first_arg = m.Int32Constant(1); + Node* arg_count = m.Int32Constant(2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); + Node* call_js = + m.CallJS(function, context, first_arg, arg_count, tail_call_mode); + EXPECT_THAT( + call_js, + IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, + function, + IsParameter(InterpreterDispatchDescriptor::kContextParameter), + _, _)); + } } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); Node* feedback_vector = m.LoadTypeFeedbackVector(); - Matcher<Node*> load_function_matcher = - m.IsLoad(MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsIntPtrConstant( - InterpreterFrameConstants::kFunctionFromRegisterPointer)); + Matcher<Node*> load_function_matcher = m.IsLoad( + MachineType::AnyTagged(), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsIntPtrConstant( + InterpreterFrameConstants::kFunctionFromRegisterPointer)); Matcher<Node*> load_shared_function_info_matcher = m.IsLoad(MachineType::AnyTagged(), load_function_matcher, IsIntPtrConstant(JSFunction::kSharedFunctionInfoOffset - @@ -682,6 +691,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { } } -} // namespace compiler +} // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h new file mode 100644 index 0000000000..321c72490b --- /dev/null +++ b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h @@ -0,0 +1,57 @@ +// Copyright 2015 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. + +#ifndef V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ +#define V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ + +#include "src/compiler/machine-operator.h" +#include "src/interpreter/interpreter-assembler.h" +#include "test/unittests/test-utils.h" +#include "testing/gmock-support.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +using ::testing::Matcher; + +class InterpreterAssemblerTest : public TestWithIsolateAndZone { + public: + InterpreterAssemblerTest() {} + ~InterpreterAssemblerTest() override {} + + class InterpreterAssemblerForTest final : public InterpreterAssembler { + public: + InterpreterAssemblerForTest(InterpreterAssemblerTest* test, + Bytecode bytecode) + : InterpreterAssembler(test->isolate(), test->zone(), bytecode) {} + ~InterpreterAssemblerForTest() override {} + + Matcher<compiler::Node*> IsLoad( + const Matcher<compiler::LoadRepresentation>& rep_matcher, + const Matcher<compiler::Node*>& base_matcher, + const Matcher<compiler::Node*>& index_matcher); + Matcher<compiler::Node*> IsStore( + const Matcher<compiler::StoreRepresentation>& rep_matcher, + const Matcher<compiler::Node*>& base_matcher, + const Matcher<compiler::Node*>& index_matcher, + const Matcher<compiler::Node*>& value_matcher); + + Matcher<compiler::Node*> IsBytecodeOperand(int offset); + Matcher<compiler::Node*> IsBytecodeOperandSignExtended(int offset); + Matcher<compiler::Node*> IsBytecodeOperandShort(int offset); + Matcher<compiler::Node*> IsBytecodeOperandShortSignExtended(int offset); + + using InterpreterAssembler::graph; + + private: + DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest); + }; +}; + +} // namespace interpreter +} // namespace internal +} // namespace v8 + +#endif // V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ diff --git a/deps/v8/test/unittests/interpreter/register-translator-unittest.cc b/deps/v8/test/unittests/interpreter/register-translator-unittest.cc new file mode 100644 index 0000000000..e9f65a6af0 --- /dev/null +++ b/deps/v8/test/unittests/interpreter/register-translator-unittest.cc @@ -0,0 +1,260 @@ +// Copyright 2014 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. + +#include <stack> + +#include "src/v8.h" + +#include "src/interpreter/register-translator.h" +#include "src/isolate.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +class RegisterTranslatorTest : public TestWithIsolateAndZone, + private RegisterMover { + public: + RegisterTranslatorTest() : translator_(this), move_count_(0) { + window_start_ = + RegisterTranslator::DistanceToTranslationWindow(Register(0)); + window_width_ = + Register::MaxRegisterIndexForByteOperand() - window_start_ + 1; + } + + ~RegisterTranslatorTest() override {} + + bool PopMoveAndMatch(Register from, Register to) { + if (!moves_.empty()) { + CHECK(from.is_valid() && to.is_valid()); + const std::pair<Register, Register> top = moves_.top(); + moves_.pop(); + return top.first == from && top.second == to; + } else { + return false; + } + } + + int move_count() const { return move_count_; } + RegisterTranslator* translator() { return &translator_; } + + int window_start() const { return window_start_; } + int window_width() const { return window_width_; } + int window_limit() const { return window_start_ + window_width_; } + + protected: + static const char* const kBadOperandRegex; + + private: + void MoveRegisterUntranslated(Register from, Register to) override { + moves_.push(std::make_pair(from, to)); + move_count_++; + } + + RegisterTranslator translator_; + std::stack<std::pair<Register, Register>> moves_; + int move_count_; + int window_start_; + int window_width_; +}; + +const char* const RegisterTranslatorTest::kBadOperandRegex = + ".*OperandType::kReg8 \\|\\| .*OperandType::kRegOut8\\) && " + "RegisterIsMovableToWindow.*"; + +TEST_F(RegisterTranslatorTest, TestFrameSizeAdjustmentsForTranslationWindow) { + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(0, 0)); + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(10, 10)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 0)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 137)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 137)); + // TODO(oth): Add a kMaxParameters8 that derives this info from the frame. + int param_limit = FLAG_enable_embedded_constant_pool ? 119 : 120; + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(0, param_limit)); + EXPECT_EQ(window_limit(), + RegisterTranslator::RegisterCountAdjustment(0, 128)); + EXPECT_EQ(window_limit(), + RegisterTranslator::RegisterCountAdjustment(0, 129)); + EXPECT_EQ(window_limit() - 32, + RegisterTranslator::RegisterCountAdjustment(32, 129)); +} + +TEST_F(RegisterTranslatorTest, TestInTranslationWindow) { + EXPECT_GE(window_start(), 0); + EXPECT_FALSE( + RegisterTranslator::InTranslationWindow(Register(window_start() - 1))); + EXPECT_TRUE(RegisterTranslator::InTranslationWindow( + Register(Register::MaxRegisterIndexForByteOperand()))); + EXPECT_FALSE(RegisterTranslator::InTranslationWindow( + Register(Register::MaxRegisterIndexForByteOperand() + 1))); + for (int index = window_start(); index < window_limit(); index += 1) { + EXPECT_TRUE(RegisterTranslator::InTranslationWindow(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, FitsInReg8Operand) { + EXPECT_GT(window_start(), 0); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand( + Register::FromParameterIndex(0, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand( + Register::FromParameterIndex(2, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand(Register(0))); + EXPECT_TRUE( + RegisterTranslator::FitsInReg8Operand(Register(window_start() - 1))); + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(kMaxInt8))); + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(kMaxInt8 + 1))); + for (int index = window_start(); index < window_limit(); index += 1) { + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, FitsInReg16Operand) { + EXPECT_GT(window_start(), 0); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(2, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, 999))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, Register::MaxParameterIndex() + 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(0))); + EXPECT_TRUE( + RegisterTranslator::FitsInReg16Operand(Register(window_start() - 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(kMaxInt8 + 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(kMaxInt8 + 2))); + for (int index = 0; index <= kMaxInt16 - window_width(); index += 1) { + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(index))); + } + for (int index = Register::MaxRegisterIndex() - window_width() + 1; + index < Register::MaxRegisterIndex() + 2; index += 1) { + EXPECT_FALSE(RegisterTranslator::FitsInReg16Operand(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, NoTranslationRequired) { + Register window_reg(window_start()); + Register local_reg(57); + uint32_t operands[] = {local_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); + + Register param_reg = Register::FromParameterIndex(129, 130); + operands[0] = param_reg.ToRawOperand(); + translator()->TranslateInputRegisters(Bytecode::kAdd, operands, 1); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); +} + +TEST_F(RegisterTranslatorTest, TranslationRequired) { + Register window_reg(window_start()); + Register local_reg(137); + Register local_reg_translated(local_reg.index() + window_width()); + + uint32_t operands[] = {local_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + EXPECT_EQ(1, move_count()); + EXPECT_TRUE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(1, move_count()); + EXPECT_FALSE(PopMoveAndMatch(window_reg, local_reg_translated)); + + operands[0] = local_reg.ToRawOperand(); + translator()->TranslateInputRegisters(Bytecode::kStar, operands, 1); + EXPECT_EQ(1, move_count()); + EXPECT_FALSE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(2, move_count()); + EXPECT_TRUE(PopMoveAndMatch(window_reg, local_reg_translated)); + + Register param_reg = Register::FromParameterIndex(0, 130); + operands[0] = {param_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + EXPECT_EQ(3, move_count()); + EXPECT_TRUE(PopMoveAndMatch(param_reg, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(3, move_count()); + EXPECT_FALSE(PopMoveAndMatch(window_reg, param_reg)); + + operands[0] = {param_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kStar, operands, 1); + EXPECT_EQ(3, move_count()); + EXPECT_FALSE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(4, move_count()); + EXPECT_TRUE(PopMoveAndMatch(window_reg, param_reg)); +} + +TEST_F(RegisterTranslatorTest, RangeTranslation) { + Register window0(window_start()); + Register window1(window_start() + 1); + Register window2(window_start() + 2); + uint32_t operands[3]; + + // Bytecode::kNew with valid range operand. + Register constructor0(0); + Register args0(1); + operands[0] = constructor0.ToRawOperand(); + operands[1] = args0.ToRawOperand(); + operands[2] = 1; + translator()->TranslateInputRegisters(Bytecode::kNew, operands, 3); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); + + // Bytecode::kNewWide with valid range operand. + Register constructor1(128); + Register constructor1_translated(constructor1.index() + window_width()); + Register args1(129); + Register args1_translated(args1.index() + window_width()); + operands[0] = constructor1.ToRawOperand(); + operands[1] = args1.ToRawOperand(); + operands[2] = 3; + translator()->TranslateInputRegisters(Bytecode::kNewWide, operands, 3); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); +} + +TEST_F(RegisterTranslatorTest, BadRange0) { + // Bytecode::kNew with invalid range operand (kMaybeReg8). + Register constructor1(128); + Register args1(129); + uint32_t operands[] = {constructor1.ToRawOperand(), args1.ToRawOperand(), 3}; + ASSERT_DEATH_IF_SUPPORTED( + translator()->TranslateInputRegisters(Bytecode::kNew, operands, 3), + kBadOperandRegex); +} + +TEST_F(RegisterTranslatorTest, BadRange1) { + // Bytecode::kForInPrepare with invalid range operand (kRegTriple8) + Register for_in_state(160); + Register for_in_state_translated(for_in_state.index() + window_width()); + uint32_t operands[] = {for_in_state.ToRawOperand()}; + ASSERT_DEATH_IF_SUPPORTED(translator()->TranslateInputRegisters( + Bytecode::kForInPrepare, operands, 1), + kBadOperandRegex); +} + +TEST_F(RegisterTranslatorTest, BadRange2) { + // Bytecode::kForInNext with invalid range operand (kRegPair8) + Register receiver(192); + Register receiver_translated(receiver.index() + window_width()); + Register index(193); + Register index_translated(index.index() + window_width()); + Register cache_info_pair(194); + Register cache_info_pair_translated(cache_info_pair.index() + window_width()); + uint32_t operands[] = {receiver.ToRawOperand(), index.ToRawOperand(), + cache_info_pair.ToRawOperand()}; + ASSERT_DEATH_IF_SUPPORTED( + translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 3), + kBadOperandRegex); +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/unittests.gyp b/deps/v8/test/unittests/unittests.gyp index 5339da35fd..638fd847bf 100644 --- a/deps/v8/test/unittests/unittests.gyp +++ b/deps/v8/test/unittests/unittests.gyp @@ -60,10 +60,9 @@ 'compiler/instruction-selector-unittest.h', 'compiler/instruction-sequence-unittest.cc', 'compiler/instruction-sequence-unittest.h', - 'compiler/interpreter-assembler-unittest.cc', - 'compiler/interpreter-assembler-unittest.h', + 'compiler/int64-lowering-unittest.cc', 'compiler/js-builtin-reducer-unittest.cc', - 'compiler/js-context-relaxation-unittest.cc', + 'compiler/js-create-lowering-unittest.cc', 'compiler/js-intrinsic-lowering-unittest.cc', 'compiler/js-operator-unittest.cc', 'compiler/js-typed-lowering-unittest.cc', @@ -86,6 +85,7 @@ 'compiler/schedule-unittest.cc', 'compiler/select-lowering-unittest.cc', 'compiler/scheduler-unittest.cc', + 'compiler/scheduler-rpo-unittest.cc', 'compiler/simplified-operator-reducer-unittest.cc', 'compiler/simplified-operator-unittest.cc', 'compiler/state-values-utils-unittest.cc', @@ -99,6 +99,9 @@ 'interpreter/bytecode-array-iterator-unittest.cc', 'interpreter/bytecode-register-allocator-unittest.cc', 'interpreter/constant-array-builder-unittest.cc', + 'interpreter/interpreter-assembler-unittest.cc', + 'interpreter/interpreter-assembler-unittest.h', + 'interpreter/register-translator-unittest.cc', 'libplatform/default-platform-unittest.cc', 'libplatform/task-queue-unittest.cc', 'libplatform/worker-thread-unittest.cc', @@ -107,6 +110,7 @@ 'heap/memory-reducer-unittest.cc', 'heap/heap-unittest.cc', 'heap/scavenge-job-unittest.cc', + 'heap/slot-set-unittest.cc', 'locked-queue-unittest.cc', 'run-all-unittests.cc', 'runtime/runtime-interpreter-unittest.cc', @@ -114,6 +118,7 @@ 'test-utils.cc', 'wasm/ast-decoder-unittest.cc', 'wasm/encoder-unittest.cc', + 'wasm/loop-assignment-analysis-unittest.cc', 'wasm/module-decoder-unittest.cc', 'wasm/wasm-macro-gen-unittest.cc', ], diff --git a/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc b/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc index 923c554604..672158714a 100644 --- a/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc @@ -35,6 +35,8 @@ static const WasmOpcode kInt32BinopOpcodes[] = { kExprI32Shl, kExprI32ShrU, kExprI32ShrS, kExprI32Eq, kExprI32LtS, kExprI32LeS, kExprI32LtU, kExprI32LeU}; +#define WASM_BRV_IF_ZERO(depth, val) \ + kExprBrIf, static_cast<byte>(depth), val, WASM_ZERO #define EXPECT_VERIFIES(env, x) Verify(kSuccess, env, x, x + arraysize(x)) @@ -87,10 +89,10 @@ class WasmDecoderTest : public TestWithZone { static void init_env(FunctionEnv* env, FunctionSig* sig) { env->module = nullptr; env->sig = sig; - env->local_int32_count = 0; - env->local_int64_count = 0; - env->local_float32_count = 0; - env->local_float64_count = 0; + env->local_i32_count = 0; + env->local_i64_count = 0; + env->local_f32_count = 0; + env->local_f64_count = 0; env->SumLocals(); } @@ -179,9 +181,9 @@ static FunctionEnv CreateInt32FunctionEnv(FunctionSig* sig, int count) { FunctionEnv env; env.module = nullptr; env.sig = sig; - env.local_int32_count = count; - env.local_float64_count = 0; - env.local_float32_count = 0; + env.local_i32_count = count; + env.local_f64_count = 0; + env.local_f32_count = 0; env.total_locals = static_cast<unsigned>(count + sig->parameter_count()); return env; } @@ -251,9 +253,6 @@ TEST_F(WasmDecoderTest, Int64Const) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, Float32Const) { byte code[] = {kExprF32Const, 0, 0, 0, 0}; float* ptr = reinterpret_cast<float*>(code + 1); @@ -273,8 +272,6 @@ TEST_F(WasmDecoderTest, Float64Const) { } } -#endif - TEST_F(WasmDecoderTest, Int32Const_off_end) { byte code[] = {kExprI32Const, 0xaa, 0xbb, 0xcc, 0x44}; @@ -338,7 +335,7 @@ TEST_F(WasmDecoderTest, GetLocal_off_end) { TEST_F(WasmDecoderTest, GetLocal_varint) { - env_i_i.local_int32_count = 1000000000; + env_i_i.local_i32_count = 1000000000; env_i_i.total_locals += 1000000000; { @@ -532,16 +529,11 @@ TEST_F(WasmDecoderTest, ExprBlock1b) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBlock1c) { static const byte code[] = {kExprBlock, 1, kExprF32Const, 0, 0, 0, 0}; EXPECT_VERIFIES(&env_f_ff, code); } -#endif - TEST_F(WasmDecoderTest, IfEmpty) { static const byte code[] = {kExprIf, kExprGetLocal, 0, kExprNop}; @@ -704,9 +696,6 @@ TEST_F(WasmDecoderTest, ReturnVoid2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ReturnVoid3) { EXPECT_VERIFIES_INLINE(&env_v_v, kExprI8Const, 0); EXPECT_VERIFIES_INLINE(&env_v_v, kExprI32Const, 0, 0, 0, 0); @@ -717,8 +706,6 @@ TEST_F(WasmDecoderTest, ReturnVoid3) { EXPECT_VERIFIES_INLINE(&env_v_i, kExprGetLocal, 0); } -#endif - TEST_F(WasmDecoderTest, Unreachable1) { EXPECT_VERIFIES_INLINE(&env_v_v, kExprUnreachable); @@ -881,9 +868,6 @@ TEST_F(WasmDecoderTest, MacrosStmt) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, MacrosBreak) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BREAK(0))); @@ -895,8 +879,6 @@ TEST_F(WasmDecoderTest, MacrosBreak) { WASM_LOOP(1, WASM_BREAKV(0, WASM_F64(0.0)))); } -#endif - TEST_F(WasmDecoderTest, MacrosContinue) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_CONTINUE(0))); @@ -1204,14 +1186,13 @@ namespace { class TestModuleEnv : public ModuleEnv { public: TestModuleEnv() { - mem_start = 0; - mem_end = 0; + instance = nullptr; module = &mod; linker = nullptr; - function_code = nullptr; mod.globals = new std::vector<WasmGlobal>; mod.signatures = new std::vector<FunctionSig*>; mod.functions = new std::vector<WasmFunction>; + mod.import_table = new std::vector<WasmImport>; } byte AddGlobal(MachineType mem_type) { mod.globals->push_back({0, mem_type, 0, false}); @@ -1228,6 +1209,11 @@ class TestModuleEnv : public ModuleEnv { CHECK(mod.functions->size() <= 127); return static_cast<byte>(mod.functions->size() - 1); } + byte AddImport(FunctionSig* sig) { + mod.import_table->push_back({sig, 0, 0}); + CHECK(mod.import_table->size() <= 127); + return static_cast<byte>(mod.import_table->size() - 1); + } private: WasmModule mod; @@ -1265,9 +1251,6 @@ TEST_F(WasmDecoderTest, CallsWithTooFewArguments) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, CallsWithSpilloverArgs) { static LocalType a_i_ff[] = {kAstI32, kAstF32, kAstF32}; FunctionSig sig_i_ff(1, 2, a_i_ff); @@ -1331,8 +1314,6 @@ TEST_F(WasmDecoderTest, CallsWithMismatchedSigs3) { EXPECT_FAILURE_INLINE(env, WASM_CALL_FUNCTION(1, WASM_F32(17.6))); } -#endif - TEST_F(WasmDecoderTest, SimpleIndirectCalls) { FunctionEnv* env = &env_i_i; @@ -1389,6 +1370,39 @@ TEST_F(WasmDecoderTest, IndirectCallsWithMismatchedSigs3) { EXPECT_FAILURE_INLINE(env, WASM_CALL_INDIRECT(f1, WASM_ZERO, WASM_F32(17.6))); } +TEST_F(WasmDecoderTest, SimpleImportCalls) { + FunctionEnv* env = &env_i_i; + TestModuleEnv module_env; + env->module = &module_env; + + byte f0 = module_env.AddImport(sigs.i_v()); + byte f1 = module_env.AddImport(sigs.i_i()); + byte f2 = module_env.AddImport(sigs.i_ii()); + + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT0(f0)); + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I8(22))); + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT(f2, WASM_I8(32), WASM_I8(72))); +} + +TEST_F(WasmDecoderTest, ImportCallsWithMismatchedSigs3) { + FunctionEnv* env = &env_i_i; + TestModuleEnv module_env; + env->module = &module_env; + + byte f0 = module_env.AddImport(sigs.i_f()); + + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT0(f0)); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_I8(17))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_I64(27))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_F64(37.2))); + + byte f1 = module_env.AddImport(sigs.i_d()); + + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT0(f1)); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I8(16))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I64(16))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_F32(17.6))); +} TEST_F(WasmDecoderTest, Int32Globals) { FunctionEnv* env = &env_i_i; @@ -1575,28 +1589,22 @@ TEST_F(WasmDecoderTest, BreakNesting3) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, BreaksWithMultipleTypes) { EXPECT_FAILURE_INLINE( - &env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(7)), WASM_F32(7.7))); - EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(7)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)))); + &env_i_i, WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_I8(7)), WASM_F32(7.7))); + EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(3, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(8)), - WASM_BRV_IF(0, WASM_ZERO, WASM_I8(0)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)))); + WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_I8(7)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)))); EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(3, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(9)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)), - WASM_BRV_IF(0, WASM_ZERO, WASM_I8(11)))); + WASM_BLOCK(3, WASM_BRV_IF_ZERO(0, WASM_I8(8)), + WASM_BRV_IF_ZERO(0, WASM_I8(0)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)))); + EXPECT_FAILURE_INLINE(&env_i_i, WASM_BLOCK(3, WASM_BRV_IF_ZERO(0, WASM_I8(9)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)), + WASM_BRV_IF_ZERO(0, WASM_I8(11)))); } -#endif - TEST_F(WasmDecoderTest, BreakNesting_6_levels) { for (int mask = 0; mask < 64; mask++) { @@ -1630,9 +1638,6 @@ TEST_F(WasmDecoderTest, BreakNesting_6_levels) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) { FunctionEnv* envs[] = {&env_i_i, &env_l_l, &env_f_ff, &env_d_dd}; for (size_t i = 0; i < arraysize(envs); i++) { @@ -1655,17 +1660,14 @@ TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) { WASM_F64(1.2))); } -#endif - TEST_F(WasmDecoderTest, ExprBreak_TypeCheckAll) { byte code1[] = {WASM_BLOCK(2, WASM_IF(WASM_ZERO, WASM_BRV(0, WASM_GET_LOCAL(0))), WASM_GET_LOCAL(1))}; - byte code2[] = {WASM_BLOCK( - 2, WASM_IF(WASM_ZERO, WASM_BRV_IF(0, WASM_ZERO, WASM_GET_LOCAL(0))), - WASM_GET_LOCAL(1))}; - + byte code2[] = { + WASM_BLOCK(2, WASM_IF(WASM_ZERO, WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(0))), + WASM_GET_LOCAL(1))}; for (size_t i = 0; i < arraysize(kLocalTypes); i++) { for (size_t j = 0; j < arraysize(kLocalTypes); j++) { @@ -1715,37 +1717,42 @@ TEST_F(WasmDecoderTest, ExprBr_Unify) { } } +TEST_F(WasmDecoderTest, ExprBrIf_cond_type) { + FunctionEnv env; + byte code[] = { + WASM_BLOCK(1, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))}; + for (size_t i = 0; i < arraysize(kLocalTypes); i++) { + for (size_t j = 0; j < arraysize(kLocalTypes); j++) { + LocalType types[] = {kLocalTypes[i], kLocalTypes[j]}; + FunctionSig sig(0, 2, types); + init_env(&env, &sig); -TEST_F(WasmDecoderTest, ExprBrIf_type) { - EXPECT_VERIFIES_INLINE( - &env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))); - EXPECT_FAILURE_INLINE( - &env_d_dd, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))); + if (types[1] == kAstI32) { + EXPECT_VERIFIES(&env, code); + } else { + EXPECT_FAILURE(&env, code); + } + } + } +} +TEST_F(WasmDecoderTest, ExprBrIf_val_type) { FunctionEnv env; + byte code[] = { + WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)), + WASM_GET_LOCAL(0))}; for (size_t i = 0; i < arraysize(kLocalTypes); i++) { - LocalType type = kLocalTypes[i]; - LocalType storage[] = {kAstI32, kAstI32, type}; - FunctionSig sig(1, 2, storage); - init_env(&env, &sig); // (i32, X) -> i32 - - byte code1[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), - WASM_GET_LOCAL(0))}; - - byte code2[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(1), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))}; - if (type == kAstI32) { - EXPECT_VERIFIES(&env, code1); - EXPECT_VERIFIES(&env, code2); - } else { - EXPECT_FAILURE(&env, code1); - EXPECT_FAILURE(&env, code2); + for (size_t j = 0; j < arraysize(kLocalTypes); j++) { + LocalType types[] = {kLocalTypes[i], kLocalTypes[i], kLocalTypes[j], + kAstI32}; + FunctionSig sig(1, 3, types); + init_env(&env, &sig); + + if (i == j) { + EXPECT_VERIFIES(&env, code); + } else { + EXPECT_FAILURE(&env, code); + } } } } @@ -1761,13 +1768,10 @@ TEST_F(WasmDecoderTest, ExprBrIf_Unify) { FunctionSig sig(1, 2, storage); init_env(&env, &sig); // (i32, X) -> i32 - byte code1[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_GET_LOCAL(which)), - WASM_GET_LOCAL(which ^ 1))}; - byte code2[] = { - WASM_LOOP(2, WASM_BRV_IF(1, WASM_ZERO, WASM_GET_LOCAL(which)), - WASM_GET_LOCAL(which ^ 1))}; - + byte code1[] = {WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(which)), + WASM_GET_LOCAL(which ^ 1))}; + byte code2[] = {WASM_LOOP(2, WASM_BRV_IF_ZERO(1, WASM_GET_LOCAL(which)), + WASM_GET_LOCAL(which ^ 1))}; if (type == kAstI32) { EXPECT_VERIFIES(&env, code1); @@ -1800,6 +1804,12 @@ TEST_F(WasmDecoderTest, TableSwitch0c) { EXPECT_VERIFIES(&env_v_v, code); } +TEST_F(WasmDecoderTest, TableSwitch0d) { + static byte code[] = { + WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), WASM_CASE_BR(1)), + WASM_I8(67))}; + EXPECT_VERIFIES(&env_v_v, code); +} TEST_F(WasmDecoderTest, TableSwitch1) { static byte code[] = {WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), @@ -1831,9 +1841,6 @@ TEST_F(WasmDecoderTest, TableSwitch2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, TableSwitch1b) { EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_ZERO)); @@ -1845,29 +1852,25 @@ TEST_F(WasmDecoderTest, TableSwitch1b) { WASM_TABLESWITCH_BODY(WASM_ZERO, WASM_F64(0.0))); } -#endif - - -TEST_F(WasmDecoderTest, TableSwitch_br) { - EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(0)), - WASM_GET_LOCAL(0)); +TEST_F(WasmDecoderTest, TableSwitch_br1) { for (int depth = 0; depth < 2; depth++) { - EXPECT_VERIFIES_INLINE( - &env_i_i, WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), - WASM_GET_LOCAL(0))); + byte code[] = {WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), + WASM_GET_LOCAL(0))}; + EXPECT_VERIFIES(&env_v_i, code); + EXPECT_FAILURE(&env_i_i, code); } } TEST_F(WasmDecoderTest, TableSwitch_invalid_br) { for (int depth = 1; depth < 4; depth++) { - EXPECT_FAILURE_INLINE(&env_i_i, + EXPECT_FAILURE_INLINE(&env_v_i, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), WASM_GET_LOCAL(0)); EXPECT_FAILURE_INLINE( - &env_i_i, - WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth + 1)), - WASM_GET_LOCAL(0))); + &env_v_i, + WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(depth), WASM_CASE_BR(depth)), + WASM_GET_LOCAL(0)); } } @@ -1880,17 +1883,12 @@ TEST_F(WasmDecoderTest, TableSwitch_invalid_case_ref) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, TableSwitch1_br) { EXPECT_VERIFIES_INLINE( &env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_BRV(0, WASM_ZERO))); } -#endif - TEST_F(WasmDecoderTest, TableSwitch2_br) { EXPECT_VERIFIES_INLINE( @@ -1914,9 +1912,6 @@ TEST_F(WasmDecoderTest, TableSwitch2x2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBreakNesting1) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BRV(0, WASM_ZERO))); EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BR(0))); @@ -1934,18 +1929,56 @@ TEST_F(WasmDecoderTest, ExprBreakNesting1) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BR(1))); } -#endif - TEST_F(WasmDecoderTest, Select) { EXPECT_VERIFIES_INLINE( + &env_i_i, WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_f_ff, + WASM_SELECT(WASM_F32(0.0), WASM_F32(0.0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_d_dd, + WASM_SELECT(WASM_F64(0.0), WASM_F64(0.0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_l_l, + WASM_SELECT(WASM_I64(0), WASM_I64(0), WASM_ZERO)); +} + +TEST_F(WasmDecoderTest, Select_fail1) { + EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_F32(0.0), WASM_GET_LOCAL(0), + WASM_GET_LOCAL(0))); + EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_GET_LOCAL(0), WASM_F32(0.0), + WASM_GET_LOCAL(0))); + EXPECT_FAILURE_INLINE( &env_i_i, - WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))); + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_F32(0.0))); } +TEST_F(WasmDecoderTest, Select_fail2) { + for (size_t i = 0; i < arraysize(kLocalTypes); i++) { + LocalType type = kLocalTypes[i]; + if (type == kAstI32) continue; + + LocalType types[] = {type, kAstI32, type}; + FunctionSig sig(1, 2, types); + FunctionEnv env; + init_env(&env, &sig); + + EXPECT_VERIFIES_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(1), WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(1), WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + } +} -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 TEST_F(WasmDecoderTest, Select_TypeCheck) { EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0), @@ -1958,22 +1991,18 @@ TEST_F(WasmDecoderTest, Select_TypeCheck) { &env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0), WASM_I64(0))); } -#endif - class WasmOpcodeLengthTest : public TestWithZone { public: WasmOpcodeLengthTest() : TestWithZone() {} }; - -#define EXPECT_LENGTH(expected, opcode) \ - { \ - static const byte code[] = {opcode, 0, 0, 0, 0, 0, 0, 0, 0}; \ - EXPECT_EQ(expected, OpcodeLength(code)); \ +#define EXPECT_LENGTH(expected, opcode) \ + { \ + static const byte code[] = {opcode, 0, 0, 0, 0, 0, 0, 0, 0}; \ + EXPECT_EQ(expected, OpcodeLength(code, code + sizeof(code))); \ } - TEST_F(WasmOpcodeLengthTest, Statements) { EXPECT_LENGTH(1, kExprNop); EXPECT_LENGTH(2, kExprBlock); @@ -1997,6 +2026,7 @@ TEST_F(WasmOpcodeLengthTest, MiscExpressions) { EXPECT_LENGTH(2, kExprLoadGlobal); EXPECT_LENGTH(2, kExprStoreGlobal); EXPECT_LENGTH(2, kExprCallFunction); + EXPECT_LENGTH(2, kExprCallImport); EXPECT_LENGTH(2, kExprCallIndirect); EXPECT_LENGTH(1, kExprIf); EXPECT_LENGTH(1, kExprIfElse); @@ -2014,11 +2044,11 @@ TEST_F(WasmOpcodeLengthTest, VariableLength) { byte size5[] = {kExprLoadGlobal, 1 | 0x80, 2 | 0x80, 3 | 0x80, 4}; byte size6[] = {kExprLoadGlobal, 1 | 0x80, 2 | 0x80, 3 | 0x80, 4 | 0x80, 5}; - EXPECT_EQ(2, OpcodeLength(size2)); - EXPECT_EQ(3, OpcodeLength(size3)); - EXPECT_EQ(4, OpcodeLength(size4)); - EXPECT_EQ(5, OpcodeLength(size5)); - EXPECT_EQ(6, OpcodeLength(size6)); + EXPECT_EQ(2, OpcodeLength(size2, size2 + sizeof(size2))); + EXPECT_EQ(3, OpcodeLength(size3, size3 + sizeof(size3))); + EXPECT_EQ(4, OpcodeLength(size4, size4 + sizeof(size4))); + EXPECT_EQ(5, OpcodeLength(size5, size5 + sizeof(size5))); + EXPECT_EQ(6, OpcodeLength(size6, size6 + sizeof(size6))); } @@ -2183,14 +2213,12 @@ class WasmOpcodeArityTest : public TestWithZone { WasmOpcodeArityTest() : TestWithZone() {} }; - -#define EXPECT_ARITY(expected, ...) \ - { \ - static const byte code[] = {__VA_ARGS__}; \ - EXPECT_EQ(expected, OpcodeArity(&env, code)); \ +#define EXPECT_ARITY(expected, ...) \ + { \ + static const byte code[] = {__VA_ARGS__}; \ + EXPECT_EQ(expected, OpcodeArity(&env, code, code + sizeof(code))); \ } - TEST_F(WasmOpcodeArityTest, Control) { FunctionEnv env; EXPECT_ARITY(0, kExprNop); @@ -2249,12 +2277,16 @@ TEST_F(WasmOpcodeArityTest, Calls) { module.AddSignature(sigs.f_ff()); module.AddSignature(sigs.i_d()); + module.AddImport(sigs.f_ff()); + module.AddImport(sigs.i_d()); + { FunctionEnv env; WasmDecoderTest::init_env(&env, sigs.i_ii()); env.module = &module; EXPECT_ARITY(2, kExprCallFunction, 0); + EXPECT_ARITY(2, kExprCallImport, 0); EXPECT_ARITY(3, kExprCallIndirect, 0); EXPECT_ARITY(1, kExprBr); EXPECT_ARITY(2, kExprBrIf); @@ -2266,6 +2298,7 @@ TEST_F(WasmOpcodeArityTest, Calls) { env.module = &module; EXPECT_ARITY(1, kExprCallFunction, 1); + EXPECT_ARITY(1, kExprCallImport, 1); EXPECT_ARITY(2, kExprCallIndirect, 1); EXPECT_ARITY(1, kExprBr); EXPECT_ARITY(2, kExprBrIf); diff --git a/deps/v8/test/unittests/wasm/encoder-unittest.cc b/deps/v8/test/unittests/wasm/encoder-unittest.cc index 156cf6b1e5..e09e71aeb8 100644 --- a/deps/v8/test/unittests/wasm/encoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/encoder-unittest.cc @@ -56,28 +56,28 @@ TEST_F(EncoderTest, Function_Builder_Variable_Indexing) { WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); uint16_t f_index = builder->AddFunction(); WasmFunctionBuilder* function = builder->FunctionAt(f_index); - uint16_t local_float32 = function->AddLocal(kAstF32); + uint16_t local_f32 = function->AddLocal(kAstF32); uint16_t param_float32 = function->AddParam(kAstF32); - uint16_t local_int32 = function->AddLocal(kAstI32); - uint16_t local_float64 = function->AddLocal(kAstF64); - uint16_t local_int64 = function->AddLocal(kAstI64); + uint16_t local_i32 = function->AddLocal(kAstI32); + uint16_t local_f64 = function->AddLocal(kAstF64); + uint16_t local_i64 = function->AddLocal(kAstI64); uint16_t param_int32 = function->AddParam(kAstI32); - uint16_t local_int32_2 = function->AddLocal(kAstI32); + uint16_t local_i32_2 = function->AddLocal(kAstI32); byte code[] = {kExprGetLocal, static_cast<uint8_t>(param_float32)}; uint32_t local_indices[] = {1}; function->EmitCode(code, sizeof(code), local_indices, 1); code[1] = static_cast<uint8_t>(param_int32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int32); + code[1] = static_cast<uint8_t>(local_i32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int32_2); + code[1] = static_cast<uint8_t>(local_i32_2); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int64); + code[1] = static_cast<uint8_t>(local_i64); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_float32); + code[1] = static_cast<uint8_t>(local_f32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_float64); + code[1] = static_cast<uint8_t>(local_f64); function->EmitCode(code, sizeof(code), local_indices, 1); WasmFunctionEncoder* f = function->Build(&zone, builder); diff --git a/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc b/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc new file mode 100644 index 0000000000..958621970c --- /dev/null +++ b/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc @@ -0,0 +1,211 @@ +// Copyright 2016 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. + +#include "test/unittests/test-utils.h" + +#include "src/v8.h" + +#include "test/cctest/wasm/test-signatures.h" + +#include "src/bit-vector.h" +#include "src/objects.h" + +#include "src/wasm/ast-decoder.h" +#include "src/wasm/wasm-macro-gen.h" +#include "src/wasm/wasm-module.h" + +#define WASM_SET_ZERO(i) WASM_SET_LOCAL(i, WASM_ZERO) + +namespace v8 { +namespace internal { +namespace wasm { + +class WasmLoopAssignmentAnalyzerTest : public TestWithZone { + public: + WasmLoopAssignmentAnalyzerTest() : TestWithZone(), sigs() { + init_env(&env, sigs.v_v()); + } + + TestSignatures sigs; + FunctionEnv env; + + static void init_env(FunctionEnv* env, FunctionSig* sig) { + env->module = nullptr; + env->sig = sig; + env->local_i32_count = 0; + env->local_i64_count = 0; + env->local_f32_count = 0; + env->local_f64_count = 0; + env->SumLocals(); + } + + BitVector* Analyze(const byte* start, const byte* end) { + return AnalyzeLoopAssignmentForTesting(zone(), &env, start, end); + } +}; + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Empty0) { + byte code[] = { 0 }; + BitVector* assigned = Analyze(code, code); + CHECK_NULL(assigned); +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Empty1) { + byte code[] = {kExprLoop, 0}; + for (int i = 0; i < 5; i++) { + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(false, assigned->Contains(j)); + } + env.AddLocals(kAstI32, 1); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, One) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP(1, WASM_SET_ZERO(i))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(j == i, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, OneBeyond) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP(1, WASM_SET_ZERO(i)), WASM_SET_ZERO(1)}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(j == i, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Two) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + byte code[] = {WASM_LOOP(2, WASM_SET_ZERO(i), WASM_SET_ZERO(j))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int k = 0; k < assigned->length(); k++) { + bool expected = k == i || k == j; + CHECK_EQ(expected, assigned->Contains(k)); + } + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, NestedIf) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP( + 1, WASM_IF_ELSE(WASM_SET_ZERO(0), WASM_SET_ZERO(i), WASM_SET_ZERO(1)))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = i == j || j == 0 || j == 1; + CHECK_EQ(expected, assigned->Contains(j)); + } + } +} + + +static byte LEBByte(uint32_t val, byte which) { + byte b = (val >> (which * 7)) & 0x7F; + if (val >> ((which + 1) * 7)) b |= 0x80; + return b; +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, BigLocal) { + env.AddLocals(kAstI32, 65000); + for (int i = 13; i < 65000; i = static_cast<int>(i * 1.5)) { + byte code[] = {kExprLoop, + 1, + kExprSetLocal, + LEBByte(i, 0), + LEBByte(i, 1), + LEBByte(i, 2), + 11, + 12, + 13}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = i == j; + CHECK_EQ(expected, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Break) { + env.AddLocals(kAstI32, 3); + byte code[] = { + WASM_LOOP(1, WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_SET_ZERO(1)))), + WASM_SET_ZERO(0)}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == 1; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Loop1) { + env.AddLocals(kAstI32, 5); + byte code[] = { + WASM_LOOP(1, WASM_IF(WASM_GET_LOCAL(0), + WASM_BRV(0, WASM_SET_LOCAL( + 3, WASM_I32_SUB(WASM_GET_LOCAL(0), + WASM_I8(1)))))), + WASM_GET_LOCAL(0)}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == 3; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Loop2) { + env.AddLocals(kAstI32, 3); + const byte kIter = 0; + env.AddLocals(kAstF32, 3); + const byte kSum = 3; + + byte code[] = {WASM_BLOCK( + 3, + WASM_WHILE( + WASM_GET_LOCAL(kIter), + WASM_BLOCK(2, WASM_SET_LOCAL( + kSum, WASM_F32_ADD( + WASM_GET_LOCAL(kSum), + WASM_LOAD_MEM(MachineType::Float32(), + WASM_GET_LOCAL(kIter)))), + WASM_SET_LOCAL(kIter, WASM_I32_SUB(WASM_GET_LOCAL(kIter), + WASM_I8(4))))), + WASM_STORE_MEM(MachineType::Float32(), WASM_ZERO, WASM_GET_LOCAL(kSum)), + WASM_GET_LOCAL(kIter))}; + + BitVector* assigned = Analyze(code + 2, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == kIter || j == kSum; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +} // namespace wasm +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc index 0738b5909b..467ffcc232 100644 --- a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc @@ -45,6 +45,15 @@ struct LocalTypePair { {kLocalF64, kAstF64}}; +// TODO(titzer): use these macros everywhere below. +#define U32_LE(v) \ + static_cast<byte>(v), static_cast<byte>((v) >> 8), \ + static_cast<byte>((v) >> 16), static_cast<byte>((v) >> 24) + + +#define U16_LE(v) static_cast<byte>(v), static_cast<byte>((v) >> 8) + + TEST_F(WasmModuleVerifyTest, DecodeEmpty) { static const byte data[1]{kDeclEnd}; { @@ -61,7 +70,7 @@ TEST_F(WasmModuleVerifyTest, DecodeEmpty) { TEST_F(WasmModuleVerifyTest, OneGlobal) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, 0, @@ -100,7 +109,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) { TEST_F(WasmModuleVerifyTest, ZeroGlobals) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 0, // declare 0 globals }; ModuleResult result = DecodeModule(data, data + arraysize(data)); @@ -125,7 +134,7 @@ static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) { TEST_F(WasmModuleVerifyTest, NGlobals) { - const byte data[] = { + static const byte data[] = { 0, 0, 0, 0, // name offset kMemI32, // memory type 0, // exported @@ -146,7 +155,7 @@ TEST_F(WasmModuleVerifyTest, NGlobals) { TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, // declare one global 0, @@ -162,7 +171,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) { TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, // declare one global 0, @@ -178,7 +187,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { TEST_F(WasmModuleVerifyTest, TwoGlobals) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 2, 0, @@ -333,10 +342,10 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(523, function->local_int32_count); - EXPECT_EQ(1037, function->local_int64_count); - EXPECT_EQ(1551, function->local_float32_count); - EXPECT_EQ(2065, function->local_float64_count); + EXPECT_EQ(523, function->local_i32_count); + EXPECT_EQ(1037, function->local_i64_count); + EXPECT_EQ(1551, function->local_f32_count); + EXPECT_EQ(2065, function->local_f64_count); EXPECT_TRUE(function->exported); EXPECT_FALSE(function->external); @@ -373,10 +382,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionImported) { EXPECT_EQ(0, function->code_start_offset); EXPECT_EQ(0, function->code_end_offset); - EXPECT_EQ(0, function->local_int32_count); - EXPECT_EQ(0, function->local_int64_count); - EXPECT_EQ(0, function->local_float32_count); - EXPECT_EQ(0, function->local_float64_count); + EXPECT_EQ(0, function->local_i32_count); + EXPECT_EQ(0, function->local_i64_count); + EXPECT_EQ(0, function->local_f32_count); + EXPECT_EQ(0, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_TRUE(function->external); @@ -410,10 +419,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(0, function->local_int32_count); - EXPECT_EQ(0, function->local_int64_count); - EXPECT_EQ(0, function->local_float32_count); - EXPECT_EQ(0, function->local_float64_count); + EXPECT_EQ(0, function->local_i32_count); + EXPECT_EQ(0, function->local_i64_count); + EXPECT_EQ(0, function->local_f32_count); + EXPECT_EQ(0, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_FALSE(function->external); @@ -450,10 +459,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(513, function->local_int32_count); - EXPECT_EQ(1027, function->local_int64_count); - EXPECT_EQ(1541, function->local_float32_count); - EXPECT_EQ(2055, function->local_float64_count); + EXPECT_EQ(513, function->local_i32_count); + EXPECT_EQ(1027, function->local_i64_count); + EXPECT_EQ(1541, function->local_f32_count); + EXPECT_EQ(2055, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_FALSE(function->external); @@ -463,10 +472,13 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { - static const byte kCodeStartOffset = 2 + kDeclGlobalSize + 4 + 2 + 17; + static const byte kDeclMemorySize = 4; + static const byte kCodeStartOffset = + 2 + kDeclMemorySize + kDeclGlobalSize + 4 + 2 + 17; static const byte kCodeEndOffset = kCodeStartOffset + 3; static const byte data[] = { + kDeclMemory, 28, 28, 1, // global#0 -------------------------------------------------- kDeclGlobals, 1, 0, 0, 0, 0, // name offset kMemU8, // memory type @@ -531,24 +543,17 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { TEST_F(WasmModuleVerifyTest, OneDataSegment) { const byte data[] = { - kDeclDataSegments, - 1, - 0xaa, - 0xbb, - 0x09, + kDeclMemory, 28, 28, 1, kDeclDataSegments, 1, 0xaa, 0xbb, 0x09, 0, // dest addr - 11, - 0, - 0, + 11, 0, 0, 0, // source offset - 3, - 0, - 0, + 3, 0, 0, 0, // source size 1, // init }; { + EXPECT_VERIFIES(data); ModuleResult result = DecodeModule(data, data + arraysize(data)); EXPECT_TRUE(result.ok()); EXPECT_EQ(0, result.val->globals->size()); @@ -565,7 +570,7 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { if (result.val) delete result.val; } - for (size_t size = 1; size < arraysize(data); size++) { + for (size_t size = 5; size < arraysize(data); size++) { // Should fall off end of module bytes. ModuleResult result = DecodeModule(data, data + size); EXPECT_FALSE(result.ok()); @@ -576,32 +581,18 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { TEST_F(WasmModuleVerifyTest, TwoDataSegments) { const byte data[] = { - kDeclDataSegments, - 2, - 0xee, - 0xff, - 0x07, + kDeclMemory, 28, 28, 1, kDeclDataSegments, 2, 0xee, 0xff, 0x07, 0, // dest addr - 9, - 0, - 0, + 9, 0, 0, 0, // #0: source offset - 4, - 0, - 0, + 4, 0, 0, 0, // source size 0, // init - 0xcc, - 0xdd, - 0x06, + 0xcc, 0xdd, 0x06, 0, // #1: dest addr - 6, - 0, - 0, + 6, 0, 0, 0, // source offset - 10, - 0, - 0, + 10, 0, 0, 0, // source size 1, // init }; @@ -629,7 +620,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { if (result.val) delete result.val; } - for (size_t size = 1; size < arraysize(data); size++) { + for (size_t size = 5; size < arraysize(data); size++) { // Should fall off end of module bytes. ModuleResult result = DecodeModule(data, data + size); EXPECT_FALSE(result.ok()); @@ -638,6 +629,71 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { } +TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidSource) { + const int dest_addr = 0x100; + const byte mem_size_log2 = 15; + const int kDataSize = 19; + + for (int source_offset = 0; source_offset < 5 + kDataSize; source_offset++) { + for (int source_size = -1; source_size < 5 + kDataSize; source_size += 3) { + byte data[] = { + kDeclMemory, + mem_size_log2, + mem_size_log2, + 1, + kDeclDataSegments, + 1, + U32_LE(dest_addr), + U32_LE(source_offset), + U32_LE(source_size), + 1, // init + }; + + STATIC_ASSERT(kDataSize == arraysize(data)); + + if (source_offset < kDataSize && source_size >= 0 && + (source_offset + source_size) <= kDataSize) { + EXPECT_VERIFIES(data); + } else { + EXPECT_FAILURE(data); + } + } + } +} + + +TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidDest) { + const int source_size = 3; + const int source_offset = 11; + + for (byte mem_size_log2 = 12; mem_size_log2 < 20; mem_size_log2++) { + int mem_size = 1 << mem_size_log2; + + for (int dest_addr = mem_size - source_size; + dest_addr < mem_size + source_size; dest_addr++) { + byte data[] = { + kDeclMemory, + mem_size_log2, + mem_size_log2, + 1, + kDeclDataSegments, + 1, + U32_LE(dest_addr), + U32_LE(source_offset), + U32_LE(source_size), + 1, // init + }; + + if (dest_addr <= (mem_size - source_size)) { + EXPECT_VERIFIES(data); + } else { + EXPECT_FAILURE(data); + } + } + } +} + + // To make below tests for indirect calls much shorter. #define FUNCTION(sig_index, external) \ kDeclFunctionImport, static_cast<byte>(sig_index), \ @@ -848,7 +904,7 @@ class WasmFunctionVerifyTest : public TestWithZone {}; TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { - byte data[] = { + static const byte data[] = { 0, kLocalVoid, // signature 3, 0, // local int32 count 4, 0, // local int64 count @@ -868,10 +924,10 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { EXPECT_EQ(0, function->name_offset); EXPECT_EQ(arraysize(data) - 1, function->code_start_offset); EXPECT_EQ(arraysize(data), function->code_end_offset); - EXPECT_EQ(3, function->local_int32_count); - EXPECT_EQ(4, function->local_int64_count); - EXPECT_EQ(5, function->local_float32_count); - EXPECT_EQ(6, function->local_float64_count); + EXPECT_EQ(3, function->local_i32_count); + EXPECT_EQ(4, function->local_i64_count); + EXPECT_EQ(5, function->local_f32_count); + EXPECT_EQ(6, function->local_f64_count); EXPECT_FALSE(function->external); EXPECT_FALSE(function->exported); } @@ -889,7 +945,7 @@ TEST_F(WasmModuleVerifyTest, WLLSectionNoLen) { TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) { - const byte data[] = { + static const byte data[] = { kDeclWLL, 0, // empty section }; ModuleResult result = DecodeModule(data, data + arraysize(data)); @@ -899,7 +955,7 @@ TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) { TEST_F(WasmModuleVerifyTest, WLLSectionOne) { - const byte data[] = { + static const byte data[] = { kDeclWLL, 1, // LEB128 1 0, // one byte section @@ -911,10 +967,10 @@ TEST_F(WasmModuleVerifyTest, WLLSectionOne) { TEST_F(WasmModuleVerifyTest, WLLSectionTen) { - const byte data[] = { + static const byte data[] = { kDeclWLL, - 10, // LEB128 10 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section + 10, // LEB128 10 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section }; ModuleResult result = DecodeModule(data, data + arraysize(data)); EXPECT_TRUE(result.ok()); @@ -923,20 +979,19 @@ TEST_F(WasmModuleVerifyTest, WLLSectionTen) { TEST_F(WasmModuleVerifyTest, WLLSectionOverflow) { - const byte data[] = { + static const byte data[] = { kDeclWLL, - 11, // LEB128 11 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section + 11, // LEB128 11 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) { - const byte data[] = { - kDeclWLL, - 0xff, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xffffffff - 1, 2, 3, 4, // 4 byte section + static const byte data[] = { + kDeclWLL, 0xff, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xffffffff + 1, 2, 3, 4, // 4 byte section }; EXPECT_FAILURE(data); } @@ -944,14 +999,92 @@ TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) { TEST_F(WasmModuleVerifyTest, WLLSectionLoop) { // Would infinite loop decoding if wrapping and allowed. - const byte data[] = { - kDeclWLL, - 0xfa, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xfffffffa - 1, 2, 3, 4, // 4 byte section + static const byte data[] = { + kDeclWLL, 0xfa, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xfffffffa + 1, 2, 3, 4, // 4 byte section }; EXPECT_FAILURE(data); } +TEST_F(WasmModuleVerifyTest, ImportTable_empty) { + static const byte data[] = {kDeclSignatures, 0, kDeclImportTable, 0}; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) { + static const byte data[] = {kDeclImportTable, 0}; + EXPECT_FAILURE(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) { + static const byte data[] = { + kDeclSignatures, + 0, + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + EXPECT_FAILURE(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_one_sig) { + static const byte data[] = { + kDeclSignatures, + 1, + 0, + static_cast<byte>(kAstStmt), + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_off_end) { + static const byte data[] = { + kDeclSignatures, + 1, + 0, + static_cast<byte>(kAstStmt), + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + + for (size_t length = 5; length < sizeof(data); length++) { + ModuleResult result = DecodeModule(data, data + length); + EXPECT_FALSE(result.ok()); + if (result.val) delete result.val; + } +} + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc b/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc index c5bb5eca00..f3f604b3ed 100644 --- a/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc +++ b/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc @@ -131,15 +131,25 @@ TEST_F(WasmMacroGenTest, Expressions) { EXPECT_SIZE(6, WASM_LOOP(3, WASM_NOP, WASM_NOP, WASM_ZERO)); } - -TEST_F(WasmMacroGenTest, FunctionCalls) { +TEST_F(WasmMacroGenTest, CallFunction) { EXPECT_SIZE(2, WASM_CALL_FUNCTION0(0)); EXPECT_SIZE(2, WASM_CALL_FUNCTION0(1)); EXPECT_SIZE(2, WASM_CALL_FUNCTION0(11)); EXPECT_SIZE(4, WASM_CALL_FUNCTION(0, WASM_ZERO)); EXPECT_SIZE(6, WASM_CALL_FUNCTION(1, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(WasmMacroGenTest, CallImport) { + EXPECT_SIZE(2, WASM_CALL_IMPORT0(0)); + EXPECT_SIZE(2, WASM_CALL_IMPORT0(1)); + EXPECT_SIZE(2, WASM_CALL_IMPORT0(11)); + + EXPECT_SIZE(4, WASM_CALL_IMPORT(0, WASM_ZERO)); + EXPECT_SIZE(6, WASM_CALL_IMPORT(1, WASM_ZERO, WASM_ZERO)); +} +TEST_F(WasmMacroGenTest, CallIndirect) { EXPECT_SIZE(4, WASM_CALL_INDIRECT0(0, WASM_ZERO)); EXPECT_SIZE(4, WASM_CALL_INDIRECT0(1, WASM_ZERO)); EXPECT_SIZE(4, WASM_CALL_INDIRECT0(11, WASM_ZERO)); |