| OLD | NEW | 
|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "src/v8.h" | 5 #include "src/v8.h" | 
| 6 | 6 | 
| 7 #include "src/compiler.h" | 7 #include "src/compiler.h" | 
| 8 #include "src/interpreter/bytecode-generator.h" | 8 #include "src/interpreter/bytecode-generator.h" | 
| 9 #include "src/interpreter/interpreter.h" | 9 #include "src/interpreter/interpreter.h" | 
| 10 #include "test/cctest/cctest.h" | 10 #include "test/cctest/cctest.h" | 
| 11 | 11 | 
| 12 namespace v8 { | 12 namespace v8 { | 
| 13 namespace internal { | 13 namespace internal { | 
| 14 namespace interpreter { | 14 namespace interpreter { | 
| 15 | 15 | 
| 16 class BytecodeGeneratorHelper { | 16 class BytecodeGeneratorHelper { | 
| 17  public: | 17  public: | 
| 18   const char* kFunctionName = "my_function"; | 18   const char* kFunctionName = "f"; | 
| 19 | 19 | 
| 20   BytecodeGeneratorHelper() { | 20   BytecodeGeneratorHelper() { | 
| 21     i::FLAG_ignition = true; | 21     i::FLAG_ignition = true; | 
| 22     i::FLAG_ignition_filter = kFunctionName; | 22     i::FLAG_ignition_filter = kFunctionName; | 
| 23     CcTest::i_isolate()->interpreter()->Initialize(); | 23     CcTest::i_isolate()->interpreter()->Initialize(); | 
| 24   } | 24   } | 
| 25 | 25 | 
| 26 | 26 | 
| 27   Handle<BytecodeArray> MakeBytecode(const char* script, | 27   Handle<BytecodeArray> MakeBytecode(const char* script, | 
| 28                                      const char* function_name) { | 28                                      const char* function_name) { | 
| 29     CompileRun(script); | 29     CompileRun(script); | 
| 30     Local<Function> function = | 30     Local<Function> function = | 
| 31         Local<Function>::Cast(CcTest::global()->Get(v8_str(function_name))); | 31         Local<Function>::Cast(CcTest::global()->Get(v8_str(function_name))); | 
| 32     i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*function); | 32     i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*function); | 
| 33     return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate()); | 33     return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate()); | 
| 34   } | 34   } | 
| 35 | 35 | 
| 36 | 36 | 
| 37   Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) { | 37   Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) { | 
| 38     ScopedVector<char> program(1024); | 38     ScopedVector<char> program(1024); | 
| 39     SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body, | 39     SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body, | 
| 40              kFunctionName); | 40              kFunctionName); | 
| 41     return MakeBytecode(program.start(), kFunctionName); | 41     return MakeBytecode(program.start(), kFunctionName); | 
| 42   } | 42   } | 
|  | 43 | 
|  | 44   Handle<BytecodeArray> MakeBytecodeForFunction(const char* function) { | 
|  | 45     ScopedVector<char> program(1024); | 
|  | 46     SNPrintF(program, "%s\n%s();", function, kFunctionName); | 
|  | 47     return MakeBytecode(program.start(), kFunctionName); | 
|  | 48   } | 
| 43 }; | 49 }; | 
| 44 | 50 | 
| 45 | 51 | 
| 46 // Structure for containing expected bytecode snippets. | 52 // Structure for containing expected bytecode snippets. | 
| 47 struct ExpectedSnippet { | 53 struct ExpectedSnippet { | 
| 48   const char* body; | 54   const char* body; | 
| 49   int frame_size; | 55   int frame_size; | 
|  | 56   int parameter_count; | 
| 50   int bytecode_length; | 57   int bytecode_length; | 
| 51   const uint8_t bytecode[16]; | 58   const uint8_t bytecode[16]; | 
| 52 }; | 59 }; | 
| 53 | 60 | 
| 54 | 61 | 
| 55 // Helper macros for handcrafting bytecode sequences. | 62 // Helper macros for handcrafting bytecode sequences. | 
| 56 #define B(x) static_cast<uint8_t>(Bytecode::k##x) | 63 #define B(x) static_cast<uint8_t>(Bytecode::k##x) | 
| 57 #define U8(x) static_cast<uint8_t>(x & 0xff) | 64 #define U8(x) static_cast<uint8_t>((x) & 0xff) | 
| 58 #define R(x) static_cast<uint8_t>(-x & 0xff) | 65 #define R(x) static_cast<uint8_t>(-(x) & 0xff) | 
| 59 | 66 | 
| 60 | 67 | 
| 61 TEST(PrimitiveReturnStatements) { | 68 TEST(PrimitiveReturnStatements) { | 
| 62   InitializedHandleScope handle_scope; | 69   InitializedHandleScope handle_scope; | 
| 63   BytecodeGeneratorHelper helper; | 70   BytecodeGeneratorHelper helper; | 
| 64 | 71 | 
| 65   ExpectedSnippet snippets[] = { | 72   ExpectedSnippet snippets[] = { | 
| 66       {"return;", 0, 2, {B(LdaUndefined), B(Return)}}, | 73       {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}}, | 
| 67       {"return null;", 0, 2, {B(LdaNull), B(Return)}}, | 74       {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}}, | 
| 68       {"return true;", 0, 2, {B(LdaTrue), B(Return)}}, | 75       {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}}, | 
| 69       {"return false;", 0, 2, {B(LdaFalse), B(Return)}}, | 76       {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}}, | 
| 70       {"return 0;", 0, 2, {B(LdaZero), B(Return)}}, | 77       {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}}, | 
| 71       {"return +1;", 0, 3, {B(LdaSmi8), U8(1), B(Return)}}, | 78       {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}}, | 
| 72       {"return -1;", 0, 3, {B(LdaSmi8), U8(-1), B(Return)}}, | 79       {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}}, | 
| 73       {"return +127;", 0, 3, {B(LdaSmi8), U8(127), B(Return)}}, | 80       {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}}, | 
| 74       {"return -128;", 0, 3, {B(LdaSmi8), U8(-128), B(Return)}}, | 81       {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}}, | 
| 75   }; | 82   }; | 
| 76 | 83 | 
| 77   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); | 84   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); | 
| 78   for (size_t i = 0; i < num_snippets; i++) { | 85   for (size_t i = 0; i < num_snippets; i++) { | 
| 79     Handle<BytecodeArray> ba = | 86     Handle<BytecodeArray> ba = | 
| 80         helper.MakeBytecodeForFunctionBody(snippets[i].body); | 87         helper.MakeBytecodeForFunctionBody(snippets[i].body); | 
| 81     CHECK_EQ(ba->frame_size(), snippets[i].frame_size); | 88     CHECK_EQ(ba->frame_size(), snippets[i].frame_size); | 
|  | 89     CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); | 
| 82     CHECK_EQ(ba->length(), snippets[i].bytecode_length); | 90     CHECK_EQ(ba->length(), snippets[i].bytecode_length); | 
| 83     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, | 91     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, | 
| 84                   ba->length())); | 92                   ba->length())); | 
| 85   } | 93   } | 
| 86 } | 94 } | 
| 87 | 95 | 
| 88 | 96 | 
| 89 TEST(PrimitiveExpressions) { | 97 TEST(PrimitiveExpressions) { | 
| 90   InitializedHandleScope handle_scope; | 98   InitializedHandleScope handle_scope; | 
| 91   BytecodeGeneratorHelper helper; | 99   BytecodeGeneratorHelper helper; | 
| 92 | 100 | 
| 93   ExpectedSnippet snippets[] = { | 101   ExpectedSnippet snippets[] = { | 
| 94       {"var x = 0; return x;", | 102       {"var x = 0; return x;", | 
| 95        kPointerSize, | 103        kPointerSize, | 
|  | 104        1, | 
| 96        6, | 105        6, | 
| 97        { | 106        { | 
| 98            B(LdaZero),     // | 107            B(LdaZero),     // | 
| 99            B(Star), R(0),  // | 108            B(Star), R(0),  // | 
| 100            B(Ldar), R(0),  // | 109            B(Ldar), R(0),  // | 
| 101            B(Return)       // | 110            B(Return)       // | 
| 102        }}, | 111        }}, | 
| 103       {"var x = 0; return x + 3;", | 112       {"var x = 0; return x + 3;", | 
| 104        2 * kPointerSize, | 113        2 * kPointerSize, | 
|  | 114        1, | 
| 105        12, | 115        12, | 
| 106        { | 116        { | 
| 107            B(LdaZero),         // | 117            B(LdaZero),         // | 
| 108            B(Star), R(0),      // | 118            B(Star), R(0),      // | 
| 109            B(Ldar), R(0),      // Easy to spot r1 not really needed here. | 119            B(Ldar), R(0),      // Easy to spot r1 not really needed here. | 
| 110            B(Star), R(1),      // Dead store. | 120            B(Star), R(1),      // Dead store. | 
| 111            B(LdaSmi8), U8(3),  // | 121            B(LdaSmi8), U8(3),  // | 
| 112            B(Add), R(1),       // | 122            B(Add), R(1),       // | 
| 113            B(Return)           // | 123            B(Return)           // | 
| 114        }}}; | 124        }}}; | 
| 115 | 125 | 
| 116   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); | 126   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); | 
| 117   for (size_t i = 0; i < num_snippets; i++) { | 127   for (size_t i = 0; i < num_snippets; i++) { | 
| 118     Handle<BytecodeArray> ba = | 128     Handle<BytecodeArray> ba = | 
| 119         helper.MakeBytecodeForFunctionBody(snippets[i].body); | 129         helper.MakeBytecodeForFunctionBody(snippets[i].body); | 
| 120     CHECK_EQ(ba->frame_size(), snippets[i].frame_size); | 130     CHECK_EQ(ba->frame_size(), snippets[i].frame_size); | 
|  | 131     CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); | 
| 121     CHECK_EQ(ba->length(), snippets[i].bytecode_length); | 132     CHECK_EQ(ba->length(), snippets[i].bytecode_length); | 
| 122     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, | 133     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, | 
| 123                   ba->length())); | 134                   ba->length())); | 
|  | 135   } | 
|  | 136 } | 
|  | 137 | 
|  | 138 | 
|  | 139 TEST(Parameters) { | 
|  | 140   InitializedHandleScope handle_scope; | 
|  | 141   BytecodeGeneratorHelper helper; | 
|  | 142 | 
|  | 143   int last_param_index = | 
|  | 144       -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; | 
|  | 145   ExpectedSnippet snippets[] = { | 
|  | 146       {"function f() { return this; }", | 
|  | 147        0, 1, 3, {B(Ldar), R(last_param_index), B(Return)}}, | 
|  | 148       {"function f(arg1) { return arg1; }", | 
|  | 149        0, 2, 3, {B(Ldar), R(last_param_index), B(Return)}}, | 
|  | 150       {"function f(arg1) { return this; }", | 
|  | 151        0, 2, 3, {B(Ldar), R(last_param_index - 1), B(Return)}}, | 
|  | 152       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }", | 
|  | 153        0, 8, 3, {B(Ldar), R(last_param_index - 3), B(Return)}}, | 
|  | 154       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }", | 
|  | 155        0, 8, 3, {B(Ldar), R(last_param_index - 7), B(Return)}} | 
|  | 156   }; | 
|  | 157 | 
|  | 158   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); | 
|  | 159   for (size_t i = 0; i < num_snippets; i++) { | 
|  | 160     Handle<BytecodeArray> ba = helper.MakeBytecodeForFunction(snippets[i].body); | 
|  | 161     CHECK_EQ(ba->frame_size(), snippets[i].frame_size); | 
|  | 162     CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); | 
|  | 163     CHECK_EQ(ba->length(), snippets[i].bytecode_length); | 
|  | 164     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, | 
|  | 165                   ba->length())); | 
| 124   } | 166   } | 
| 125 } | 167 } | 
| 126 | 168 | 
| 127 }  // namespace interpreter | 169 }  // namespace interpreter | 
| 128 }  // namespace internal | 170 }  // namespace internal | 
| 129 }  // namespance v8 | 171 }  // namespance v8 | 
| OLD | NEW | 
|---|