// 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/init/v8.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" #include "src/utils/bit-vector.h" #include "src/wasm/function-body-decoder.h" #include "src/wasm/wasm-module.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" namespace v8 { namespace internal { namespace wasm { #define WASM_SET_ZERO(i) WASM_SET_LOCAL(i, WASM_ZERO) class WasmLoopAssignmentAnalyzerTest : public TestWithZone { public: WasmLoopAssignmentAnalyzerTest() : num_locals(0) {} TestSignatures sigs; uint32_t num_locals; BitVector* Analyze(const byte* start, const byte* end) { return AnalyzeLoopAssignmentForTesting(zone(), num_locals, start, end); } }; TEST_F(WasmLoopAssignmentAnalyzerTest, Empty0) { byte code[] = { 0 }; BitVector* assigned = Analyze(code, code); CHECK_NULL(assigned); } TEST_F(WasmLoopAssignmentAnalyzerTest, Empty1) { byte code[] = {kExprLoop, kLocalVoid, 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)); } num_locals++; } } TEST_F(WasmLoopAssignmentAnalyzerTest, One) { num_locals = 5; for (int i = 0; i < 5; i++) { byte code[] = {WASM_LOOP(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, TeeOne) { num_locals = 5; for (int i = 0; i < 5; i++) { byte code[] = {WASM_LOOP(WASM_TEE_LOCAL(i, WASM_ZERO))}; 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) { num_locals = 5; for (int i = 0; i < 5; i++) { byte code[] = {WASM_LOOP(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) { num_locals = 5; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { byte code[] = {WASM_LOOP(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) { num_locals = 5; for (int i = 0; i < 5; i++) { byte code[] = {WASM_LOOP( 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)); } } } TEST_F(WasmLoopAssignmentAnalyzerTest, BigLocal) { num_locals = 65000; for (int i = 13; i < 65000; i = static_cast(i * 1.5)) { byte code[] = {WASM_LOOP(WASM_I32V_1(11), kExprSetLocal, U32V_3(i))}; 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) { num_locals = 3; byte code[] = { WASM_LOOP(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) { num_locals = 5; byte code[] = { WASM_LOOP(WASM_IF( WASM_GET_LOCAL(0), WASM_BRV(0, WASM_SET_LOCAL(3, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_I32V_1(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) { num_locals = 6; const byte kIter = 0; const byte kSum = 3; byte code[] = {WASM_BLOCK( WASM_WHILE( WASM_GET_LOCAL(kIter), WASM_BLOCK( 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_I32V_1(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)); } } TEST_F(WasmLoopAssignmentAnalyzerTest, Malformed) { byte code[] = {kExprLoop, kLocalVoid, kExprF32Neg, kExprBrTable, 0x0E, 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'}; BitVector* assigned = Analyze(code, code + arraysize(code)); CHECK_NULL(assigned); } TEST_F(WasmLoopAssignmentAnalyzerTest, regress_642867) { static const byte code[] = { WASM_LOOP(WASM_ZERO, kExprSetLocal, 0xFA, 0xFF, 0xFF, 0xFF, 0x0F)}; // local index LEB128 0xFFFFFFFA // Just make sure that the analysis does not crash. Analyze(code, code + arraysize(code)); } #undef WASM_SET_ZERO } // namespace wasm } // namespace internal } // namespace v8