| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/interpreter/bytecode-array-builder.h" | 8 #include "src/interpreter/bytecode-array-builder.h" |
| 9 #include "src/interpreter/bytecode-array-iterator.h" | 9 #include "src/interpreter/bytecode-array-iterator.h" |
| 10 #include "src/interpreter/bytecode-label.h" | 10 #include "src/interpreter/bytecode-label.h" |
| 11 #include "src/interpreter/bytecode-register-allocator.h" | 11 #include "src/interpreter/bytecode-register-allocator.h" |
| 12 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
| 13 #include "test/unittests/test-utils.h" | 13 #include "test/unittests/test-utils.h" |
| 14 | 14 |
| 15 namespace v8 { | 15 namespace v8 { |
| 16 namespace internal { | 16 namespace internal { |
| 17 namespace interpreter { | 17 namespace interpreter { |
| 18 | 18 |
| 19 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { | 19 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { |
| 20 public: | 20 public: |
| 21 BytecodeArrayBuilderTest() {} | 21 BytecodeArrayBuilderTest() {} |
| 22 ~BytecodeArrayBuilderTest() override {} | 22 ~BytecodeArrayBuilderTest() override {} |
| 23 }; | 23 }; |
| 24 | 24 |
| 25 using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode; |
| 26 |
| 25 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { | 27 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { |
| 26 CanonicalHandleScope canonical(isolate()); | 28 CanonicalHandleScope canonical(isolate()); |
| 27 BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131); | 29 BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131); |
| 28 Factory* factory = isolate()->factory(); | 30 Factory* factory = isolate()->factory(); |
| 29 AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), | 31 AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), |
| 30 isolate()->heap()->HashSeed()); | 32 isolate()->heap()->HashSeed()); |
| 31 DeclarationScope scope(zone(), &ast_factory); | 33 DeclarationScope scope(zone(), &ast_factory); |
| 32 | 34 |
| 33 CHECK_EQ(builder.locals_count(), 131); | 35 CHECK_EQ(builder.locals_count(), 131); |
| 34 CHECK_EQ(builder.context_count(), 1); | 36 CHECK_EQ(builder.context_count(), 1); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 .BinaryOperation(Token::Value::SHL, reg, 5) | 190 .BinaryOperation(Token::Value::SHL, reg, 5) |
| 189 .LoadLiteral(Smi::FromInt(6)) | 191 .LoadLiteral(Smi::FromInt(6)) |
| 190 .BinaryOperation(Token::Value::SAR, reg, 6); | 192 .BinaryOperation(Token::Value::SAR, reg, 6); |
| 191 | 193 |
| 192 // Emit count operatior invocations | 194 // Emit count operatior invocations |
| 193 builder.CountOperation(Token::Value::ADD, 1) | 195 builder.CountOperation(Token::Value::ADD, 1) |
| 194 .CountOperation(Token::Value::SUB, 1); | 196 .CountOperation(Token::Value::SUB, 1); |
| 195 | 197 |
| 196 // Emit unary operator invocations. | 198 // Emit unary operator invocations. |
| 197 builder | 199 builder |
| 198 .LogicalNot() // ToBooleanLogicalNot | 200 .LogicalNot(ToBooleanMode::kConvertToBoolean) |
| 199 .LogicalNot() // non-ToBoolean LogicalNot | 201 .LogicalNot(ToBooleanMode::kAlreadyBoolean) |
| 200 .TypeOf(); | 202 .TypeOf(); |
| 201 | 203 |
| 202 // Emit delete | 204 // Emit delete |
| 203 builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); | 205 builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); |
| 204 | 206 |
| 205 // Emit construct. | 207 // Emit construct. |
| 206 builder.Construct(reg, reg_list, 1).ConstructWithSpread(reg, reg_list); | 208 builder.Construct(reg, reg_list, 1).ConstructWithSpread(reg, reg_list); |
| 207 | 209 |
| 208 // Emit test operator invocations. | 210 // Emit test operator invocations. |
| 209 builder.CompareOperation(Token::Value::EQ, reg, 1) | 211 builder.CompareOperation(Token::Value::EQ, reg, 1) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 234 builder.ConvertAccumulatorToNumber(reg) | 236 builder.ConvertAccumulatorToNumber(reg) |
| 235 .ConvertAccumulatorToObject(reg) | 237 .ConvertAccumulatorToObject(reg) |
| 236 .ConvertAccumulatorToName(reg); | 238 .ConvertAccumulatorToName(reg); |
| 237 | 239 |
| 238 // Emit GetSuperConstructor. | 240 // Emit GetSuperConstructor. |
| 239 builder.GetSuperConstructor(reg); | 241 builder.GetSuperConstructor(reg); |
| 240 | 242 |
| 241 // Short jumps with Imm8 operands | 243 // Short jumps with Imm8 operands |
| 242 { | 244 { |
| 243 BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4, | 245 BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4, |
| 244 after_jump5, after_jump6, after_jump7; | 246 after_jump5, after_jump6, after_jump7, after_jump8, after_jump9, |
| 247 after_jump10, after_jump11; |
| 245 builder.Bind(&start) | 248 builder.Bind(&start) |
| 246 .Jump(&after_jump1) | 249 .Jump(&after_jump1) |
| 247 .Bind(&after_jump1) | 250 .Bind(&after_jump1) |
| 248 .JumpIfNull(&after_jump2) | 251 .JumpIfNull(&after_jump2) |
| 249 .Bind(&after_jump2) | 252 .Bind(&after_jump2) |
| 250 .JumpIfNotNull(&after_jump3) | 253 .JumpIfNotNull(&after_jump3) |
| 251 .Bind(&after_jump3) | 254 .Bind(&after_jump3) |
| 252 .JumpIfUndefined(&after_jump4) | 255 .JumpIfUndefined(&after_jump4) |
| 253 .Bind(&after_jump4) | 256 .Bind(&after_jump4) |
| 254 .JumpIfNotUndefined(&after_jump5) | 257 .JumpIfNotUndefined(&after_jump5) |
| 255 .Bind(&after_jump5) | 258 .Bind(&after_jump5) |
| 256 .JumpIfNotHole(&after_jump6) | 259 .JumpIfNotHole(&after_jump6) |
| 257 .Bind(&after_jump6) | 260 .Bind(&after_jump6) |
| 258 .JumpIfJSReceiver(&after_jump7) | 261 .JumpIfJSReceiver(&after_jump7) |
| 259 .Bind(&after_jump7) | 262 .Bind(&after_jump7) |
| 263 .JumpIfTrue(ToBoolean::kConvertToBoolean, &after_jump8) |
| 264 .Bind(&after_jump8) |
| 265 .JumpIfTrue(ToBoolean::kAlreadyBoolean, &after_jump9) |
| 266 .Bind(&after_jump9) |
| 267 .JumpIfFalse(ToBoolean::kConvertToBoolean, &after_jump10) |
| 268 .Bind(&after_jump10) |
| 269 .JumpIfFalse(ToBoolean::kAlreadyBoolean, &after_jump11) |
| 270 .Bind(&after_jump11) |
| 260 .JumpLoop(&start, 0); | 271 .JumpLoop(&start, 0); |
| 261 } | 272 } |
| 262 | 273 |
| 263 // Longer jumps with constant operands | 274 // Longer jumps with constant operands |
| 264 BytecodeLabel end[11]; | 275 BytecodeLabel end[11]; |
| 265 { | 276 { |
| 266 BytecodeLabel after_jump; | 277 BytecodeLabel after_jump; |
| 267 builder.Jump(&end[0]) | 278 builder.Jump(&end[0]) |
| 268 .Bind(&after_jump) | 279 .Bind(&after_jump) |
| 269 .LoadTrue() | 280 .JumpIfTrue(ToBoolean::kConvertToBoolean, &end[1]) |
| 270 .JumpIfTrue(&end[1]) | 281 .JumpIfTrue(ToBoolean::kAlreadyBoolean, &end[2]) |
| 271 .LoadTrue() | 282 .JumpIfFalse(ToBoolean::kConvertToBoolean, &end[3]) |
| 272 .JumpIfFalse(&end[2]) | 283 .JumpIfFalse(ToBoolean::kAlreadyBoolean, &end[4]) |
| 273 .LoadLiteral(Smi::kZero) | |
| 274 .JumpIfTrue(&end[3]) | |
| 275 .LoadLiteral(Smi::kZero) | |
| 276 .JumpIfFalse(&end[4]) | |
| 277 .JumpIfNull(&end[5]) | 284 .JumpIfNull(&end[5]) |
| 278 .JumpIfNotNull(&end[6]) | 285 .JumpIfNotNull(&end[6]) |
| 279 .JumpIfUndefined(&end[7]) | 286 .JumpIfUndefined(&end[7]) |
| 280 .JumpIfNotUndefined(&end[8]) | 287 .JumpIfNotUndefined(&end[8]) |
| 281 .JumpIfNotHole(&end[9]) | 288 .JumpIfNotHole(&end[9]) |
| 282 .LoadLiteral(ast_factory.prototype_string()) | 289 .LoadLiteral(ast_factory.prototype_string()) |
| 283 .JumpIfJSReceiver(&end[10]); | 290 .JumpIfJSReceiver(&end[10]); |
| 284 } | 291 } |
| 285 | 292 |
| 286 // Perform an operation that returns boolean value to | |
| 287 // generate JumpIfTrue/False | |
| 288 { | |
| 289 BytecodeLabel after_jump1, after_jump2; | |
| 290 builder.CompareOperation(Token::Value::EQ, reg, 1) | |
| 291 .JumpIfTrue(&after_jump1) | |
| 292 .Bind(&after_jump1) | |
| 293 .CompareOperation(Token::Value::EQ, reg, 2) | |
| 294 .JumpIfFalse(&after_jump2) | |
| 295 .Bind(&after_jump2); | |
| 296 } | |
| 297 | |
| 298 // Perform an operation that returns a non-boolean operation to | |
| 299 // generate JumpIfToBooleanTrue/False. | |
| 300 { | |
| 301 BytecodeLabel after_jump1, after_jump2; | |
| 302 builder.BinaryOperation(Token::Value::ADD, reg, 1) | |
| 303 .JumpIfTrue(&after_jump1) | |
| 304 .Bind(&after_jump1) | |
| 305 .BinaryOperation(Token::Value::ADD, reg, 2) | |
| 306 .JumpIfFalse(&after_jump2) | |
| 307 .Bind(&after_jump2); | |
| 308 } | |
| 309 | |
| 310 // Emit set pending message bytecode. | 293 // Emit set pending message bytecode. |
| 311 builder.SetPendingMessage(); | 294 builder.SetPendingMessage(); |
| 312 | 295 |
| 313 // Emit stack check bytecode. | 296 // Emit stack check bytecode. |
| 314 builder.StackCheck(0); | 297 builder.StackCheck(0); |
| 315 | 298 |
| 316 // Emit throw and re-throw in it's own basic block so that the rest of the | 299 // Emit throw and re-throw in it's own basic block so that the rest of the |
| 317 // code isn't omitted due to being dead. | 300 // code isn't omitted due to being dead. |
| 318 BytecodeLabel after_throw; | 301 BytecodeLabel after_throw; |
| 319 builder.Throw().Bind(&after_throw); | 302 builder.Throw().Bind(&after_throw); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 } | 415 } |
| 433 | 416 |
| 434 // Insert entry for illegal bytecode as this is never willingly emitted. | 417 // Insert entry for illegal bytecode as this is never willingly emitted. |
| 435 scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1; | 418 scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1; |
| 436 | 419 |
| 437 // Insert entry for nop bytecode as this often gets optimized out. | 420 // Insert entry for nop bytecode as this often gets optimized out. |
| 438 scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1; | 421 scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1; |
| 439 | 422 |
| 440 if (!FLAG_ignition_peephole) { | 423 if (!FLAG_ignition_peephole) { |
| 441 // Insert entries for bytecodes only emitted by peephole optimizer. | 424 // Insert entries for bytecodes only emitted by peephole optimizer. |
| 442 scorecard[Bytecodes::ToByte(Bytecode::kLogicalNot)] = 1; | |
| 443 scorecard[Bytecodes::ToByte(Bytecode::kJump)] = 1; | |
| 444 scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrue)] = 1; | |
| 445 scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalse)] = 1; | |
| 446 scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrueConstant)] = 1; | |
| 447 scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalseConstant)] = 1; | |
| 448 scorecard[Bytecodes::ToByte(Bytecode::kAddSmi)] = 1; | 425 scorecard[Bytecodes::ToByte(Bytecode::kAddSmi)] = 1; |
| 449 scorecard[Bytecodes::ToByte(Bytecode::kSubSmi)] = 1; | 426 scorecard[Bytecodes::ToByte(Bytecode::kSubSmi)] = 1; |
| 450 scorecard[Bytecodes::ToByte(Bytecode::kBitwiseAndSmi)] = 1; | 427 scorecard[Bytecodes::ToByte(Bytecode::kBitwiseAndSmi)] = 1; |
| 451 scorecard[Bytecodes::ToByte(Bytecode::kBitwiseOrSmi)] = 1; | 428 scorecard[Bytecodes::ToByte(Bytecode::kBitwiseOrSmi)] = 1; |
| 452 scorecard[Bytecodes::ToByte(Bytecode::kShiftLeftSmi)] = 1; | 429 scorecard[Bytecodes::ToByte(Bytecode::kShiftLeftSmi)] = 1; |
| 453 scorecard[Bytecodes::ToByte(Bytecode::kShiftRightSmi)] = 1; | 430 scorecard[Bytecodes::ToByte(Bytecode::kShiftRightSmi)] = 1; |
| 454 } | 431 } |
| 455 | 432 |
| 456 if (!FLAG_type_profile) { | 433 if (!FLAG_type_profile) { |
| 457 // Bytecode for CollectTypeProfile is only emitted when | 434 // Bytecode for CollectTypeProfile is only emitted when |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 iterator.Advance(); | 771 iterator.Advance(); |
| 795 } | 772 } |
| 796 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 773 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
| 797 iterator.Advance(); | 774 iterator.Advance(); |
| 798 CHECK(iterator.done()); | 775 CHECK(iterator.done()); |
| 799 } | 776 } |
| 800 | 777 |
| 801 } // namespace interpreter | 778 } // namespace interpreter |
| 802 } // namespace internal | 779 } // namespace internal |
| 803 } // namespace v8 | 780 } // namespace v8 |
| OLD | NEW |