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-array-iterator.h" | 8 #include "src/interpreter/bytecode-array-iterator.h" |
9 #include "src/interpreter/bytecode-generator.h" | 9 #include "src/interpreter/bytecode-generator.h" |
10 #include "src/interpreter/interpreter.h" | 10 #include "src/interpreter/interpreter.h" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 } | 70 } |
71 }; | 71 }; |
72 | 72 |
73 | 73 |
74 // Helper macros for handcrafting bytecode sequences. | 74 // Helper macros for handcrafting bytecode sequences. |
75 #define B(x) static_cast<uint8_t>(Bytecode::k##x) | 75 #define B(x) static_cast<uint8_t>(Bytecode::k##x) |
76 #define U8(x) static_cast<uint8_t>((x) & 0xff) | 76 #define U8(x) static_cast<uint8_t>((x) & 0xff) |
77 #define R(x) static_cast<uint8_t>(-(x) & 0xff) | 77 #define R(x) static_cast<uint8_t>(-(x) & 0xff) |
78 #define A(x, n) R(helper.kLastParamIndex - (n) + 1 + (x)) | 78 #define A(x, n) R(helper.kLastParamIndex - (n) + 1 + (x)) |
79 #define THIS(n) A(0, n) | 79 #define THIS(n) A(0, n) |
80 #define _ static_cast<uint8_t>(0x5a) | |
81 #if defined(V8_TARGET_LITTLE_ENDIAN) | 80 #if defined(V8_TARGET_LITTLE_ENDIAN) |
82 #define U16(x) static_cast<uint8_t>((x) & 0xff), \ | 81 #define U16(x) static_cast<uint8_t>((x) & 0xff), \ |
83 static_cast<uint8_t>(((x) >> kBitsPerByte) & 0xff) | 82 static_cast<uint8_t>(((x) >> kBitsPerByte) & 0xff) |
84 #elif defined(V8_TARGET_BIG_ENDIAN) | 83 #elif defined(V8_TARGET_BIG_ENDIAN) |
85 #define U16(x) static_cast<uint8_t>(((x) >> kBitsPerByte) & 0xff), \ | 84 #define U16(x) static_cast<uint8_t>(((x) >> kBitsPerByte) & 0xff), \ |
86 static_cast<uint8_t>((x) & 0xff) | 85 static_cast<uint8_t>((x) & 0xff) |
87 #else | 86 #else |
88 #error Unknown byte ordering | 87 #error Unknown byte ordering |
89 #endif | 88 #endif |
90 | 89 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 } | 123 } |
125 | 124 |
126 | 125 |
127 static void CheckConstant(InstanceType expected, Object* actual) { | 126 static void CheckConstant(InstanceType expected, Object* actual) { |
128 CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type()); | 127 CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type()); |
129 } | 128 } |
130 | 129 |
131 | 130 |
132 template <typename T> | 131 template <typename T> |
133 static void CheckBytecodeArrayEqual(const ExpectedSnippet<T>& expected, | 132 static void CheckBytecodeArrayEqual(const ExpectedSnippet<T>& expected, |
134 Handle<BytecodeArray> actual, | 133 Handle<BytecodeArray> actual) { |
135 bool has_unknown = false) { | |
136 CHECK_EQ(expected.frame_size, actual->frame_size()); | 134 CHECK_EQ(expected.frame_size, actual->frame_size()); |
137 CHECK_EQ(expected.parameter_count, actual->parameter_count()); | 135 CHECK_EQ(expected.parameter_count, actual->parameter_count()); |
138 CHECK_EQ(expected.bytecode_length, actual->length()); | 136 CHECK_EQ(expected.bytecode_length, actual->length()); |
139 if (expected.constant_count == 0) { | 137 if (expected.constant_count == 0) { |
140 CHECK_EQ(CcTest::heap()->empty_fixed_array(), actual->constant_pool()); | 138 CHECK_EQ(CcTest::heap()->empty_fixed_array(), actual->constant_pool()); |
141 } else { | 139 } else { |
142 CHECK_EQ(expected.constant_count, actual->constant_pool()->length()); | 140 CHECK_EQ(expected.constant_count, actual->constant_pool()->length()); |
143 for (int i = 0; i < expected.constant_count; i++) { | 141 for (int i = 0; i < expected.constant_count; i++) { |
144 CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); | 142 CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); |
145 } | 143 } |
(...skipping 10 matching lines...) Expand all Loading... |
156 << "] to be " << Bytecodes::ToString(static_cast<Bytecode>( | 154 << "] to be " << Bytecodes::ToString(static_cast<Bytecode>( |
157 expected.bytecode[bytecode_index])) | 155 expected.bytecode[bytecode_index])) |
158 << " but got " << Bytecodes::ToString(bytecode); | 156 << " but got " << Bytecodes::ToString(bytecode); |
159 FATAL(stream.str().c_str()); | 157 FATAL(stream.str().c_str()); |
160 } | 158 } |
161 for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j) { | 159 for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j) { |
162 OperandType operand_type = Bytecodes::GetOperandType(bytecode, j); | 160 OperandType operand_type = Bytecodes::GetOperandType(bytecode, j); |
163 int operand_index = i; | 161 int operand_index = i; |
164 i += static_cast<int>(Bytecodes::SizeOfOperand(operand_type)); | 162 i += static_cast<int>(Bytecodes::SizeOfOperand(operand_type)); |
165 uint32_t raw_operand = iterator.GetRawOperand(j, operand_type); | 163 uint32_t raw_operand = iterator.GetRawOperand(j, operand_type); |
166 if (has_unknown) { | |
167 // Check actual bytecode array doesn't have the same byte as the | |
168 // one we use to specify an unknown byte. | |
169 CHECK_NE(raw_operand, _); | |
170 if (expected.bytecode[operand_index] == _) { | |
171 continue; | |
172 } | |
173 } | |
174 uint32_t expected_operand; | 164 uint32_t expected_operand; |
175 switch (Bytecodes::SizeOfOperand(operand_type)) { | 165 switch (Bytecodes::SizeOfOperand(operand_type)) { |
176 case OperandSize::kNone: | 166 case OperandSize::kNone: |
177 UNREACHABLE(); | 167 UNREACHABLE(); |
178 return; | 168 return; |
179 case OperandSize::kByte: | 169 case OperandSize::kByte: |
180 expected_operand = | 170 expected_operand = |
181 static_cast<uint32_t>(expected.bytecode[operand_index]); | 171 static_cast<uint32_t>(expected.bytecode[operand_index]); |
182 break; | 172 break; |
183 case OperandSize::kShort: | 173 case OperandSize::kShort: |
(...skipping 1334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1518 B(Return) // | 1508 B(Return) // |
1519 }, | 1509 }, |
1520 2, | 1510 2, |
1521 {InstanceType::FIXED_ARRAY_TYPE, | 1511 {InstanceType::FIXED_ARRAY_TYPE, |
1522 InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, | 1512 InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, |
1523 }; | 1513 }; |
1524 | 1514 |
1525 for (size_t i = 0; i < arraysize(snippets); i++) { | 1515 for (size_t i = 0; i < arraysize(snippets); i++) { |
1526 Handle<BytecodeArray> bytecode_array = | 1516 Handle<BytecodeArray> bytecode_array = |
1527 helper.MakeTopLevelBytecode(snippets[i].code_snippet); | 1517 helper.MakeTopLevelBytecode(snippets[i].code_snippet); |
1528 CheckBytecodeArrayEqual(snippets[i], bytecode_array, true); | 1518 CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
1529 } | 1519 } |
1530 } | 1520 } |
1531 | 1521 |
1532 | 1522 |
1533 TEST(BasicLoops) { | 1523 TEST(BasicLoops) { |
1534 InitializedHandleScope handle_scope; | 1524 InitializedHandleScope handle_scope; |
1535 BytecodeGeneratorHelper helper; | 1525 BytecodeGeneratorHelper helper; |
1536 | 1526 |
1537 ExpectedSnippet<int> snippets[] = { | 1527 ExpectedSnippet<int> snippets[] = { |
1538 {"var x = 0;" | 1528 {"var x = 0;" |
(...skipping 1163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2702 B(New), R(0), R(1), U8(3), // | 2692 B(New), R(0), R(1), U8(3), // |
2703 B(Return), // | 2693 B(Return), // |
2704 }, | 2694 }, |
2705 1, | 2695 1, |
2706 {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, | 2696 {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, |
2707 }; | 2697 }; |
2708 | 2698 |
2709 for (size_t i = 0; i < arraysize(snippets); i++) { | 2699 for (size_t i = 0; i < arraysize(snippets); i++) { |
2710 Handle<BytecodeArray> bytecode_array = | 2700 Handle<BytecodeArray> bytecode_array = |
2711 helper.MakeBytecode(snippets[i].code_snippet, "f"); | 2701 helper.MakeBytecode(snippets[i].code_snippet, "f"); |
2712 CheckBytecodeArrayEqual(snippets[i], bytecode_array, true); | 2702 CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
2713 } | 2703 } |
2714 } | 2704 } |
2715 | 2705 |
2716 | 2706 |
2717 TEST(ContextVariables) { | 2707 TEST(ContextVariables) { |
2718 InitializedHandleScope handle_scope; | 2708 InitializedHandleScope handle_scope; |
2719 BytecodeGeneratorHelper helper; | 2709 BytecodeGeneratorHelper helper; |
2720 | 2710 |
2721 int closure = Register::function_closure().index(); | 2711 int closure = Register::function_closure().index(); |
2722 int first_context_slot = Context::MIN_CONTEXT_SLOTS; | 2712 int first_context_slot = Context::MIN_CONTEXT_SLOTS; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2831 } | 2821 } |
2832 } | 2822 } |
2833 | 2823 |
2834 | 2824 |
2835 TEST(ContextParameters) { | 2825 TEST(ContextParameters) { |
2836 InitializedHandleScope handle_scope; | 2826 InitializedHandleScope handle_scope; |
2837 BytecodeGeneratorHelper helper; | 2827 BytecodeGeneratorHelper helper; |
2838 | 2828 |
2839 int closure = Register::function_closure().index(); | 2829 int closure = Register::function_closure().index(); |
2840 int first_context_slot = Context::MIN_CONTEXT_SLOTS; | 2830 int first_context_slot = Context::MIN_CONTEXT_SLOTS; |
| 2831 |
2841 ExpectedSnippet<InstanceType> snippets[] = { | 2832 ExpectedSnippet<InstanceType> snippets[] = { |
2842 {"function f(arg1) { return function() { arg1 = 2; }; }", | 2833 {"function f(arg1) { return function() { arg1 = 2; }; }", |
2843 1 * kPointerSize, | 2834 1 * kPointerSize, |
2844 2, | 2835 2, |
2845 17, | 2836 17, |
2846 { | 2837 { |
2847 B(CallRuntime), U16(Runtime::kNewFunctionContext), // | 2838 B(CallRuntime), U16(Runtime::kNewFunctionContext), // |
2848 R(closure), U8(1), // | 2839 R(closure), U8(1), // |
2849 B(PushContext), R(0), // | 2840 B(PushContext), R(0), // |
2850 B(Ldar), R(helper.kLastParamIndex), // | 2841 B(Ldar), R(helper.kLastParamIndex), // |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3194 B(Ldar), R(0), // | 3185 B(Ldar), R(0), // |
3195 B(Return), | 3186 B(Return), |
3196 }, | 3187 }, |
3197 1, | 3188 1, |
3198 {"unallocated"}}, | 3189 {"unallocated"}}, |
3199 }; | 3190 }; |
3200 | 3191 |
3201 for (size_t i = 0; i < arraysize(snippets); i++) { | 3192 for (size_t i = 0; i < arraysize(snippets); i++) { |
3202 Handle<BytecodeArray> bytecode_array = | 3193 Handle<BytecodeArray> bytecode_array = |
3203 helper.MakeBytecode(snippets[i].code_snippet, "f"); | 3194 helper.MakeBytecode(snippets[i].code_snippet, "f"); |
3204 CheckBytecodeArrayEqual(snippets[i], bytecode_array, true); | 3195 CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
3205 } | 3196 } |
3206 } | 3197 } |
3207 | 3198 |
| 3199 |
| 3200 TEST(CompoundExpressions) { |
| 3201 InitializedHandleScope handle_scope; |
| 3202 BytecodeGeneratorHelper helper; |
| 3203 Zone zone; |
| 3204 |
| 3205 int closure = Register::function_closure().index(); |
| 3206 int first_context_slot = Context::MIN_CONTEXT_SLOTS; |
| 3207 |
| 3208 FeedbackVectorSpec feedback_spec(&zone); |
| 3209 FeedbackVectorSlot slot1 = feedback_spec.AddLoadICSlot(); |
| 3210 FeedbackVectorSlot slot2 = feedback_spec.AddStoreICSlot(); |
| 3211 |
| 3212 Handle<i::TypeFeedbackVector> vector = |
| 3213 i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); |
| 3214 |
| 3215 int object_literal_flags = |
| 3216 ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; |
| 3217 ExpectedSnippet<InstanceType> snippets[] = { |
| 3218 {"var a = 1; a += 2;", |
| 3219 1 * kPointerSize, |
| 3220 1, |
| 3221 12, |
| 3222 { |
| 3223 B(LdaSmi8), U8(1), // |
| 3224 B(Star), R(0), // |
| 3225 B(LdaSmi8), U8(2), // |
| 3226 B(Add), R(0), // |
| 3227 B(Star), R(0), // |
| 3228 B(LdaUndefined), // |
| 3229 B(Return), // |
| 3230 }}, |
| 3231 {"var a = 1; a /= 2;", |
| 3232 1 * kPointerSize, |
| 3233 1, |
| 3234 12, |
| 3235 { |
| 3236 B(LdaSmi8), U8(1), // |
| 3237 B(Star), R(0), // |
| 3238 B(LdaSmi8), U8(2), // |
| 3239 B(Div), R(0), // |
| 3240 B(Star), R(0), // |
| 3241 B(LdaUndefined), // |
| 3242 B(Return), // |
| 3243 }}, |
| 3244 {"var a = { val: 2 }; a.name *= 2;", |
| 3245 2 * kPointerSize, |
| 3246 1, |
| 3247 23, |
| 3248 { |
| 3249 B(LdaConstant), U8(0), // |
| 3250 B(CreateObjectLiteral), U8(0), U8(object_literal_flags), // |
| 3251 B(Star), R(0), // |
| 3252 B(LoadICSloppy), R(0), U8(1), U8(vector->GetIndex(slot1)), // |
| 3253 B(Star), R(1), // |
| 3254 B(LdaSmi8), U8(2), // |
| 3255 B(Mul), R(1), // |
| 3256 B(StoreICSloppy), R(0), U8(1), U8(vector->GetIndex(slot2)), // |
| 3257 B(LdaUndefined), // |
| 3258 B(Return), // |
| 3259 }, |
| 3260 2, |
| 3261 {InstanceType::FIXED_ARRAY_TYPE, |
| 3262 InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, |
| 3263 {"var a = { 1: 2 }; a[1] ^= 2;", |
| 3264 3 * kPointerSize, |
| 3265 1, |
| 3266 26, |
| 3267 { |
| 3268 B(LdaConstant), U8(0), // |
| 3269 B(CreateObjectLiteral), U8(0), U8(object_literal_flags), // |
| 3270 B(Star), R(0), // |
| 3271 B(LdaSmi8), U8(1), // |
| 3272 B(Star), R(1), // |
| 3273 B(KeyedLoadICSloppy), R(0), U8(vector->GetIndex(slot1)), // |
| 3274 B(Star), R(2), // |
| 3275 B(LdaSmi8), U8(2), // |
| 3276 B(BitwiseXor), R(2), // |
| 3277 B(KeyedStoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot2)), // |
| 3278 B(LdaUndefined), // |
| 3279 B(Return), // |
| 3280 }, |
| 3281 1, |
| 3282 {InstanceType::FIXED_ARRAY_TYPE}}, |
| 3283 {"var a = 1; (function f() { return a; }); a |= 24;", |
| 3284 2 * kPointerSize, |
| 3285 1, |
| 3286 30, |
| 3287 { |
| 3288 B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // |
| 3289 U8(1), // |
| 3290 B(PushContext), R(0), // |
| 3291 B(LdaSmi8), U8(1), // |
| 3292 B(StaContextSlot), R(0), U8(first_context_slot), // |
| 3293 B(LdaConstant), U8(0), // |
| 3294 B(CreateClosure), U8(0), // |
| 3295 B(LdaContextSlot), R(0), U8(first_context_slot), // |
| 3296 B(Star), R(1), // |
| 3297 B(LdaSmi8), U8(24), // |
| 3298 B(BitwiseOr), R(1), // |
| 3299 B(StaContextSlot), R(0), U8(first_context_slot), // |
| 3300 B(LdaUndefined), // |
| 3301 B(Return), // |
| 3302 }, |
| 3303 1, |
| 3304 {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, |
| 3305 }; |
| 3306 |
| 3307 for (size_t i = 0; i < arraysize(snippets); i++) { |
| 3308 Handle<BytecodeArray> bytecode_array = |
| 3309 helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); |
| 3310 CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
| 3311 } |
| 3312 } |
| 3313 |
| 3314 |
| 3315 TEST(GlobalCompoundExpressions) { |
| 3316 InitializedHandleScope handle_scope; |
| 3317 BytecodeGeneratorHelper helper; |
| 3318 Zone zone; |
| 3319 |
| 3320 FeedbackVectorSpec feedback_spec(&zone); |
| 3321 FeedbackVectorSlot slot1 = feedback_spec.AddLoadICSlot(); |
| 3322 FeedbackVectorSlot slot2 = feedback_spec.AddStoreICSlot(); |
| 3323 |
| 3324 Handle<i::TypeFeedbackVector> vector = |
| 3325 i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); |
| 3326 |
| 3327 ExpectedSnippet<const char*> snippets[] = { |
| 3328 {"var global = 1;\nfunction f() { return global &= 1; }\nf()", |
| 3329 1 * kPointerSize, |
| 3330 1, |
| 3331 13, |
| 3332 { |
| 3333 B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // |
| 3334 B(Star), R(0), // |
| 3335 B(LdaSmi8), U8(1), // |
| 3336 B(BitwiseAnd), R(0), // |
| 3337 B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // |
| 3338 B(Return), // |
| 3339 }, |
| 3340 1, |
| 3341 {"global"}}, |
| 3342 {"unallocated = 1;\nfunction f() { return unallocated += 1; }\nf()", |
| 3343 1 * kPointerSize, |
| 3344 1, |
| 3345 13, |
| 3346 { |
| 3347 B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // |
| 3348 B(Star), R(0), // |
| 3349 B(LdaSmi8), U8(1), // |
| 3350 B(Add), R(0), // |
| 3351 B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // |
| 3352 B(Return), // |
| 3353 }, |
| 3354 1, |
| 3355 {"unallocated"}}, |
| 3356 }; |
| 3357 |
| 3358 for (size_t i = 0; i < arraysize(snippets); i++) { |
| 3359 Handle<BytecodeArray> bytecode_array = |
| 3360 helper.MakeBytecode(snippets[i].code_snippet, "f"); |
| 3361 CheckBytecodeArrayEqual(snippets[i], bytecode_array); |
| 3362 } |
| 3363 } |
| 3364 |
3208 } // namespace interpreter | 3365 } // namespace interpreter |
3209 } // namespace internal | 3366 } // namespace internal |
3210 } // namespace v8 | 3367 } // namespace v8 |
OLD | NEW |