Index: test/cctest/interpreter/test-bytecode-generator.cc |
diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc |
index bff48bcce1a3447d7d1ab9d1fe18df29e985d832..5c6cea0167653669d9a8b0f5b569819bc1252ff7 100644 |
--- a/test/cctest/interpreter/test-bytecode-generator.cc |
+++ b/test/cctest/interpreter/test-bytecode-generator.cc |
@@ -5,6 +5,7 @@ |
#include "src/v8.h" |
#include "src/compiler.h" |
+#include "src/interpreter/bytecode-array-iterator.h" |
#include "src/interpreter/bytecode-generator.h" |
#include "src/interpreter/interpreter.h" |
#include "test/cctest/cctest.h" |
@@ -57,6 +58,13 @@ class BytecodeGeneratorHelper { |
}; |
+// Helper macros for handcrafting bytecode sequences. |
+#define B(x) static_cast<uint8_t>(Bytecode::k##x) |
+#define U8(x) static_cast<uint8_t>((x) & 0xff) |
+#define R(x) static_cast<uint8_t>(-(x) & 0xff) |
+#define _ static_cast<uint8_t>(0x5a) |
+ |
+ |
// Structure for containing expected bytecode snippets. |
template<typename T> |
struct ExpectedSnippet { |
@@ -70,17 +78,82 @@ struct ExpectedSnippet { |
}; |
-// Helper macros for handcrafting bytecode sequences. |
-#define B(x) static_cast<uint8_t>(Bytecode::k##x) |
-#define U8(x) static_cast<uint8_t>((x) & 0xff) |
-#define R(x) static_cast<uint8_t>(-(x) & 0xff) |
+static void CheckConstant(int expected, Object* actual) { |
+ CHECK_EQ(expected, Smi::cast(actual)->value()); |
+} |
+ |
+ |
+static void CheckConstant(double expected, Object* actual) { |
+ CHECK_EQ(expected, HeapNumber::cast(actual)->value()); |
+} |
+ |
+ |
+static void CheckConstant(const char* expected, Object* actual) { |
+ Handle<String> expected_string = |
+ CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(expected); |
+ CHECK(String::cast(actual)->Equals(*expected_string)); |
+} |
+ |
+ |
+template <typename T> |
+static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected, |
+ Handle<BytecodeArray> actual, |
+ bool has_unknown = false) { |
+ CHECK_EQ(actual->frame_size(), expected.frame_size); |
+ CHECK_EQ(actual->parameter_count(), expected.parameter_count); |
+ CHECK_EQ(actual->length(), expected.bytecode_length); |
+ if (expected.constant_count == 0) { |
+ CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array()); |
+ } else { |
+ CHECK_EQ(actual->constant_pool()->length(), expected.constant_count); |
+ for (int i = 0; i < expected.constant_count; i++) { |
+ CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); |
+ } |
+ } |
+ |
+ BytecodeArrayIterator iterator(actual); |
+ int i = 0; |
+ while (!iterator.done()) { |
+ int bytecode_index = i++; |
+ Bytecode bytecode = iterator.current_bytecode(); |
+ if (Bytecodes::ToByte(bytecode) != expected.bytecode[bytecode_index]) { |
+ std::ostringstream stream; |
+ stream << "Check failed: expected bytecode [" << bytecode_index |
+ << "] to be " << Bytecodes::ToString(static_cast<Bytecode>( |
+ expected.bytecode[bytecode_index])) |
+ << " but got " << Bytecodes::ToString(bytecode); |
+ FATAL(stream.str().c_str()); |
+ } |
+ for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j, ++i) { |
+ uint8_t raw_operand = |
+ iterator.GetRawOperand(j, Bytecodes::GetOperandType(bytecode, j)); |
+ if (has_unknown) { |
+ // Check actual bytecode array doesn't have the same byte as the |
+ // one we use to specify an unknown byte. |
+ CHECK_NE(raw_operand, _); |
+ if (expected.bytecode[i] == _) { |
+ continue; |
+ } |
+ } |
+ if (raw_operand != expected.bytecode[i]) { |
+ std::ostringstream stream; |
+ stream << "Check failed: expected operand [" << j << "] for bytecode [" |
+ << bytecode_index << "] to be " |
+ << static_cast<unsigned int>(expected.bytecode[i]) << " but got " |
+ << static_cast<unsigned int>(raw_operand); |
+ FATAL(stream.str().c_str()); |
+ } |
+ } |
+ iterator.Advance(); |
+ } |
+} |
TEST(PrimitiveReturnStatements) { |
InitializedHandleScope handle_scope; |
BytecodeGeneratorHelper helper; |
- ExpectedSnippet<void*> snippets[] = { |
+ ExpectedSnippet<int> snippets[] = { |
{"", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0}, |
{"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0}, |
{"return null;", 0, 1, 2, {B(LdaNull), B(Return)}, 0}, |
@@ -95,14 +168,9 @@ TEST(PrimitiveReturnStatements) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array()); |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -111,7 +179,7 @@ TEST(PrimitiveExpressions) { |
InitializedHandleScope handle_scope; |
BytecodeGeneratorHelper helper; |
- ExpectedSnippet<void*> snippets[] = { |
+ ExpectedSnippet<int> snippets[] = { |
{"var x = 0; return x;", |
kPointerSize, |
1, |
@@ -142,14 +210,9 @@ TEST(PrimitiveExpressions) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array()); |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -158,7 +221,7 @@ TEST(Parameters) { |
InitializedHandleScope handle_scope; |
BytecodeGeneratorHelper helper; |
- ExpectedSnippet<void*> snippets[] = { |
+ ExpectedSnippet<int> snippets[] = { |
{"function f() { return this; }", |
0, 1, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0}, |
{"function f(arg1) { return arg1; }", |
@@ -173,14 +236,9 @@ TEST(Parameters) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunction(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array()); |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -219,18 +277,9 @@ TEST(Constants) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- CHECK_EQ(Smi::cast(ba->constant_pool()->get(j))->value(), |
- snippets[i].constants[j]); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -268,18 +317,9 @@ TEST(Constants) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- CHECK_EQ(HeapNumber::cast(ba->constant_pool()->get(j))->value(), |
- snippets[i].constants[j]); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -315,19 +355,9 @@ TEST(Constants) { |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- Handle<String> expected = helper.factory()->NewStringFromAsciiChecked( |
- snippets[i].constants[j]); |
- CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected)); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
} |
@@ -405,19 +435,9 @@ TEST(PropertyLoads) { |
}; |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecode(snippets[i].code_snippet, "f"); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- Handle<String> expected = helper.factory()->NewStringFromAsciiChecked( |
- snippets[i].constants[j]); |
- CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected)); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -509,19 +529,9 @@ TEST(PropertyStores) { |
}; |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecode(snippets[i].code_snippet, "f"); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- Handle<String> expected = |
- helper.factory()->NewStringFromAsciiChecked(snippets[i].constants[j]); |
- CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected)); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
} |
} |
@@ -592,19 +602,84 @@ TEST(PropertyCall) { |
}; |
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
for (size_t i = 0; i < num_snippets; i++) { |
- Handle<BytecodeArray> ba = |
+ Handle<BytecodeArray> bytecode_array = |
helper.MakeBytecode(snippets[i].code_snippet, "f"); |
- CHECK_EQ(ba->frame_size(), snippets[i].frame_size); |
- CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); |
- CHECK_EQ(ba->length(), snippets[i].bytecode_length); |
- CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, |
- ba->length())); |
- CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); |
- for (int j = 0; j < snippets[i].constant_count; j++) { |
- Handle<String> expected = |
- helper.factory()->NewStringFromAsciiChecked(snippets[i].constants[j]); |
- CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected)); |
- } |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
+ } |
+} |
+ |
+ |
+TEST(LoadGlobal) { |
+ InitializedHandleScope handle_scope; |
+ BytecodeGeneratorHelper helper; |
+ |
+ ExpectedSnippet<const char*> snippets[] = { |
+ {"var a = 1;\nfunction f() { return a; }\nf()", |
+ 0, 1, 3, |
+ { |
+ B(LdaGlobal), _, |
+ B(Return) |
+ }, |
+ }, |
+ {"function t() { }\nfunction f() { return t; }\nf()", |
+ 0, 1, 3, |
+ { |
+ B(LdaGlobal), _, |
+ B(Return) |
+ }, |
+ }, |
+ }; |
+ |
+ size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
+ for (size_t i = 0; i < num_snippets; i++) { |
+ Handle<BytecodeArray> bytecode_array = |
+ helper.MakeBytecode(snippets[i].code_snippet, "f"); |
+ bytecode_array->Print(); |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array, true); |
+ } |
+} |
+ |
+ |
+TEST(CallGlobal) { |
+ InitializedHandleScope handle_scope; |
+ BytecodeGeneratorHelper helper; |
+ |
+ ExpectedSnippet<const char*> snippets[] = { |
+ {"function t() { }\nfunction f() { return t(); }\nf()", |
+ 2 * kPointerSize, 1, 12, |
+ { |
+ B(LdaUndefined), |
+ B(Star), R(1), |
+ B(LdaGlobal), _, |
+ B(Star), R(0), |
+ B(Call), R(0), R(1), U8(0), |
+ B(Return) |
+ }, |
+ }, |
+ {"function t(a, b, c) { }\nfunction f() { return t(1, 2, 3); }\nf()", |
+ 5 * kPointerSize, 1, 24, |
+ { |
+ B(LdaUndefined), |
+ B(Star), R(1), |
+ B(LdaGlobal), _, |
+ B(Star), R(0), |
+ B(LdaSmi8), U8(1), |
+ B(Star), R(2), |
+ B(LdaSmi8), U8(2), |
+ B(Star), R(3), |
+ B(LdaSmi8), U8(3), |
+ B(Star), R(4), |
+ B(Call), R(0), R(1), U8(3), |
+ B(Return) |
+ }, |
+ }, |
+ }; |
+ |
+ size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); |
+ for (size_t i = 0; i < num_snippets; i++) { |
+ Handle<BytecodeArray> bytecode_array = |
+ helper.MakeBytecode(snippets[i].code_snippet, "f"); |
+ CheckBytecodeArrayEqual(snippets[i], bytecode_array, true); |
} |
} |