| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 function_ = fun; | 55 function_ = fun; |
| 56 SetFunctionPosition(fun); | 56 SetFunctionPosition(fun); |
| 57 | 57 |
| 58 __ push(rbp); // Caller's frame pointer. | 58 __ push(rbp); // Caller's frame pointer. |
| 59 __ movq(rbp, rsp); | 59 __ movq(rbp, rsp); |
| 60 __ push(rsi); // Callee's context. | 60 __ push(rsi); // Callee's context. |
| 61 __ push(rdi); // Callee's JS Function. | 61 __ push(rdi); // Callee's JS Function. |
| 62 | 62 |
| 63 { Comment cmnt(masm_, "[ Allocate locals"); | 63 { Comment cmnt(masm_, "[ Allocate locals"); |
| 64 int locals_count = fun->scope()->num_stack_slots(); | 64 int locals_count = fun->scope()->num_stack_slots(); |
| 65 if (locals_count <= 1) { | 65 if (locals_count == 1) { |
| 66 if (locals_count > 0) { | 66 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 67 __ PushRoot(Heap::kUndefinedValueRootIndex); | 67 } else if (locals_count > 1) { |
| 68 } | |
| 69 } else { | |
| 70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 68 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 71 for (int i = 0; i < locals_count; i++) { | 69 for (int i = 0; i < locals_count; i++) { |
| 72 __ push(rdx); | 70 __ push(rdx); |
| 73 } | 71 } |
| 74 } | 72 } |
| 75 } | 73 } |
| 76 | 74 |
| 77 bool function_in_register = true; | 75 bool function_in_register = true; |
| 78 | 76 |
| 79 // Possibly allocate a local context. | 77 // Possibly allocate a local context. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 123 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 126 __ CallStub(&stub); | 124 __ CallStub(&stub); |
| 127 // Store new arguments object in both "arguments" and ".arguments" slots. | 125 // Store new arguments object in both "arguments" and ".arguments" slots. |
| 128 __ movq(rcx, rax); | 126 __ movq(rcx, rax); |
| 129 Move(arguments->slot(), rax, rbx, rdx); | 127 Move(arguments->slot(), rax, rbx, rdx); |
| 130 Slot* dot_arguments_slot = | 128 Slot* dot_arguments_slot = |
| 131 fun->scope()->arguments_shadow()->AsVariable()->slot(); | 129 fun->scope()->arguments_shadow()->AsVariable()->slot(); |
| 132 Move(dot_arguments_slot, rcx, rbx, rdx); | 130 Move(dot_arguments_slot, rcx, rbx, rdx); |
| 133 } | 131 } |
| 134 | 132 |
| 133 { Comment cmnt(masm_, "[ Declarations"); |
| 134 VisitDeclarations(fun->scope()->declarations()); |
| 135 } |
| 136 |
| 135 { Comment cmnt(masm_, "[ Stack check"); | 137 { Comment cmnt(masm_, "[ Stack check"); |
| 136 Label ok; | 138 Label ok; |
| 137 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 139 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 138 __ j(above_equal, &ok); | 140 __ j(above_equal, &ok); |
| 139 StackCheckStub stub; | 141 StackCheckStub stub; |
| 140 __ CallStub(&stub); | 142 __ CallStub(&stub); |
| 141 __ bind(&ok); | 143 __ bind(&ok); |
| 142 } | 144 } |
| 143 | 145 |
| 144 { Comment cmnt(masm_, "[ Declarations"); | |
| 145 VisitDeclarations(fun->scope()->declarations()); | |
| 146 } | |
| 147 | |
| 148 if (FLAG_trace) { | 146 if (FLAG_trace) { |
| 149 __ CallRuntime(Runtime::kTraceEnter, 0); | 147 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 150 } | 148 } |
| 151 | 149 |
| 152 { Comment cmnt(masm_, "[ Body"); | 150 { Comment cmnt(masm_, "[ Body"); |
| 153 ASSERT(loop_depth() == 0); | 151 ASSERT(loop_depth() == 0); |
| 154 VisitStatements(fun->body()); | 152 VisitStatements(fun->body()); |
| 155 ASSERT(loop_depth() == 0); | 153 ASSERT(loop_depth() == 0); |
| 156 } | 154 } |
| 157 | 155 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 } | 193 } |
| 196 // Check that the size of the code used for returning matches what is | 194 // Check that the size of the code used for returning matches what is |
| 197 // expected by the debugger. | 195 // expected by the debugger. |
| 198 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 196 ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
| 199 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 197 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 200 #endif | 198 #endif |
| 201 } | 199 } |
| 202 } | 200 } |
| 203 | 201 |
| 204 | 202 |
| 205 void FastCodeGenerator::Apply(Expression::Context context, | 203 void FastCodeGenerator::Apply(Expression::Context context, Register reg) { |
| 206 Slot* slot, | 204 switch (context) { |
| 207 Register scratch) { | 205 case Expression::kUninitialized: |
| 206 UNREACHABLE(); |
| 207 |
| 208 case Expression::kEffect: |
| 209 // Nothing to do. |
| 210 break; |
| 211 |
| 212 case Expression::kValue: |
| 213 // Move value into place. |
| 214 switch (location_) { |
| 215 case kAccumulator: |
| 216 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 217 break; |
| 218 case kStack: |
| 219 __ push(reg); |
| 220 break; |
| 221 } |
| 222 break; |
| 223 |
| 224 case Expression::kTest: |
| 225 // For simplicity we always test the accumulator register. |
| 226 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 227 DoTest(context); |
| 228 break; |
| 229 |
| 230 case Expression::kValueTest: |
| 231 case Expression::kTestValue: |
| 232 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 233 switch (location_) { |
| 234 case kAccumulator: |
| 235 break; |
| 236 case kStack: |
| 237 __ push(result_register()); |
| 238 break; |
| 239 } |
| 240 DoTest(context); |
| 241 break; |
| 242 } |
| 243 } |
| 244 |
| 245 |
| 246 void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) { |
| 208 switch (context) { | 247 switch (context) { |
| 209 case Expression::kUninitialized: | 248 case Expression::kUninitialized: |
| 210 UNREACHABLE(); | 249 UNREACHABLE(); |
| 211 case Expression::kEffect: | 250 case Expression::kEffect: |
| 251 // Nothing to do. |
| 212 break; | 252 break; |
| 213 case Expression::kValue: { | 253 case Expression::kValue: { |
| 214 MemOperand location = EmitSlotSearch(slot, scratch); | 254 MemOperand slot_operand = EmitSlotSearch(slot, result_register()); |
| 215 __ push(location); | 255 switch (location_) { |
| 256 case kAccumulator: |
| 257 __ movq(result_register(), slot_operand); |
| 258 break; |
| 259 case kStack: |
| 260 // Memory operands can be pushed directly. |
| 261 __ push(slot_operand); |
| 262 break; |
| 263 } |
| 216 break; | 264 break; |
| 217 } | 265 } |
| 266 |
| 218 case Expression::kTest: | 267 case Expression::kTest: |
| 268 Move(result_register(), slot); |
| 269 DoTest(context); |
| 270 break; |
| 271 |
| 219 case Expression::kValueTest: | 272 case Expression::kValueTest: |
| 220 case Expression::kTestValue: | 273 case Expression::kTestValue: |
| 221 Move(scratch, slot); | 274 Move(result_register(), slot); |
| 222 Apply(context, scratch); | 275 switch (location_) { |
| 276 case kAccumulator: |
| 277 break; |
| 278 case kStack: |
| 279 __ push(result_register()); |
| 280 break; |
| 281 } |
| 282 DoTest(context); |
| 223 break; | 283 break; |
| 224 } | 284 } |
| 225 } | 285 } |
| 226 | 286 |
| 227 | 287 |
| 228 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { | 288 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { |
| 229 switch (context) { | 289 switch (context) { |
| 230 case Expression::kUninitialized: | 290 case Expression::kUninitialized: |
| 231 UNREACHABLE(); | 291 UNREACHABLE(); |
| 232 case Expression::kEffect: | 292 case Expression::kEffect: |
| 293 // Nothing to do. |
| 233 break; | 294 break; |
| 234 case Expression::kValue: | 295 case Expression::kValue: |
| 235 __ Push(lit->handle()); | 296 switch (location_) { |
| 297 case kAccumulator: |
| 298 __ Move(result_register(), lit->handle()); |
| 299 break; |
| 300 case kStack: |
| 301 __ Push(lit->handle()); |
| 302 break; |
| 303 } |
| 236 break; | 304 break; |
| 305 |
| 237 case Expression::kTest: | 306 case Expression::kTest: |
| 307 __ Move(result_register(), lit->handle()); |
| 308 DoTest(context); |
| 309 break; |
| 310 |
| 238 case Expression::kValueTest: | 311 case Expression::kValueTest: |
| 239 case Expression::kTestValue: | 312 case Expression::kTestValue: |
| 240 __ Move(rax, lit->handle()); | 313 __ Move(result_register(), lit->handle()); |
| 241 Apply(context, rax); | 314 switch (location_) { |
| 315 case kAccumulator: |
| 316 break; |
| 317 case kStack: |
| 318 __ push(result_register()); |
| 319 break; |
| 320 } |
| 321 DoTest(context); |
| 242 break; | 322 break; |
| 243 } | 323 } |
| 244 } | 324 } |
| 245 | 325 |
| 246 | 326 |
| 247 void FastCodeGenerator::ApplyTOS(Expression::Context context) { | 327 void FastCodeGenerator::ApplyTOS(Expression::Context context) { |
| 248 switch (context) { | 328 switch (context) { |
| 249 case Expression::kUninitialized: | 329 case Expression::kUninitialized: |
| 250 UNREACHABLE(); | 330 UNREACHABLE(); |
| 331 |
| 251 case Expression::kEffect: | 332 case Expression::kEffect: |
| 252 __ Drop(1); | 333 __ Drop(1); |
| 253 break; | 334 break; |
| 335 |
| 254 case Expression::kValue: | 336 case Expression::kValue: |
| 337 switch (location_) { |
| 338 case kAccumulator: |
| 339 __ pop(result_register()); |
| 340 break; |
| 341 case kStack: |
| 342 break; |
| 343 } |
| 255 break; | 344 break; |
| 345 |
| 256 case Expression::kTest: | 346 case Expression::kTest: |
| 257 __ pop(rax); | 347 __ pop(result_register()); |
| 258 TestAndBranch(rax, true_label_, false_label_); | 348 DoTest(context); |
| 259 break; | 349 break; |
| 260 case Expression::kValueTest: { | 350 |
| 261 Label discard; | 351 case Expression::kValueTest: |
| 262 __ movq(rax, Operand(rsp, 0)); | 352 case Expression::kTestValue: |
| 263 TestAndBranch(rax, true_label_, &discard); | 353 switch (location_) { |
| 264 __ bind(&discard); | 354 case kAccumulator: |
| 265 __ Drop(1); | 355 __ pop(result_register()); |
| 266 __ jmp(false_label_); | 356 break; |
| 357 case kStack: |
| 358 __ movq(result_register(), Operand(rsp, 0)); |
| 359 break; |
| 360 } |
| 361 DoTest(context); |
| 267 break; | 362 break; |
| 268 } | |
| 269 case Expression::kTestValue: { | |
| 270 Label discard; | |
| 271 __ movq(rax, Operand(rsp, 0)); | |
| 272 TestAndBranch(rax, &discard, false_label_); | |
| 273 __ bind(&discard); | |
| 274 __ Drop(1); | |
| 275 __ jmp(true_label_); | |
| 276 } | |
| 277 } | 363 } |
| 278 } | 364 } |
| 279 | 365 |
| 280 | 366 |
| 281 void FastCodeGenerator::DropAndApply(int count, | 367 void FastCodeGenerator::DropAndApply(int count, |
| 282 Expression::Context context, | 368 Expression::Context context, |
| 283 Register reg) { | 369 Register reg) { |
| 284 ASSERT(count > 0); | 370 ASSERT(count > 0); |
| 285 ASSERT(!reg.is(rsp)); | 371 ASSERT(!reg.is(rsp)); |
| 286 switch (context) { | 372 switch (context) { |
| 287 case Expression::kUninitialized: | 373 case Expression::kUninitialized: |
| 288 UNREACHABLE(); | 374 UNREACHABLE(); |
| 375 |
| 289 case Expression::kEffect: | 376 case Expression::kEffect: |
| 290 __ Drop(count); | 377 __ Drop(count); |
| 291 break; | 378 break; |
| 292 case Expression::kValue: | 379 |
| 293 if (count > 1) __ Drop(count - 1); | 380 case Expression::kValue: |
| 294 __ movq(Operand(rsp, 0), reg); | 381 switch (location_) { |
| 295 break; | 382 case kAccumulator: |
| 383 __ Drop(count); |
| 384 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 385 break; |
| 386 case kStack: |
| 387 if (count > 1) __ Drop(count - 1); |
| 388 __ movq(Operand(rsp, 0), reg); |
| 389 break; |
| 390 } |
| 391 break; |
| 392 |
| 296 case Expression::kTest: | 393 case Expression::kTest: |
| 297 __ Drop(count); | 394 __ Drop(count); |
| 298 TestAndBranch(reg, true_label_, false_label_); | 395 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 299 break; | 396 DoTest(context); |
| 300 case Expression::kValueTest: { | 397 break; |
| 301 Label discard; | 398 |
| 302 if (count > 1) __ Drop(count - 1); | 399 case Expression::kValueTest: |
| 303 __ movq(Operand(rsp, 0), reg); | 400 case Expression::kTestValue: |
| 304 TestAndBranch(reg, true_label_, &discard); | 401 switch (location_) { |
| 402 case kAccumulator: |
| 403 __ Drop(count); |
| 404 if (!reg.is(result_register())) __ movq(result_register(), reg); |
| 405 break; |
| 406 case kStack: |
| 407 if (count > 1) __ Drop(count - 1); |
| 408 __ movq(result_register(), reg); |
| 409 __ movq(Operand(rsp, 0), result_register()); |
| 410 break; |
| 411 } |
| 412 DoTest(context); |
| 413 break; |
| 414 } |
| 415 } |
| 416 |
| 417 |
| 418 void FastCodeGenerator::Apply(Expression::Context context, |
| 419 Label* materialize_true, |
| 420 Label* materialize_false) { |
| 421 switch (context) { |
| 422 case Expression::kUninitialized: |
| 423 |
| 424 case Expression::kEffect: |
| 425 ASSERT_EQ(materialize_true, materialize_false); |
| 426 __ bind(materialize_true); |
| 427 break; |
| 428 |
| 429 case Expression::kValue: { |
| 430 Label done; |
| 431 switch (location_) { |
| 432 case kAccumulator: |
| 433 __ bind(materialize_true); |
| 434 __ Move(result_register(), Factory::true_value()); |
| 435 __ jmp(&done); |
| 436 __ bind(materialize_false); |
| 437 __ Move(result_register(), Factory::false_value()); |
| 438 break; |
| 439 case kStack: |
| 440 __ bind(materialize_true); |
| 441 __ Push(Factory::true_value()); |
| 442 __ jmp(&done); |
| 443 __ bind(materialize_false); |
| 444 __ Push(Factory::false_value()); |
| 445 break; |
| 446 } |
| 447 __ bind(&done); |
| 448 break; |
| 449 } |
| 450 |
| 451 case Expression::kTest: |
| 452 break; |
| 453 |
| 454 case Expression::kValueTest: |
| 455 __ bind(materialize_true); |
| 456 switch (location_) { |
| 457 case kAccumulator: |
| 458 __ Move(result_register(), Factory::true_value()); |
| 459 break; |
| 460 case kStack: |
| 461 __ Push(Factory::true_value()); |
| 462 break; |
| 463 } |
| 464 __ jmp(true_label_); |
| 465 break; |
| 466 |
| 467 case Expression::kTestValue: |
| 468 __ bind(materialize_false); |
| 469 switch (location_) { |
| 470 case kAccumulator: |
| 471 __ Move(result_register(), Factory::false_value()); |
| 472 break; |
| 473 case kStack: |
| 474 __ Push(Factory::false_value()); |
| 475 break; |
| 476 } |
| 477 __ jmp(false_label_); |
| 478 break; |
| 479 } |
| 480 } |
| 481 |
| 482 |
| 483 void FastCodeGenerator::DoTest(Expression::Context context) { |
| 484 // The value to test is in the accumulator. If the value might be needed |
| 485 // on the stack (value/test and test/value contexts with a stack location |
| 486 // desired), then the value is already duplicated on the stack. |
| 487 ASSERT_NE(NULL, true_label_); |
| 488 ASSERT_NE(NULL, false_label_); |
| 489 |
| 490 // In value/test and test/value expression contexts with stack as the |
| 491 // desired location, there is already an extra value on the stack. Use a |
| 492 // label to discard it if unneeded. |
| 493 Label discard; |
| 494 Label* if_true = true_label_; |
| 495 Label* if_false = false_label_; |
| 496 switch (context) { |
| 497 case Expression::kUninitialized: |
| 498 case Expression::kEffect: |
| 499 case Expression::kValue: |
| 500 UNREACHABLE(); |
| 501 case Expression::kTest: |
| 502 break; |
| 503 case Expression::kValueTest: |
| 504 switch (location_) { |
| 505 case kAccumulator: |
| 506 break; |
| 507 case kStack: |
| 508 if_false = &discard; |
| 509 break; |
| 510 } |
| 511 break; |
| 512 case Expression::kTestValue: |
| 513 switch (location_) { |
| 514 case kAccumulator: |
| 515 break; |
| 516 case kStack: |
| 517 if_true = &discard; |
| 518 break; |
| 519 } |
| 520 break; |
| 521 } |
| 522 |
| 523 // Emit the inlined tests assumed by the stub. |
| 524 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 525 __ j(equal, if_false); |
| 526 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); |
| 527 __ j(equal, if_true); |
| 528 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); |
| 529 __ j(equal, if_false); |
| 530 ASSERT_EQ(0, kSmiTag); |
| 531 __ SmiCompare(result_register(), Smi::FromInt(0)); |
| 532 __ j(equal, if_false); |
| 533 Condition is_smi = masm_->CheckSmi(result_register()); |
| 534 __ j(is_smi, if_true); |
| 535 |
| 536 // Save a copy of the value if it may be needed and isn't already saved. |
| 537 switch (context) { |
| 538 case Expression::kUninitialized: |
| 539 case Expression::kEffect: |
| 540 case Expression::kValue: |
| 541 UNREACHABLE(); |
| 542 case Expression::kTest: |
| 543 break; |
| 544 case Expression::kValueTest: |
| 545 switch (location_) { |
| 546 case kAccumulator: |
| 547 __ push(result_register()); |
| 548 break; |
| 549 case kStack: |
| 550 break; |
| 551 } |
| 552 break; |
| 553 case Expression::kTestValue: |
| 554 switch (location_) { |
| 555 case kAccumulator: |
| 556 __ push(result_register()); |
| 557 break; |
| 558 case kStack: |
| 559 break; |
| 560 } |
| 561 break; |
| 562 } |
| 563 |
| 564 // Call the ToBoolean stub for all other cases. |
| 565 ToBooleanStub stub; |
| 566 __ push(result_register()); |
| 567 __ CallStub(&stub); |
| 568 __ testq(rax, rax); |
| 569 |
| 570 // The stub returns nonzero for true. Complete based on the context. |
| 571 switch (context) { |
| 572 case Expression::kUninitialized: |
| 573 case Expression::kEffect: |
| 574 case Expression::kValue: |
| 575 UNREACHABLE(); |
| 576 |
| 577 case Expression::kTest: |
| 578 __ j(not_zero, true_label_); |
| 579 __ jmp(false_label_); |
| 580 break; |
| 581 |
| 582 case Expression::kValueTest: |
| 583 switch (location_) { |
| 584 case kAccumulator: |
| 585 __ j(zero, &discard); |
| 586 __ pop(result_register()); |
| 587 __ jmp(true_label_); |
| 588 break; |
| 589 case kStack: |
| 590 __ j(not_zero, true_label_); |
| 591 break; |
| 592 } |
| 305 __ bind(&discard); | 593 __ bind(&discard); |
| 306 __ Drop(1); | 594 __ Drop(1); |
| 307 __ jmp(false_label_); | 595 __ jmp(false_label_); |
| 308 break; | 596 break; |
| 309 } | 597 |
| 310 case Expression::kTestValue: { | 598 case Expression::kTestValue: |
| 311 Label discard; | 599 switch (location_) { |
| 312 if (count > 1) __ Drop(count - 1); | 600 case kAccumulator: |
| 313 __ movq(Operand(rsp, 0), reg); | 601 __ j(not_zero, &discard); |
| 314 TestAndBranch(reg, &discard, false_label_); | 602 __ pop(result_register()); |
| 603 __ jmp(false_label_); |
| 604 break; |
| 605 case kStack: |
| 606 __ j(zero, false_label_); |
| 607 break; |
| 608 } |
| 315 __ bind(&discard); | 609 __ bind(&discard); |
| 316 __ Drop(1); | 610 __ Drop(1); |
| 317 __ jmp(true_label_); | 611 __ jmp(true_label_); |
| 318 break; | 612 break; |
| 319 } | |
| 320 } | 613 } |
| 321 } | 614 } |
| 322 | 615 |
| 323 | 616 |
| 324 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 617 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
| 325 switch (slot->type()) { | 618 switch (slot->type()) { |
| 326 case Slot::PARAMETER: | 619 case Slot::PARAMETER: |
| 327 case Slot::LOCAL: | 620 case Slot::LOCAL: |
| 328 return Operand(rbp, SlotOffset(slot)); | 621 return Operand(rbp, SlotOffset(slot)); |
| 329 case Slot::CONTEXT: { | 622 case Slot::CONTEXT: { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 355 MemOperand location = EmitSlotSearch(dst, scratch1); | 648 MemOperand location = EmitSlotSearch(dst, scratch1); |
| 356 __ movq(location, src); | 649 __ movq(location, src); |
| 357 // Emit the write barrier code if the location is in the heap. | 650 // Emit the write barrier code if the location is in the heap. |
| 358 if (dst->type() == Slot::CONTEXT) { | 651 if (dst->type() == Slot::CONTEXT) { |
| 359 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 652 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
| 360 __ RecordWrite(scratch1, offset, src, scratch2); | 653 __ RecordWrite(scratch1, offset, src, scratch2); |
| 361 } | 654 } |
| 362 } | 655 } |
| 363 | 656 |
| 364 | 657 |
| 365 void FastCodeGenerator::TestAndBranch(Register source, | |
| 366 Label* true_label, | |
| 367 Label* false_label) { | |
| 368 ASSERT_NE(NULL, true_label); | |
| 369 ASSERT_NE(NULL, false_label); | |
| 370 // Use the shared ToBoolean stub to compile the value in the register into | |
| 371 // control flow to the code generator's true and false labels. Perform | |
| 372 // the fast checks assumed by the stub. | |
| 373 | |
| 374 // The undefined value is false. | |
| 375 __ CompareRoot(source, Heap::kUndefinedValueRootIndex); | |
| 376 __ j(equal, false_label); | |
| 377 __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true. | |
| 378 __ j(equal, true_label); | |
| 379 __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false. | |
| 380 __ j(equal, false_label); | |
| 381 ASSERT_EQ(0, kSmiTag); | |
| 382 __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false. | |
| 383 __ j(equal, false_label); | |
| 384 Condition is_smi = masm_->CheckSmi(source); // All other smis are true. | |
| 385 __ j(is_smi, true_label); | |
| 386 | |
| 387 // Call the stub for all other cases. | |
| 388 __ push(source); | |
| 389 ToBooleanStub stub; | |
| 390 __ CallStub(&stub); | |
| 391 __ testq(rax, rax); // The stub returns nonzero for true. | |
| 392 __ j(not_zero, true_label); | |
| 393 __ jmp(false_label); | |
| 394 } | |
| 395 | |
| 396 | |
| 397 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | 658 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 398 Comment cmnt(masm_, "[ Declaration"); | 659 Comment cmnt(masm_, "[ Declaration"); |
| 399 Variable* var = decl->proxy()->var(); | 660 Variable* var = decl->proxy()->var(); |
| 400 ASSERT(var != NULL); // Must have been resolved. | 661 ASSERT(var != NULL); // Must have been resolved. |
| 401 Slot* slot = var->slot(); | 662 Slot* slot = var->slot(); |
| 402 Property* prop = var->AsProperty(); | 663 Property* prop = var->AsProperty(); |
| 403 | 664 |
| 404 if (slot != NULL) { | 665 if (slot != NULL) { |
| 405 switch (slot->type()) { | 666 switch (slot->type()) { |
| 406 case Slot::PARAMETER: | 667 case Slot::PARAMETER: |
| 407 case Slot::LOCAL: | 668 case Slot::LOCAL: |
| 408 if (decl->mode() == Variable::CONST) { | 669 if (decl->mode() == Variable::CONST) { |
| 409 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 670 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 410 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); | 671 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); |
| 411 } else if (decl->fun() != NULL) { | 672 } else if (decl->fun() != NULL) { |
| 412 Visit(decl->fun()); | 673 VisitForValue(decl->fun(), kAccumulator); |
| 413 __ pop(Operand(rbp, SlotOffset(slot))); | 674 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
| 414 } | 675 } |
| 415 break; | 676 break; |
| 416 | 677 |
| 417 case Slot::CONTEXT: | 678 case Slot::CONTEXT: |
| 418 // We bypass the general EmitSlotSearch because we know more about | 679 // We bypass the general EmitSlotSearch because we know more about |
| 419 // this specific context. | 680 // this specific context. |
| 420 | 681 |
| 421 // The variable in the decl always resides in the current context. | 682 // The variable in the decl always resides in the current context. |
| 422 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 683 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
| 423 if (FLAG_debug_code) { | 684 if (FLAG_debug_code) { |
| 424 // Check if we have the correct context pointer. | 685 // Check if we have the correct context pointer. |
| 425 __ movq(rbx, | 686 __ movq(rbx, |
| 426 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); | 687 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
| 427 __ cmpq(rbx, rsi); | 688 __ cmpq(rbx, rsi); |
| 428 __ Check(equal, "Unexpected declaration in current context."); | 689 __ Check(equal, "Unexpected declaration in current context."); |
| 429 } | 690 } |
| 430 if (decl->mode() == Variable::CONST) { | 691 if (decl->mode() == Variable::CONST) { |
| 431 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 692 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 432 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), | 693 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), |
| 433 kScratchRegister); | 694 kScratchRegister); |
| 434 // No write barrier since the hole value is in old space. | 695 // No write barrier since the hole value is in old space. |
| 435 } else if (decl->fun() != NULL) { | 696 } else if (decl->fun() != NULL) { |
| 436 Visit(decl->fun()); | 697 VisitForValue(decl->fun(), kAccumulator); |
| 437 __ pop(rax); | 698 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), |
| 438 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); | 699 result_register()); |
| 439 int offset = Context::SlotOffset(slot->index()); | 700 int offset = Context::SlotOffset(slot->index()); |
| 440 __ RecordWrite(rsi, offset, rax, rcx); | 701 __ RecordWrite(rsi, offset, result_register(), rcx); |
| 441 } | 702 } |
| 442 break; | 703 break; |
| 443 | 704 |
| 444 case Slot::LOOKUP: { | 705 case Slot::LOOKUP: { |
| 445 __ push(rsi); | 706 __ push(rsi); |
| 446 __ Push(var->name()); | 707 __ Push(var->name()); |
| 447 // Declaration nodes are always introduced in one of two modes. | 708 // Declaration nodes are always introduced in one of two modes. |
| 448 ASSERT(decl->mode() == Variable::VAR || | 709 ASSERT(decl->mode() == Variable::VAR || |
| 449 decl->mode() == Variable::CONST); | 710 decl->mode() == Variable::CONST); |
| 450 PropertyAttributes attr = | 711 PropertyAttributes attr = |
| 451 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; | 712 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; |
| 452 __ Push(Smi::FromInt(attr)); | 713 __ Push(Smi::FromInt(attr)); |
| 453 // Push initial value, if any. | 714 // Push initial value, if any. |
| 454 // Note: For variables we must not push an initial value (such as | 715 // Note: For variables we must not push an initial value (such as |
| 455 // 'undefined') because we may have a (legal) redeclaration and we | 716 // 'undefined') because we may have a (legal) redeclaration and we |
| 456 // must not destroy the current value. | 717 // must not destroy the current value. |
| 457 if (decl->mode() == Variable::CONST) { | 718 if (decl->mode() == Variable::CONST) { |
| 458 __ PushRoot(Heap::kTheHoleValueRootIndex); | 719 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 459 } else if (decl->fun() != NULL) { | 720 } else if (decl->fun() != NULL) { |
| 460 Visit(decl->fun()); | 721 VisitForValue(decl->fun(), kStack); |
| 461 } else { | 722 } else { |
| 462 __ Push(Smi::FromInt(0)); // no initial value! | 723 __ Push(Smi::FromInt(0)); // no initial value! |
| 463 } | 724 } |
| 464 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 725 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 465 break; | 726 break; |
| 466 } | 727 } |
| 467 } | 728 } |
| 468 | 729 |
| 469 } else if (prop != NULL) { | 730 } else if (prop != NULL) { |
| 470 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 731 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
| 471 // We are declaring a function or constant that rewrites to a | 732 // We are declaring a function or constant that rewrites to a |
| 472 // property. Use (keyed) IC to set the initial value. | 733 // property. Use (keyed) IC to set the initial value. |
| 473 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | 734 VisitForValue(prop->obj(), kStack); |
| 474 Visit(prop->obj()); | 735 VisitForValue(prop->key(), kStack); |
| 475 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
| 476 Visit(prop->key()); | |
| 477 | 736 |
| 478 if (decl->fun() != NULL) { | 737 if (decl->fun() != NULL) { |
| 479 ASSERT_EQ(Expression::kValue, decl->fun()->context()); | 738 VisitForValue(decl->fun(), kAccumulator); |
| 480 Visit(decl->fun()); | |
| 481 __ pop(rax); | |
| 482 } else { | 739 } else { |
| 483 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | 740 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); |
| 484 } | 741 } |
| 485 | 742 |
| 486 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 743 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 487 __ call(ic, RelocInfo::CODE_TARGET); | 744 __ call(ic, RelocInfo::CODE_TARGET); |
| 488 | |
| 489 // Absence of a test rax instruction following the call | 745 // Absence of a test rax instruction following the call |
| 490 // indicates that none of the load was inlined. | 746 // indicates that none of the load was inlined. |
| 747 __ nop(); |
| 491 | 748 |
| 492 // Value in rax is ignored (declarations are statements). Receiver | 749 // Value in rax is ignored (declarations are statements). Receiver |
| 493 // and key on stack are discarded. | 750 // and key on stack are discarded. |
| 494 __ Drop(2); | 751 __ Drop(2); |
| 495 } | 752 } |
| 496 } | 753 } |
| 497 } | 754 } |
| 498 | 755 |
| 499 | 756 |
| 500 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 757 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 525 } | 782 } |
| 526 | 783 |
| 527 | 784 |
| 528 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 785 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 529 Comment cmnt(masm_, "[ VariableProxy"); | 786 Comment cmnt(masm_, "[ VariableProxy"); |
| 530 EmitVariableLoad(expr->var(), expr->context()); | 787 EmitVariableLoad(expr->var(), expr->context()); |
| 531 } | 788 } |
| 532 | 789 |
| 533 | 790 |
| 534 void FastCodeGenerator::EmitVariableLoad(Variable* var, | 791 void FastCodeGenerator::EmitVariableLoad(Variable* var, |
| 535 Expression::Context context) { | 792 Expression::Context context) { |
| 536 Expression* rewrite = var->rewrite(); | 793 Expression* rewrite = var->rewrite(); |
| 537 if (rewrite == NULL) { | 794 if (rewrite == NULL) { |
| 538 ASSERT(var->is_global()); | 795 ASSERT(var->is_global()); |
| 539 Comment cmnt(masm_, "Global variable"); | 796 Comment cmnt(masm_, "Global variable"); |
| 540 // Use inline caching. Variable name is passed in rcx and the global | 797 // Use inline caching. Variable name is passed in rcx and the global |
| 541 // object on the stack. | 798 // object on the stack. |
| 542 __ push(CodeGenerator::GlobalObject()); | 799 __ push(CodeGenerator::GlobalObject()); |
| 543 __ Move(rcx, var->name()); | 800 __ Move(rcx, var->name()); |
| 544 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 801 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 545 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 802 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 546 // A test rax instruction following the call is used by the IC to | 803 // A test rax instruction following the call is used by the IC to |
| 547 // indicate that the inobject property case was inlined. Ensure there | 804 // indicate that the inobject property case was inlined. Ensure there |
| 548 // is no test rax instruction here. | 805 // is no test rax instruction here. |
| 549 __ nop(); | 806 __ nop(); |
| 550 | |
| 551 DropAndApply(1, context, rax); | 807 DropAndApply(1, context, rax); |
| 552 } else if (rewrite->AsSlot() != NULL) { | 808 } else if (rewrite->AsSlot() != NULL) { |
| 553 Slot* slot = rewrite->AsSlot(); | 809 Slot* slot = rewrite->AsSlot(); |
| 554 if (FLAG_debug_code) { | 810 if (FLAG_debug_code) { |
| 555 switch (slot->type()) { | 811 switch (slot->type()) { |
| 556 case Slot::LOCAL: | 812 case Slot::PARAMETER: |
| 557 case Slot::PARAMETER: { | 813 case Slot::LOCAL: { |
| 558 Comment cmnt(masm_, "Stack slot"); | 814 Comment cmnt(masm_, "Stack slot"); |
| 559 break; | 815 break; |
| 560 } | 816 } |
| 561 case Slot::CONTEXT: { | 817 case Slot::CONTEXT: { |
| 562 Comment cmnt(masm_, "Context slot"); | 818 Comment cmnt(masm_, "Context slot"); |
| 563 break; | 819 break; |
| 564 } | 820 } |
| 565 case Slot::LOOKUP: | 821 case Slot::LOOKUP: |
| 566 UNIMPLEMENTED(); | 822 UNIMPLEMENTED(); |
| 567 break; | 823 break; |
| 568 } | 824 } |
| 569 } | 825 } |
| 570 Apply(context, slot, rax); | 826 Apply(context, slot); |
| 571 } else { | 827 } else { |
| 572 Comment cmnt(masm_, "Variable rewritten to property"); | 828 Comment cmnt(masm_, "Variable rewritten to property"); |
| 573 // A variable has been rewritten into an explicit access to an object | 829 // A variable has been rewritten into an explicit access to an object |
| 574 // property. | 830 // property. |
| 575 Property* property = rewrite->AsProperty(); | 831 Property* property = rewrite->AsProperty(); |
| 576 ASSERT_NOT_NULL(property); | 832 ASSERT_NOT_NULL(property); |
| 577 | 833 |
| 578 // The only property expressions that can occur are of the form | 834 // The only property expressions that can occur are of the form |
| 579 // "slot[literal]". | 835 // "slot[literal]". |
| 580 | 836 |
| 581 // Assert that the object is in a slot. | 837 // Assert that the object is in a slot. |
| 582 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); | 838 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 583 ASSERT_NOT_NULL(object); | 839 ASSERT_NOT_NULL(object_var); |
| 584 Slot* object_slot = object->slot(); | 840 Slot* object_slot = object_var->slot(); |
| 585 ASSERT_NOT_NULL(object_slot); | 841 ASSERT_NOT_NULL(object_slot); |
| 586 | 842 |
| 587 // Load the object. | 843 // Load the object. |
| 588 MemOperand object_loc = EmitSlotSearch(object_slot, rax); | 844 MemOperand object_loc = EmitSlotSearch(object_slot, rax); |
| 589 __ push(object_loc); | 845 __ push(object_loc); |
| 590 | 846 |
| 591 // Assert that the key is a smi. | 847 // Assert that the key is a smi. |
| 592 Literal* key_literal = property->key()->AsLiteral(); | 848 Literal* key_literal = property->key()->AsLiteral(); |
| 593 ASSERT_NOT_NULL(key_literal); | 849 ASSERT_NOT_NULL(key_literal); |
| 594 ASSERT(key_literal->handle()->IsSmi()); | 850 ASSERT(key_literal->handle()->IsSmi()); |
| 595 | 851 |
| 596 // Load the key. | 852 // Load the key. |
| 597 __ Push(key_literal->handle()); | 853 __ Push(key_literal->handle()); |
| 598 | 854 |
| 599 // Do a keyed property load. | 855 // Do a keyed property load. |
| 600 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 856 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 601 __ call(ic, RelocInfo::CODE_TARGET); | 857 __ call(ic, RelocInfo::CODE_TARGET); |
| 602 // Notice: We must not have a "test rax, ..." instruction after the | 858 // Notice: We must not have a "test rax, ..." instruction after the |
| 603 // call. It is treated specially by the LoadIC code. | 859 // call. It is treated specially by the LoadIC code. |
| 604 | 860 __ nop(); |
| 605 // Drop key and object left on the stack by IC, and push the result. | 861 // Drop key and object left on the stack by IC, and push the result. |
| 606 DropAndApply(2, context, rax); | 862 DropAndApply(2, context, rax); |
| 607 } | 863 } |
| 608 } | 864 } |
| 609 | 865 |
| 610 | 866 |
| 611 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 867 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 612 Comment cmnt(masm_, "[ RegExpLiteral"); | 868 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 613 Label done; | 869 Label done; |
| 614 // Registers will be used as follows: | 870 // Registers will be used as follows: |
| 615 // rdi = JS function. | 871 // rdi = JS function. |
| 616 // rbx = literals array. | 872 // rbx = literals array. |
| 617 // rax = regexp literal. | 873 // rax = regexp literal. |
| 618 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 874 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 619 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 875 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 620 int literal_offset = | 876 int literal_offset = |
| 621 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 877 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 622 __ movq(rax, FieldOperand(rbx, literal_offset)); | 878 __ movq(rax, FieldOperand(rbx, literal_offset)); |
| 623 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 879 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 624 __ j(not_equal, &done); | 880 __ j(not_equal, &done); |
| 625 // Create regexp literal using runtime function | 881 // Create regexp literal using runtime function |
| 626 // Result will be in rax. | 882 // Result will be in rax. |
| 627 __ push(rbx); | 883 __ push(rbx); |
| 628 __ Push(Smi::FromInt(expr->literal_index())); | 884 __ Push(Smi::FromInt(expr->literal_index())); |
| 629 __ Push(expr->pattern()); | 885 __ Push(expr->pattern()); |
| 630 __ Push(expr->flags()); | 886 __ Push(expr->flags()); |
| 631 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 887 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 632 // Label done: | |
| 633 __ bind(&done); | 888 __ bind(&done); |
| 634 Apply(expr->context(), rax); | 889 Apply(expr->context(), rax); |
| 635 } | 890 } |
| 636 | 891 |
| 637 | 892 |
| 638 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 893 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 639 Comment cmnt(masm_, "[ ObjectLiteral"); | 894 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 640 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 895 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 641 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 896 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 642 __ Push(Smi::FromInt(expr->literal_index())); | 897 __ Push(Smi::FromInt(expr->literal_index())); |
| 643 __ Push(expr->constant_properties()); | 898 __ Push(expr->constant_properties()); |
| 644 if (expr->depth() > 1) { | 899 if (expr->depth() > 1) { |
| 645 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); | 900 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); |
| 646 } else { | 901 } else { |
| 647 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 902 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
| 648 } | 903 } |
| 649 | 904 |
| 650 // If result_saved == true: The result is saved on top of the | 905 // If result_saved is true the result is on top of the stack. If |
| 651 // stack and in rax. | 906 // result_saved is false the result is in rax. |
| 652 // If result_saved == false: The result not on the stack, just in rax. | |
| 653 bool result_saved = false; | 907 bool result_saved = false; |
| 654 | 908 |
| 655 for (int i = 0; i < expr->properties()->length(); i++) { | 909 for (int i = 0; i < expr->properties()->length(); i++) { |
| 656 ObjectLiteral::Property* property = expr->properties()->at(i); | 910 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 657 if (property->IsCompileTimeValue()) continue; | 911 if (property->IsCompileTimeValue()) continue; |
| 658 | 912 |
| 659 Literal* key = property->key(); | 913 Literal* key = property->key(); |
| 660 Expression* value = property->value(); | 914 Expression* value = property->value(); |
| 661 if (!result_saved) { | 915 if (!result_saved) { |
| 662 __ push(rax); // Save result on the stack | 916 __ push(rax); // Save result on the stack |
| 663 result_saved = true; | 917 result_saved = true; |
| 664 } | 918 } |
| 665 switch (property->kind()) { | 919 switch (property->kind()) { |
| 920 case ObjectLiteral::Property::CONSTANT: |
| 921 UNREACHABLE(); |
| 666 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 922 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 667 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 923 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 924 // Fall through. |
| 668 case ObjectLiteral::Property::COMPUTED: | 925 case ObjectLiteral::Property::COMPUTED: |
| 669 if (key->handle()->IsSymbol()) { | 926 if (key->handle()->IsSymbol()) { |
| 670 Visit(value); | 927 VisitForValue(value, kAccumulator); |
| 671 ASSERT_EQ(Expression::kValue, value->context()); | |
| 672 __ pop(rax); | |
| 673 __ Move(rcx, key->handle()); | 928 __ Move(rcx, key->handle()); |
| 674 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 929 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 675 __ call(ic, RelocInfo::CODE_TARGET); | 930 __ call(ic, RelocInfo::CODE_TARGET); |
| 931 __ nop(); |
| 676 // StoreIC leaves the receiver on the stack. | 932 // StoreIC leaves the receiver on the stack. |
| 677 __ movq(rax, Operand(rsp, 0)); // Restore result back into rax. | |
| 678 break; | 933 break; |
| 679 } | 934 } |
| 680 // Fall through. | 935 // Fall through. |
| 681 case ObjectLiteral::Property::PROTOTYPE: | 936 case ObjectLiteral::Property::PROTOTYPE: |
| 682 __ push(rax); | 937 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 683 Visit(key); | 938 VisitForValue(key, kStack); |
| 684 ASSERT_EQ(Expression::kValue, key->context()); | 939 VisitForValue(value, kStack); |
| 685 Visit(value); | |
| 686 ASSERT_EQ(Expression::kValue, value->context()); | |
| 687 __ CallRuntime(Runtime::kSetProperty, 3); | 940 __ CallRuntime(Runtime::kSetProperty, 3); |
| 688 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | |
| 689 break; | 941 break; |
| 690 case ObjectLiteral::Property::SETTER: | 942 case ObjectLiteral::Property::SETTER: |
| 691 case ObjectLiteral::Property::GETTER: | 943 case ObjectLiteral::Property::GETTER: |
| 692 __ push(rax); | 944 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 693 Visit(key); | 945 VisitForValue(key, kStack); |
| 694 ASSERT_EQ(Expression::kValue, key->context()); | |
| 695 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 946 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
| 696 Smi::FromInt(1) : | 947 Smi::FromInt(1) : |
| 697 Smi::FromInt(0)); | 948 Smi::FromInt(0)); |
| 698 Visit(value); | 949 VisitForValue(value, kStack); |
| 699 ASSERT_EQ(Expression::kValue, value->context()); | |
| 700 __ CallRuntime(Runtime::kDefineAccessor, 4); | 950 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 701 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | |
| 702 break; | 951 break; |
| 703 default: UNREACHABLE(); | |
| 704 } | 952 } |
| 705 } | 953 } |
| 706 switch (expr->context()) { | 954 |
| 707 case Expression::kUninitialized: | 955 if (result_saved) { |
| 708 UNREACHABLE(); | 956 ApplyTOS(expr->context()); |
| 709 case Expression::kEffect: | 957 } else { |
| 710 if (result_saved) __ Drop(1); | 958 Apply(expr->context(), rax); |
| 711 break; | |
| 712 case Expression::kValue: | |
| 713 if (!result_saved) __ push(rax); | |
| 714 break; | |
| 715 case Expression::kTest: | |
| 716 if (result_saved) __ pop(rax); | |
| 717 TestAndBranch(rax, true_label_, false_label_); | |
| 718 break; | |
| 719 case Expression::kValueTest: { | |
| 720 Label discard; | |
| 721 if (!result_saved) __ push(rax); | |
| 722 TestAndBranch(rax, true_label_, &discard); | |
| 723 __ bind(&discard); | |
| 724 __ Drop(1); | |
| 725 __ jmp(false_label_); | |
| 726 break; | |
| 727 } | |
| 728 case Expression::kTestValue: { | |
| 729 Label discard; | |
| 730 if (!result_saved) __ push(rax); | |
| 731 TestAndBranch(rax, &discard, false_label_); | |
| 732 __ bind(&discard); | |
| 733 __ Drop(1); | |
| 734 __ jmp(true_label_); | |
| 735 break; | |
| 736 } | |
| 737 } | 959 } |
| 738 } | 960 } |
| 739 | 961 |
| 740 | 962 |
| 741 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 963 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 742 Comment cmnt(masm_, "[ ArrayLiteral"); | 964 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 743 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 965 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 744 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 966 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
| 745 __ Push(Smi::FromInt(expr->literal_index())); | 967 __ Push(Smi::FromInt(expr->literal_index())); |
| 746 __ Push(expr->constant_elements()); | 968 __ Push(expr->constant_elements()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 761 // is already set in the cloned array. | 983 // is already set in the cloned array. |
| 762 if (subexpr->AsLiteral() != NULL || | 984 if (subexpr->AsLiteral() != NULL || |
| 763 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 985 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 764 continue; | 986 continue; |
| 765 } | 987 } |
| 766 | 988 |
| 767 if (!result_saved) { | 989 if (!result_saved) { |
| 768 __ push(rax); | 990 __ push(rax); |
| 769 result_saved = true; | 991 result_saved = true; |
| 770 } | 992 } |
| 771 Visit(subexpr); | 993 VisitForValue(subexpr, kAccumulator); |
| 772 ASSERT_EQ(Expression::kValue, subexpr->context()); | |
| 773 | 994 |
| 774 // Store the subexpression value in the array's elements. | 995 // Store the subexpression value in the array's elements. |
| 775 __ pop(rax); // Subexpression value. | |
| 776 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 996 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
| 777 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 997 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 778 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 998 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 779 __ movq(FieldOperand(rbx, offset), rax); | 999 __ movq(FieldOperand(rbx, offset), result_register()); |
| 780 | 1000 |
| 781 // Update the write barrier for the array store. | 1001 // Update the write barrier for the array store. |
| 782 __ RecordWrite(rbx, offset, rax, rcx); | 1002 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 783 } | 1003 } |
| 784 | 1004 |
| 785 switch (expr->context()) { | 1005 if (result_saved) { |
| 786 case Expression::kUninitialized: | 1006 ApplyTOS(expr->context()); |
| 787 UNREACHABLE(); | 1007 } else { |
| 788 case Expression::kEffect: | 1008 Apply(expr->context(), rax); |
| 789 if (result_saved) __ Drop(1); | |
| 790 break; | |
| 791 case Expression::kValue: | |
| 792 if (!result_saved) __ push(rax); | |
| 793 break; | |
| 794 case Expression::kTest: | |
| 795 if (result_saved) __ pop(rax); | |
| 796 TestAndBranch(rax, true_label_, false_label_); | |
| 797 break; | |
| 798 case Expression::kValueTest: { | |
| 799 Label discard; | |
| 800 if (!result_saved) __ push(rax); | |
| 801 TestAndBranch(rax, true_label_, &discard); | |
| 802 __ bind(&discard); | |
| 803 __ Drop(1); | |
| 804 __ jmp(false_label_); | |
| 805 break; | |
| 806 } | |
| 807 case Expression::kTestValue: { | |
| 808 Label discard; | |
| 809 if (!result_saved) __ push(rax); | |
| 810 TestAndBranch(rax, &discard, false_label_); | |
| 811 __ bind(&discard); | |
| 812 __ Drop(1); | |
| 813 __ jmp(true_label_); | |
| 814 break; | |
| 815 } | |
| 816 } | 1009 } |
| 817 } | 1010 } |
| 818 | 1011 |
| 819 | 1012 |
| 820 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, | 1013 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 821 Expression::Context context) { | |
| 822 SetSourcePosition(prop->position()); | 1014 SetSourcePosition(prop->position()); |
| 823 Literal* key = prop->key()->AsLiteral(); | 1015 Literal* key = prop->key()->AsLiteral(); |
| 824 __ Move(rcx, key->handle()); | 1016 __ Move(rcx, key->handle()); |
| 825 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1017 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 826 __ Call(ic, RelocInfo::CODE_TARGET); | 1018 __ Call(ic, RelocInfo::CODE_TARGET); |
| 827 Apply(context, rax); | 1019 __ nop(); |
| 828 } | 1020 } |
| 829 | 1021 |
| 830 | 1022 |
| 831 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, | 1023 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 832 Expression::Context context) { | |
| 833 SetSourcePosition(prop->position()); | 1024 SetSourcePosition(prop->position()); |
| 834 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1025 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 835 __ Call(ic, RelocInfo::CODE_TARGET); | 1026 __ Call(ic, RelocInfo::CODE_TARGET); |
| 836 Apply(context, rax); | 1027 __ nop(); |
| 837 } | 1028 } |
| 838 | 1029 |
| 839 | 1030 |
| 840 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 1031 void FastCodeGenerator::EmitBinaryOp(Token::Value op, |
| 841 Expression::Context context) { | 1032 Expression::Context context) { |
| 1033 __ push(result_register()); |
| 842 GenericBinaryOpStub stub(op, | 1034 GenericBinaryOpStub stub(op, |
| 843 NO_OVERWRITE, | 1035 NO_OVERWRITE, |
| 844 NO_GENERIC_BINARY_FLAGS); | 1036 NO_GENERIC_BINARY_FLAGS); |
| 845 __ CallStub(&stub); | 1037 __ CallStub(&stub); |
| 846 Apply(context, rax); | 1038 Apply(context, rax); |
| 847 } | 1039 } |
| 848 | 1040 |
| 849 | 1041 |
| 850 void FastCodeGenerator::EmitVariableAssignment(Variable* var, | 1042 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
| 851 Expression::Context context) { | 1043 Expression::Context context) { |
| 852 ASSERT(var != NULL); | 1044 ASSERT(var != NULL); |
| 853 ASSERT(var->is_global() || var->slot() != NULL); | 1045 ASSERT(var->is_global() || var->slot() != NULL); |
| 854 if (var->is_global()) { | 1046 if (var->is_global()) { |
| 855 // Assignment to a global variable. Use inline caching for the | 1047 // Assignment to a global variable. Use inline caching for the |
| 856 // assignment. Right-hand-side value is passed in rax, variable name in | 1048 // assignment. Right-hand-side value is passed in rax, variable name in |
| 857 // rcx, and the global object on the stack. | 1049 // rcx, and the global object on the stack. |
| 858 __ pop(rax); | |
| 859 __ Move(rcx, var->name()); | 1050 __ Move(rcx, var->name()); |
| 860 __ push(CodeGenerator::GlobalObject()); | 1051 __ push(CodeGenerator::GlobalObject()); |
| 861 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1052 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 862 __ Call(ic, RelocInfo::CODE_TARGET); | 1053 __ Call(ic, RelocInfo::CODE_TARGET); |
| 863 // Overwrite the global object on the stack with the result if needed. | 1054 // Overwrite the global object on the stack with the result if needed. |
| 864 DropAndApply(1, context, rax); | 1055 DropAndApply(1, context, rax); |
| 865 | 1056 |
| 866 } else if (var->slot() != NULL) { | 1057 } else if (var->slot() != NULL) { |
| 867 Slot* slot = var->slot(); | 1058 Slot* slot = var->slot(); |
| 868 switch (slot->type()) { | 1059 switch (slot->type()) { |
| 869 case Slot::LOCAL: | 1060 case Slot::LOCAL: |
| 870 case Slot::PARAMETER: { | 1061 case Slot::PARAMETER: |
| 871 Operand target = Operand(rbp, SlotOffset(slot)); | 1062 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
| 872 switch (context) { | 1063 break; |
| 873 case Expression::kUninitialized: | 1064 |
| 874 UNREACHABLE(); | 1065 case Slot::CONTEXT: { |
| 875 case Expression::kEffect: | 1066 MemOperand target = EmitSlotSearch(slot, rcx); |
| 876 // Perform assignment and discard value. | 1067 __ movq(target, result_register()); |
| 877 __ pop(target); | 1068 |
| 878 break; | 1069 // RecordWrite may destroy all its register arguments. |
| 879 case Expression::kValue: | 1070 __ movq(rdx, result_register()); |
| 880 // Perform assignment and preserve value. | 1071 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 881 __ movq(rax, Operand(rsp, 0)); | 1072 __ RecordWrite(rcx, offset, rdx, rbx); |
| 882 __ movq(target, rax); | |
| 883 break; | |
| 884 case Expression::kTest: | |
| 885 // Perform assignment and test (and discard) value. | |
| 886 __ pop(rax); | |
| 887 __ movq(target, rax); | |
| 888 TestAndBranch(rax, true_label_, false_label_); | |
| 889 break; | |
| 890 case Expression::kValueTest: { | |
| 891 Label discard; | |
| 892 __ movq(rax, Operand(rsp, 0)); | |
| 893 __ movq(target, rax); | |
| 894 TestAndBranch(rax, true_label_, &discard); | |
| 895 __ bind(&discard); | |
| 896 __ Drop(1); | |
| 897 __ jmp(false_label_); | |
| 898 break; | |
| 899 } | |
| 900 case Expression::kTestValue: { | |
| 901 Label discard; | |
| 902 __ movq(rax, Operand(rsp, 0)); | |
| 903 __ movq(target, rax); | |
| 904 TestAndBranch(rax, &discard, false_label_); | |
| 905 __ bind(&discard); | |
| 906 __ Drop(1); | |
| 907 __ jmp(true_label_); | |
| 908 break; | |
| 909 } | |
| 910 } | |
| 911 break; | 1073 break; |
| 912 } | 1074 } |
| 913 | 1075 |
| 914 case Slot::CONTEXT: { | |
| 915 MemOperand target = EmitSlotSearch(slot, rcx); | |
| 916 __ pop(rax); | |
| 917 __ movq(target, rax); | |
| 918 | |
| 919 // RecordWrite may destroy all its register arguments. | |
| 920 if (context == Expression::kValue) { | |
| 921 __ push(rax); | |
| 922 } else if (context != Expression::kEffect) { | |
| 923 __ movq(rdx, rax); | |
| 924 } | |
| 925 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
| 926 __ RecordWrite(rcx, offset, rax, rbx); | |
| 927 if (context != Expression::kEffect && context != Expression::kValue) { | |
| 928 Apply(context, rdx); | |
| 929 } | |
| 930 break; | |
| 931 } | |
| 932 | |
| 933 case Slot::LOOKUP: | 1076 case Slot::LOOKUP: |
| 934 UNREACHABLE(); | 1077 UNREACHABLE(); |
| 935 break; | 1078 break; |
| 936 } | 1079 } |
| 1080 Apply(context, result_register()); |
| 937 } else { | 1081 } else { |
| 938 // Variables rewritten as properties are not treated as variables in | 1082 // Variables rewritten as properties are not treated as variables in |
| 939 // assignments. | 1083 // assignments. |
| 940 UNREACHABLE(); | 1084 UNREACHABLE(); |
| 941 } | 1085 } |
| 942 } | 1086 } |
| 943 | 1087 |
| 944 | 1088 |
| 945 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1089 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 946 // Assignment to a property, using a named store IC. | 1090 // Assignment to a property, using a named store IC. |
| 947 Property* prop = expr->target()->AsProperty(); | 1091 Property* prop = expr->target()->AsProperty(); |
| 948 ASSERT(prop != NULL); | 1092 ASSERT(prop != NULL); |
| 949 ASSERT(prop->key()->AsLiteral() != NULL); | 1093 ASSERT(prop->key()->AsLiteral() != NULL); |
| 950 | 1094 |
| 951 // If the assignment starts a block of assignments to the same object, | 1095 // If the assignment starts a block of assignments to the same object, |
| 952 // change to slow case to avoid the quadratic behavior of repeatedly | 1096 // change to slow case to avoid the quadratic behavior of repeatedly |
| 953 // adding fast properties. | 1097 // adding fast properties. |
| 954 if (expr->starts_initialization_block()) { | 1098 if (expr->starts_initialization_block()) { |
| 955 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1099 __ push(result_register()); |
| 1100 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. |
| 956 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1101 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1102 __ pop(result_register()); |
| 957 } | 1103 } |
| 958 | 1104 |
| 959 __ pop(rax); | 1105 // Record source code position before IC call. |
| 1106 SetSourcePosition(expr->position()); |
| 960 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1107 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 961 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1108 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 962 __ Call(ic, RelocInfo::CODE_TARGET); | 1109 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1110 __ nop(); |
| 963 | 1111 |
| 964 // If the assignment ends an initialization block, revert to fast case. | 1112 // If the assignment ends an initialization block, revert to fast case. |
| 965 if (expr->ends_initialization_block()) { | 1113 if (expr->ends_initialization_block()) { |
| 966 __ push(rax); // Result of assignment, saved even if not needed. | 1114 __ push(rax); // Result of assignment, saved even if not needed. |
| 967 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1115 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 968 __ CallRuntime(Runtime::kToFastProperties, 1); | 1116 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 969 __ pop(rax); | 1117 __ pop(rax); |
| 970 } | 1118 } |
| 971 | 1119 |
| 972 DropAndApply(1, expr->context(), rax); | 1120 DropAndApply(1, expr->context(), rax); |
| 973 } | 1121 } |
| 974 | 1122 |
| 975 | 1123 |
| 976 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1124 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 977 // Assignment to a property, using a keyed store IC. | 1125 // Assignment to a property, using a keyed store IC. |
| 978 | 1126 |
| 979 // If the assignment starts a block of assignments to the same object, | 1127 // If the assignment starts a block of assignments to the same object, |
| 980 // change to slow case to avoid the quadratic behavior of repeatedly | 1128 // change to slow case to avoid the quadratic behavior of repeatedly |
| 981 // adding fast properties. | 1129 // adding fast properties. |
| 982 if (expr->starts_initialization_block()) { | 1130 if (expr->starts_initialization_block()) { |
| 983 // Reciever is under the key and value. | 1131 __ push(result_register()); |
| 1132 // Receiver is now under the key and value. |
| 984 __ push(Operand(rsp, 2 * kPointerSize)); | 1133 __ push(Operand(rsp, 2 * kPointerSize)); |
| 985 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1134 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1135 __ pop(result_register()); |
| 986 } | 1136 } |
| 987 | 1137 |
| 988 __ pop(rax); | 1138 // Record source code position before IC call. |
| 1139 SetSourcePosition(expr->position()); |
| 989 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1140 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 990 __ Call(ic, RelocInfo::CODE_TARGET); | 1141 __ Call(ic, RelocInfo::CODE_TARGET); |
| 991 // This nop signals to the IC that there is no inlined code at the call | 1142 // This nop signals to the IC that there is no inlined code at the call |
| 992 // site for it to patch. | 1143 // site for it to patch. |
| 993 __ nop(); | 1144 __ nop(); |
| 994 | 1145 |
| 995 // If the assignment ends an initialization block, revert to fast case. | 1146 // If the assignment ends an initialization block, revert to fast case. |
| 996 if (expr->ends_initialization_block()) { | 1147 if (expr->ends_initialization_block()) { |
| 997 __ push(rax); // Result of assignment, saved even if not needed. | 1148 __ push(rax); // Result of assignment, saved even if not needed. |
| 998 // Reciever is under the key and value. | 1149 // Receiver is under the key and value. |
| 999 __ push(Operand(rsp, 2 * kPointerSize)); | 1150 __ push(Operand(rsp, 2 * kPointerSize)); |
| 1000 __ CallRuntime(Runtime::kToFastProperties, 1); | 1151 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1001 __ pop(rax); | 1152 __ pop(rax); |
| 1002 } | 1153 } |
| 1003 | 1154 |
| 1004 // Receiver and key are still on stack. | 1155 // Receiver and key are still on stack. |
| 1005 DropAndApply(2, expr->context(), rax); | 1156 DropAndApply(2, expr->context(), rax); |
| 1006 } | 1157 } |
| 1007 | 1158 |
| 1008 | 1159 |
| 1009 void FastCodeGenerator::VisitProperty(Property* expr) { | 1160 void FastCodeGenerator::VisitProperty(Property* expr) { |
| 1010 Comment cmnt(masm_, "[ Property"); | 1161 Comment cmnt(masm_, "[ Property"); |
| 1011 Expression* key = expr->key(); | 1162 Expression* key = expr->key(); |
| 1012 | 1163 |
| 1013 // Record the source position for the property load. | |
| 1014 SetSourcePosition(expr->position()); | |
| 1015 | |
| 1016 // Evaluate receiver. | 1164 // Evaluate receiver. |
| 1017 Visit(expr->obj()); | 1165 VisitForValue(expr->obj(), kStack); |
| 1018 | 1166 |
| 1019 if (key->IsPropertyName()) { | 1167 if (key->IsPropertyName()) { |
| 1020 // Do a named property load. The IC expects the property name in rcx | 1168 EmitNamedPropertyLoad(expr); |
| 1021 // and the receiver on the stack. | 1169 // Drop receiver left on the stack by IC. |
| 1022 __ Move(rcx, key->AsLiteral()->handle()); | |
| 1023 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
| 1024 __ call(ic, RelocInfo::CODE_TARGET); | |
| 1025 // By emitting a nop we make sure that we do not have a "test rax,..." | |
| 1026 // instruction after the call it is treated specially by the LoadIC code. | |
| 1027 __ nop(); | |
| 1028 DropAndApply(1, expr->context(), rax); | 1170 DropAndApply(1, expr->context(), rax); |
| 1029 } else { | 1171 } else { |
| 1030 // Do a keyed property load. | 1172 VisitForValue(expr->key(), kStack); |
| 1031 Visit(expr->key()); | 1173 EmitKeyedPropertyLoad(expr); |
| 1032 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1033 __ call(ic, RelocInfo::CODE_TARGET); | |
| 1034 // Notice: We must not have a "test rax, ..." instruction after the | |
| 1035 // call. It is treated specially by the LoadIC code. | |
| 1036 __ nop(); | |
| 1037 // Drop key and receiver left on the stack by IC. | 1174 // Drop key and receiver left on the stack by IC. |
| 1038 DropAndApply(2, expr->context(), rax); | 1175 DropAndApply(2, expr->context(), rax); |
| 1039 } | 1176 } |
| 1040 } | 1177 } |
| 1041 | 1178 |
| 1042 | 1179 |
| 1043 void FastCodeGenerator::EmitCallWithIC(Call* expr, | 1180 void FastCodeGenerator::EmitCallWithIC(Call* expr, |
| 1044 Handle<Object> ignored, | 1181 Handle<Object> ignored, |
| 1045 RelocInfo::Mode mode) { | 1182 RelocInfo::Mode mode) { |
| 1046 // Code common for calls using the IC. | 1183 // Code common for calls using the IC. |
| 1047 ZoneList<Expression*>* args = expr->arguments(); | 1184 ZoneList<Expression*>* args = expr->arguments(); |
| 1048 int arg_count = args->length(); | 1185 int arg_count = args->length(); |
| 1049 for (int i = 0; i < arg_count; i++) { | 1186 for (int i = 0; i < arg_count; i++) { |
| 1050 Visit(args->at(i)); | 1187 VisitForValue(args->at(i), kStack); |
| 1051 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
| 1052 } | 1188 } |
| 1053 // Record source position for debugger. | 1189 // Record source position for debugger. |
| 1054 SetSourcePosition(expr->position()); | 1190 SetSourcePosition(expr->position()); |
| 1055 // Call the IC initialization code. | 1191 // Call the IC initialization code. |
| 1192 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1056 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1193 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 1057 NOT_IN_LOOP); | 1194 in_loop); |
| 1058 __ call(ic, mode); | 1195 __ Call(ic, mode); |
| 1059 // Restore context register. | 1196 // Restore context register. |
| 1060 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1197 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1061 // Discard the function left on TOS. | 1198 // Discard the function left on TOS. |
| 1062 DropAndApply(1, expr->context(), rax); | 1199 DropAndApply(1, expr->context(), rax); |
| 1063 } | 1200 } |
| 1064 | 1201 |
| 1065 | 1202 |
| 1066 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 1203 void FastCodeGenerator::EmitCallWithStub(Call* expr) { |
| 1067 // Code common for calls using the call stub. | 1204 // Code common for calls using the call stub. |
| 1068 ZoneList<Expression*>* args = expr->arguments(); | 1205 ZoneList<Expression*>* args = expr->arguments(); |
| 1069 int arg_count = args->length(); | 1206 int arg_count = args->length(); |
| 1070 for (int i = 0; i < arg_count; i++) { | 1207 for (int i = 0; i < arg_count; i++) { |
| 1071 Visit(args->at(i)); | 1208 VisitForValue(args->at(i), kStack); |
| 1072 } | 1209 } |
| 1073 // Record source position for debugger. | 1210 // Record source position for debugger. |
| 1074 SetSourcePosition(expr->position()); | 1211 SetSourcePosition(expr->position()); |
| 1075 CallFunctionStub stub(arg_count, NOT_IN_LOOP); | 1212 CallFunctionStub stub(arg_count, NOT_IN_LOOP); |
| 1076 __ CallStub(&stub); | 1213 __ CallStub(&stub); |
| 1077 // Restore context register. | 1214 // Restore context register. |
| 1078 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1215 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1079 // Discard the function left on TOS. | 1216 // Discard the function left on TOS. |
| 1080 DropAndApply(1, expr->context(), rax); | 1217 DropAndApply(1, expr->context(), rax); |
| 1081 } | 1218 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1099 var->slot()->type() == Slot::LOOKUP) { | 1236 var->slot()->type() == Slot::LOOKUP) { |
| 1100 // Call to a lookup slot. | 1237 // Call to a lookup slot. |
| 1101 UNREACHABLE(); | 1238 UNREACHABLE(); |
| 1102 } else if (fun->AsProperty() != NULL) { | 1239 } else if (fun->AsProperty() != NULL) { |
| 1103 // Call to an object property. | 1240 // Call to an object property. |
| 1104 Property* prop = fun->AsProperty(); | 1241 Property* prop = fun->AsProperty(); |
| 1105 Literal* key = prop->key()->AsLiteral(); | 1242 Literal* key = prop->key()->AsLiteral(); |
| 1106 if (key != NULL && key->handle()->IsSymbol()) { | 1243 if (key != NULL && key->handle()->IsSymbol()) { |
| 1107 // Call to a named property, use call IC. | 1244 // Call to a named property, use call IC. |
| 1108 __ Push(key->handle()); | 1245 __ Push(key->handle()); |
| 1109 Visit(prop->obj()); | 1246 VisitForValue(prop->obj(), kStack); |
| 1110 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1247 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 1111 } else { | 1248 } else { |
| 1112 // Call to a keyed property, use keyed load IC followed by function | 1249 // Call to a keyed property, use keyed load IC followed by function |
| 1113 // call. | 1250 // call. |
| 1114 Visit(prop->obj()); | 1251 VisitForValue(prop->obj(), kStack); |
| 1115 Visit(prop->key()); | 1252 VisitForValue(prop->key(), kStack); |
| 1116 // Record source code position for IC call. | 1253 // Record source code position for IC call. |
| 1117 SetSourcePosition(prop->position()); | 1254 SetSourcePosition(prop->position()); |
| 1118 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1255 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1119 __ call(ic, RelocInfo::CODE_TARGET); | 1256 __ call(ic, RelocInfo::CODE_TARGET); |
| 1120 // By emitting a nop we make sure that we do not have a "test rax,..." | 1257 // By emitting a nop we make sure that we do not have a "test rax,..." |
| 1121 // instruction after the call it is treated specially by the LoadIC code. | 1258 // instruction after the call it is treated specially by the LoadIC code. |
| 1122 __ nop(); | 1259 __ nop(); |
| 1123 // Drop key left on the stack by IC. | 1260 // Drop key left on the stack by IC. |
| 1124 __ Drop(1); | 1261 __ Drop(1); |
| 1125 // Pop receiver. | 1262 // Pop receiver. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1138 } else { | 1275 } else { |
| 1139 // Call to some other expression. If the expression is an anonymous | 1276 // Call to some other expression. If the expression is an anonymous |
| 1140 // function literal not called in a loop, mark it as one that should | 1277 // function literal not called in a loop, mark it as one that should |
| 1141 // also use the fast code generator. | 1278 // also use the fast code generator. |
| 1142 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 1279 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 1143 if (lit != NULL && | 1280 if (lit != NULL && |
| 1144 lit->name()->Equals(Heap::empty_string()) && | 1281 lit->name()->Equals(Heap::empty_string()) && |
| 1145 loop_depth() == 0) { | 1282 loop_depth() == 0) { |
| 1146 lit->set_try_fast_codegen(true); | 1283 lit->set_try_fast_codegen(true); |
| 1147 } | 1284 } |
| 1148 Visit(fun); | 1285 VisitForValue(fun, kStack); |
| 1149 // Load global receiver object. | 1286 // Load global receiver object. |
| 1150 __ movq(rbx, CodeGenerator::GlobalObject()); | 1287 __ movq(rbx, CodeGenerator::GlobalObject()); |
| 1151 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 1288 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
| 1152 // Emit function call. | 1289 // Emit function call. |
| 1153 EmitCallWithStub(expr); | 1290 EmitCallWithStub(expr); |
| 1154 } | 1291 } |
| 1155 } | 1292 } |
| 1156 | 1293 |
| 1157 | 1294 |
| 1158 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 1295 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
| 1159 Comment cmnt(masm_, "[ CallNew"); | 1296 Comment cmnt(masm_, "[ CallNew"); |
| 1160 // According to ECMA-262, section 11.2.2, page 44, the function | 1297 // According to ECMA-262, section 11.2.2, page 44, the function |
| 1161 // expression in new calls must be evaluated before the | 1298 // expression in new calls must be evaluated before the |
| 1162 // arguments. | 1299 // arguments. |
| 1163 // Push function on the stack. | 1300 // Push function on the stack. |
| 1164 Visit(expr->expression()); | 1301 VisitForValue(expr->expression(), kStack); |
| 1165 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | |
| 1166 // If location is value, already on the stack, | |
| 1167 | 1302 |
| 1168 // Push global object (receiver). | 1303 // Push global object (receiver). |
| 1169 __ push(CodeGenerator::GlobalObject()); | 1304 __ push(CodeGenerator::GlobalObject()); |
| 1170 | 1305 |
| 1171 // Push the arguments ("left-to-right") on the stack. | 1306 // Push the arguments ("left-to-right") on the stack. |
| 1172 ZoneList<Expression*>* args = expr->arguments(); | 1307 ZoneList<Expression*>* args = expr->arguments(); |
| 1173 int arg_count = args->length(); | 1308 int arg_count = args->length(); |
| 1174 for (int i = 0; i < arg_count; i++) { | 1309 for (int i = 0; i < arg_count; i++) { |
| 1175 Visit(args->at(i)); | 1310 VisitForValue(args->at(i), kStack); |
| 1176 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
| 1177 // If location is value, it is already on the stack, | |
| 1178 // so nothing to do here. | |
| 1179 } | 1311 } |
| 1180 | 1312 |
| 1181 // Call the construct call builtin that handles allocation and | 1313 // Call the construct call builtin that handles allocation and |
| 1182 // constructor invocation. | 1314 // constructor invocation. |
| 1183 SetSourcePosition(expr->position()); | 1315 SetSourcePosition(expr->position()); |
| 1184 | 1316 |
| 1185 // Load function, arg_count into rdi and rax. | 1317 // Load function, arg_count into rdi and rax. |
| 1186 __ Set(rax, arg_count); | 1318 __ Set(rax, arg_count); |
| 1187 // Function is in rsp[arg_count + 1]. | 1319 // Function is in rsp[arg_count + 1]. |
| 1188 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); | 1320 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1202 if (expr->is_jsruntime()) { | 1334 if (expr->is_jsruntime()) { |
| 1203 // Prepare for calling JS runtime function. | 1335 // Prepare for calling JS runtime function. |
| 1204 __ Push(expr->name()); | 1336 __ Push(expr->name()); |
| 1205 __ movq(rax, CodeGenerator::GlobalObject()); | 1337 __ movq(rax, CodeGenerator::GlobalObject()); |
| 1206 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); | 1338 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); |
| 1207 } | 1339 } |
| 1208 | 1340 |
| 1209 // Push the arguments ("left-to-right"). | 1341 // Push the arguments ("left-to-right"). |
| 1210 int arg_count = args->length(); | 1342 int arg_count = args->length(); |
| 1211 for (int i = 0; i < arg_count; i++) { | 1343 for (int i = 0; i < arg_count; i++) { |
| 1212 Visit(args->at(i)); | 1344 VisitForValue(args->at(i), kStack); |
| 1213 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
| 1214 } | 1345 } |
| 1215 | 1346 |
| 1216 if (expr->is_jsruntime()) { | 1347 if (expr->is_jsruntime()) { |
| 1217 // Call the JS runtime function. | 1348 // Call the JS runtime function. |
| 1218 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1349 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 1219 NOT_IN_LOOP); | 1350 NOT_IN_LOOP); |
| 1220 __ call(ic, RelocInfo::CODE_TARGET); | 1351 __ call(ic, RelocInfo::CODE_TARGET); |
| 1221 // Restore context register. | 1352 // Restore context register. |
| 1222 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1353 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1223 // Discard the function left on TOS. | 1354 // Discard the function left on TOS. |
| 1224 DropAndApply(1, expr->context(), rax); | 1355 DropAndApply(1, expr->context(), rax); |
| 1225 } else { | 1356 } else { |
| 1226 __ CallRuntime(expr->function(), arg_count); | 1357 __ CallRuntime(expr->function(), arg_count); |
| 1227 Apply(expr->context(), rax); | 1358 Apply(expr->context(), rax); |
| 1228 } | 1359 } |
| 1229 } | 1360 } |
| 1230 | 1361 |
| 1231 | 1362 |
| 1232 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1363 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 1233 switch (expr->op()) { | 1364 switch (expr->op()) { |
| 1234 case Token::VOID: { | 1365 case Token::VOID: { |
| 1235 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1366 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 1367 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); |
| 1236 Visit(expr->expression()); | 1368 Visit(expr->expression()); |
| 1237 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); | |
| 1238 switch (expr->context()) { | 1369 switch (expr->context()) { |
| 1239 case Expression::kUninitialized: | 1370 case Expression::kUninitialized: |
| 1240 UNREACHABLE(); | 1371 UNREACHABLE(); |
| 1241 break; | 1372 break; |
| 1242 case Expression::kEffect: | 1373 case Expression::kEffect: |
| 1243 break; | 1374 break; |
| 1244 case Expression::kValue: | 1375 case Expression::kValue: |
| 1245 __ PushRoot(Heap::kUndefinedValueRootIndex); | 1376 switch (location_) { |
| 1377 case kAccumulator: |
| 1378 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 1379 break; |
| 1380 case kStack: |
| 1381 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1382 break; |
| 1383 } |
| 1246 break; | 1384 break; |
| 1247 case Expression::kTestValue: | 1385 case Expression::kTestValue: |
| 1248 // Value is false so it's needed. | 1386 // Value is false so it's needed. |
| 1249 __ PushRoot(Heap::kUndefinedValueRootIndex); | 1387 switch (location_) { |
| 1388 case kAccumulator: |
| 1389 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 1390 break; |
| 1391 case kStack: |
| 1392 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1393 break; |
| 1394 } |
| 1250 // Fall through. | 1395 // Fall through. |
| 1251 case Expression::kTest: | 1396 case Expression::kTest: |
| 1252 case Expression::kValueTest: | 1397 case Expression::kValueTest: |
| 1253 __ jmp(false_label_); | 1398 __ jmp(false_label_); |
| 1254 break; | 1399 break; |
| 1255 } | 1400 } |
| 1256 break; | 1401 break; |
| 1257 } | 1402 } |
| 1258 | 1403 |
| 1259 case Token::NOT: { | 1404 case Token::NOT: { |
| 1260 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 1405 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 1261 ASSERT_EQ(Expression::kTest, expr->expression()->context()); | 1406 ASSERT_EQ(Expression::kTest, expr->expression()->context()); |
| 1262 | 1407 |
| 1263 Label push_true, push_false, done; | 1408 Label materialize_true, materialize_false, done; |
| 1409 // Initially assume a pure test context. Notice that the labels are |
| 1410 // swapped. |
| 1411 Label* if_true = false_label_; |
| 1412 Label* if_false = true_label_; |
| 1264 switch (expr->context()) { | 1413 switch (expr->context()) { |
| 1265 case Expression::kUninitialized: | 1414 case Expression::kUninitialized: |
| 1266 UNREACHABLE(); | 1415 UNREACHABLE(); |
| 1267 break; | 1416 break; |
| 1268 | 1417 case Expression::kEffect: |
| 1418 if_true = &done; |
| 1419 if_false = &done; |
| 1420 break; |
| 1269 case Expression::kValue: | 1421 case Expression::kValue: |
| 1270 VisitForControl(expr->expression(), &push_false, &push_true); | 1422 if_true = &materialize_false; |
| 1271 __ bind(&push_true); | 1423 if_false = &materialize_true; |
| 1272 __ PushRoot(Heap::kTrueValueRootIndex); | |
| 1273 __ jmp(&done); | |
| 1274 __ bind(&push_false); | |
| 1275 __ PushRoot(Heap::kFalseValueRootIndex); | |
| 1276 __ bind(&done); | |
| 1277 break; | 1424 break; |
| 1278 | 1425 case Expression::kTest: |
| 1279 case Expression::kEffect: | |
| 1280 VisitForControl(expr->expression(), &done, &done); | |
| 1281 __ bind(&done); | |
| 1282 break; | 1426 break; |
| 1283 | 1427 case Expression::kValueTest: |
| 1284 case Expression::kTest: | 1428 if_false = &materialize_true; |
| 1285 VisitForControl(expr->expression(), false_label_, true_label_); | |
| 1286 break; | 1429 break; |
| 1287 | |
| 1288 case Expression::kValueTest: | |
| 1289 VisitForControl(expr->expression(), false_label_, &push_true); | |
| 1290 __ bind(&push_true); | |
| 1291 __ PushRoot(Heap::kTrueValueRootIndex); | |
| 1292 __ jmp(true_label_); | |
| 1293 break; | |
| 1294 | |
| 1295 case Expression::kTestValue: | 1430 case Expression::kTestValue: |
| 1296 VisitForControl(expr->expression(), &push_false, true_label_); | 1431 if_true = &materialize_false; |
| 1297 __ bind(&push_false); | |
| 1298 __ PushRoot(Heap::kFalseValueRootIndex); | |
| 1299 __ jmp(false_label_); | |
| 1300 break; | 1432 break; |
| 1301 } | 1433 } |
| 1434 VisitForControl(expr->expression(), if_true, if_false); |
| 1435 Apply(expr->context(), if_false, if_true); // Labels swapped. |
| 1302 break; | 1436 break; |
| 1303 } | 1437 } |
| 1304 | 1438 |
| 1305 case Token::TYPEOF: { | 1439 case Token::TYPEOF: { |
| 1306 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 1440 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 1307 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 1441 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
| 1308 | 1442 |
| 1309 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 1443 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 1310 if (proxy != NULL && | 1444 if (proxy != NULL && |
| 1311 !proxy->var()->is_this() && | 1445 !proxy->var()->is_this() && |
| 1312 proxy->var()->is_global()) { | 1446 proxy->var()->is_global()) { |
| 1313 Comment cmnt(masm_, "Global variable"); | 1447 Comment cmnt(masm_, "Global variable"); |
| 1314 __ push(CodeGenerator::GlobalObject()); | 1448 __ push(CodeGenerator::GlobalObject()); |
| 1315 __ Move(rcx, proxy->name()); | 1449 __ Move(rcx, proxy->name()); |
| 1316 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1450 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1317 // Use a regular load, not a contextual load, to avoid a reference | 1451 // Use a regular load, not a contextual load, to avoid a reference |
| 1318 // error. | 1452 // error. |
| 1319 __ Call(ic, RelocInfo::CODE_TARGET); | 1453 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1320 __ movq(Operand(rsp, 0), rax); | 1454 __ movq(Operand(rsp, 0), rax); |
| 1321 } else if (proxy != NULL && | 1455 } else if (proxy != NULL && |
| 1322 proxy->var()->slot() != NULL && | 1456 proxy->var()->slot() != NULL && |
| 1323 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1457 proxy->var()->slot()->type() == Slot::LOOKUP) { |
| 1324 __ push(rsi); | 1458 __ push(rsi); |
| 1325 __ Push(proxy->name()); | 1459 __ Push(proxy->name()); |
| 1326 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1460 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 1327 __ push(rax); | 1461 __ push(rax); |
| 1328 } else { | 1462 } else { |
| 1329 // This expression cannot throw a reference error at the top level. | 1463 // This expression cannot throw a reference error at the top level. |
| 1330 Visit(expr->expression()); | 1464 VisitForValue(expr->expression(), kStack); |
| 1331 } | 1465 } |
| 1332 | 1466 |
| 1333 __ CallRuntime(Runtime::kTypeof, 1); | 1467 __ CallRuntime(Runtime::kTypeof, 1); |
| 1334 Apply(expr->context(), rax); | 1468 Apply(expr->context(), rax); |
| 1335 break; | 1469 break; |
| 1336 } | 1470 } |
| 1337 | 1471 |
| 1338 default: | 1472 default: |
| 1339 UNREACHABLE(); | 1473 UNREACHABLE(); |
| 1340 } | 1474 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1353 // of the key to detect a named property. | 1487 // of the key to detect a named property. |
| 1354 if (prop != NULL) { | 1488 if (prop != NULL) { |
| 1355 assign_type = (prop->key()->context() == Expression::kUninitialized) | 1489 assign_type = (prop->key()->context() == Expression::kUninitialized) |
| 1356 ? NAMED_PROPERTY | 1490 ? NAMED_PROPERTY |
| 1357 : KEYED_PROPERTY; | 1491 : KEYED_PROPERTY; |
| 1358 } | 1492 } |
| 1359 | 1493 |
| 1360 // Evaluate expression and get value. | 1494 // Evaluate expression and get value. |
| 1361 if (assign_type == VARIABLE) { | 1495 if (assign_type == VARIABLE) { |
| 1362 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 1496 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1497 Location saved_location = location_; |
| 1498 location_ = kStack; |
| 1363 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 1499 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
| 1364 Expression::kValue); | 1500 Expression::kValue); |
| 1501 location_ = saved_location; |
| 1365 } else { | 1502 } else { |
| 1366 // Reserve space for result of postfix operation. | 1503 // Reserve space for result of postfix operation. |
| 1367 if (expr->is_postfix() && expr->context() != Expression::kEffect) { | 1504 if (expr->is_postfix() && expr->context() != Expression::kEffect) { |
| 1368 ASSERT(expr->context() != Expression::kUninitialized); | 1505 ASSERT(expr->context() != Expression::kUninitialized); |
| 1369 __ Push(Smi::FromInt(0)); | 1506 __ Push(Smi::FromInt(0)); |
| 1370 } | 1507 } |
| 1371 Visit(prop->obj()); | 1508 VisitForValue(prop->obj(), kStack); |
| 1372 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | |
| 1373 if (assign_type == NAMED_PROPERTY) { | 1509 if (assign_type == NAMED_PROPERTY) { |
| 1374 EmitNamedPropertyLoad(prop, Expression::kValue); | 1510 EmitNamedPropertyLoad(prop); |
| 1375 } else { | 1511 } else { |
| 1376 Visit(prop->key()); | 1512 VisitForValue(prop->key(), kStack); |
| 1377 ASSERT_EQ(Expression::kValue, prop->key()->context()); | 1513 EmitKeyedPropertyLoad(prop); |
| 1378 EmitKeyedPropertyLoad(prop, Expression::kValue); | |
| 1379 } | 1514 } |
| 1515 __ push(rax); |
| 1380 } | 1516 } |
| 1381 | 1517 |
| 1382 // Convert to number. | 1518 // Convert to number. |
| 1383 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 1519 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 1384 | 1520 |
| 1385 // Save result for postfix expressions. | 1521 // Save result for postfix expressions. |
| 1386 if (expr->is_postfix()) { | 1522 if (expr->is_postfix()) { |
| 1387 switch (expr->context()) { | 1523 switch (expr->context()) { |
| 1388 case Expression::kUninitialized: | 1524 case Expression::kUninitialized: |
| 1389 UNREACHABLE(); | 1525 UNREACHABLE(); |
| 1390 case Expression::kEffect: | 1526 case Expression::kEffect: |
| 1391 // Do not save result. | 1527 // Do not save result. |
| 1392 break; | 1528 break; |
| 1393 case Expression::kValue: // Fall through | 1529 case Expression::kValue: |
| 1394 case Expression::kTest: // Fall through | 1530 case Expression::kTest: |
| 1395 case Expression::kTestValue: // Fall through | |
| 1396 case Expression::kValueTest: | 1531 case Expression::kValueTest: |
| 1532 case Expression::kTestValue: |
| 1397 // Save the result on the stack. If we have a named or keyed property | 1533 // Save the result on the stack. If we have a named or keyed property |
| 1398 // we store the result under the receiver that is currently on top | 1534 // we store the result under the receiver that is currently on top |
| 1399 // of the stack. | 1535 // of the stack. |
| 1400 switch (assign_type) { | 1536 switch (assign_type) { |
| 1401 case VARIABLE: | 1537 case VARIABLE: |
| 1402 __ push(rax); | 1538 __ push(rax); |
| 1403 break; | 1539 break; |
| 1404 case NAMED_PROPERTY: | 1540 case NAMED_PROPERTY: |
| 1405 __ movq(Operand(rsp, kPointerSize), rax); | 1541 __ movq(Operand(rsp, kPointerSize), rax); |
| 1406 break; | 1542 break; |
| 1407 case KEYED_PROPERTY: | 1543 case KEYED_PROPERTY: |
| 1408 __ movq(Operand(rsp, 2 * kPointerSize), rax); | 1544 __ movq(Operand(rsp, 2 * kPointerSize), rax); |
| 1409 break; | 1545 break; |
| 1410 } | 1546 } |
| 1411 break; | 1547 break; |
| 1412 } | 1548 } |
| 1413 } | 1549 } |
| 1414 | 1550 |
| 1415 // Call runtime for +1/-1. | 1551 // Call stub for +1/-1. |
| 1416 __ push(rax); | 1552 __ push(rax); |
| 1417 __ Push(Smi::FromInt(1)); | 1553 __ Push(Smi::FromInt(1)); |
| 1418 if (expr->op() == Token::INC) { | 1554 GenericBinaryOpStub stub(expr->binary_op(), |
| 1419 __ CallRuntime(Runtime::kNumberAdd, 2); | 1555 NO_OVERWRITE, |
| 1420 } else { | 1556 NO_GENERIC_BINARY_FLAGS); |
| 1421 __ CallRuntime(Runtime::kNumberSub, 2); | 1557 __ CallStub(&stub); |
| 1422 } | |
| 1423 | 1558 |
| 1424 // Store the value returned in rax. | 1559 // Store the value returned in rax. |
| 1425 switch (assign_type) { | 1560 switch (assign_type) { |
| 1426 case VARIABLE: | 1561 case VARIABLE: |
| 1427 __ push(rax); | |
| 1428 if (expr->is_postfix()) { | 1562 if (expr->is_postfix()) { |
| 1429 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1563 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1430 Expression::kEffect); | 1564 Expression::kEffect); |
| 1431 // For all contexts except kEffect: We have the result on | 1565 // For all contexts except kEffect: We have the result on |
| 1432 // top of the stack. | 1566 // top of the stack. |
| 1433 if (expr->context() != Expression::kEffect) { | 1567 if (expr->context() != Expression::kEffect) { |
| 1434 ApplyTOS(expr->context()); | 1568 ApplyTOS(expr->context()); |
| 1435 } | 1569 } |
| 1436 } else { | 1570 } else { |
| 1437 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1571 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1492 case Token::ADD: | 1626 case Token::ADD: |
| 1493 case Token::SUB: | 1627 case Token::SUB: |
| 1494 case Token::DIV: | 1628 case Token::DIV: |
| 1495 case Token::MOD: | 1629 case Token::MOD: |
| 1496 case Token::MUL: | 1630 case Token::MUL: |
| 1497 case Token::BIT_OR: | 1631 case Token::BIT_OR: |
| 1498 case Token::BIT_AND: | 1632 case Token::BIT_AND: |
| 1499 case Token::BIT_XOR: | 1633 case Token::BIT_XOR: |
| 1500 case Token::SHL: | 1634 case Token::SHL: |
| 1501 case Token::SHR: | 1635 case Token::SHR: |
| 1502 case Token::SAR: { | 1636 case Token::SAR: |
| 1503 ASSERT_EQ(Expression::kValue, expr->left()->context()); | 1637 VisitForValue(expr->left(), kStack); |
| 1504 ASSERT_EQ(Expression::kValue, expr->right()->context()); | 1638 VisitForValue(expr->right(), kAccumulator); |
| 1639 EmitBinaryOp(expr->op(), expr->context()); |
| 1640 break; |
| 1505 | 1641 |
| 1506 Visit(expr->left()); | |
| 1507 Visit(expr->right()); | |
| 1508 GenericBinaryOpStub stub(expr->op(), | |
| 1509 NO_OVERWRITE, | |
| 1510 NO_GENERIC_BINARY_FLAGS); | |
| 1511 __ CallStub(&stub); | |
| 1512 Apply(expr->context(), rax); | |
| 1513 | |
| 1514 break; | |
| 1515 } | |
| 1516 default: | 1642 default: |
| 1517 UNREACHABLE(); | 1643 UNREACHABLE(); |
| 1518 } | 1644 } |
| 1519 } | 1645 } |
| 1520 | 1646 |
| 1521 | 1647 |
| 1522 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1648 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 1523 Comment cmnt(masm_, "[ CompareOperation"); | 1649 Comment cmnt(masm_, "[ CompareOperation"); |
| 1524 ASSERT_EQ(Expression::kValue, expr->left()->context()); | |
| 1525 ASSERT_EQ(Expression::kValue, expr->right()->context()); | |
| 1526 Visit(expr->left()); | |
| 1527 Visit(expr->right()); | |
| 1528 | 1650 |
| 1529 // Always perform the comparison for its control flow. Pack the result | 1651 // Always perform the comparison for its control flow. Pack the result |
| 1530 // into the expression's context after the comparison is performed. | 1652 // into the expression's context after the comparison is performed. |
| 1531 Label push_true, push_false, done; | 1653 Label materialize_true, materialize_false, done; |
| 1532 // Initially assume we are in a test context. | 1654 // Initially assume we are in a test context. |
| 1533 Label* if_true = true_label_; | 1655 Label* if_true = true_label_; |
| 1534 Label* if_false = false_label_; | 1656 Label* if_false = false_label_; |
| 1535 switch (expr->context()) { | 1657 switch (expr->context()) { |
| 1536 case Expression::kUninitialized: | 1658 case Expression::kUninitialized: |
| 1537 UNREACHABLE(); | 1659 UNREACHABLE(); |
| 1538 break; | 1660 break; |
| 1539 case Expression::kValue: | |
| 1540 if_true = &push_true; | |
| 1541 if_false = &push_false; | |
| 1542 break; | |
| 1543 case Expression::kEffect: | 1661 case Expression::kEffect: |
| 1544 if_true = &done; | 1662 if_true = &done; |
| 1545 if_false = &done; | 1663 if_false = &done; |
| 1546 break; | 1664 break; |
| 1665 case Expression::kValue: |
| 1666 if_true = &materialize_true; |
| 1667 if_false = &materialize_false; |
| 1668 break; |
| 1547 case Expression::kTest: | 1669 case Expression::kTest: |
| 1548 break; | 1670 break; |
| 1549 case Expression::kValueTest: | 1671 case Expression::kValueTest: |
| 1550 if_true = &push_true; | 1672 if_true = &materialize_true; |
| 1551 break; | 1673 break; |
| 1552 case Expression::kTestValue: | 1674 case Expression::kTestValue: |
| 1553 if_false = &push_false; | 1675 if_false = &materialize_false; |
| 1554 break; | 1676 break; |
| 1555 } | 1677 } |
| 1556 | 1678 |
| 1679 VisitForValue(expr->left(), kStack); |
| 1557 switch (expr->op()) { | 1680 switch (expr->op()) { |
| 1558 case Token::IN: { | 1681 case Token::IN: |
| 1682 VisitForValue(expr->right(), kStack); |
| 1559 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 1683 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 1560 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 1684 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 1561 __ j(equal, if_true); | 1685 __ j(equal, if_true); |
| 1562 __ jmp(if_false); | 1686 __ jmp(if_false); |
| 1563 break; | 1687 break; |
| 1564 } | |
| 1565 | 1688 |
| 1566 case Token::INSTANCEOF: { | 1689 case Token::INSTANCEOF: { |
| 1690 VisitForValue(expr->right(), kStack); |
| 1567 InstanceofStub stub; | 1691 InstanceofStub stub; |
| 1568 __ CallStub(&stub); | 1692 __ CallStub(&stub); |
| 1569 __ testq(rax, rax); | 1693 __ testq(rax, rax); |
| 1570 __ j(zero, if_true); // The stub returns 0 for true. | 1694 __ j(zero, if_true); // The stub returns 0 for true. |
| 1571 __ jmp(if_false); | 1695 __ jmp(if_false); |
| 1572 break; | 1696 break; |
| 1573 } | 1697 } |
| 1574 | 1698 |
| 1575 default: { | 1699 default: { |
| 1700 VisitForValue(expr->right(), kAccumulator); |
| 1576 Condition cc = no_condition; | 1701 Condition cc = no_condition; |
| 1577 bool strict = false; | 1702 bool strict = false; |
| 1578 switch (expr->op()) { | 1703 switch (expr->op()) { |
| 1579 case Token::EQ_STRICT: | 1704 case Token::EQ_STRICT: |
| 1580 strict = true; | 1705 strict = true; |
| 1581 // Fall through. | 1706 // Fall through. |
| 1582 case Token::EQ: | 1707 case Token::EQ: |
| 1583 cc = equal; | 1708 cc = equal; |
| 1584 __ pop(rax); | |
| 1585 __ pop(rdx); | 1709 __ pop(rdx); |
| 1586 break; | 1710 break; |
| 1587 case Token::LT: | 1711 case Token::LT: |
| 1588 cc = less; | 1712 cc = less; |
| 1589 __ pop(rax); | |
| 1590 __ pop(rdx); | 1713 __ pop(rdx); |
| 1591 break; | 1714 break; |
| 1592 case Token::GT: | 1715 case Token::GT: |
| 1593 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1716 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
| 1594 cc = less; | 1717 cc = less; |
| 1595 __ pop(rdx); | 1718 __ movq(rdx, result_register()); |
| 1596 __ pop(rax); | 1719 __ pop(rax); |
| 1597 break; | 1720 break; |
| 1598 case Token::LTE: | 1721 case Token::LTE: |
| 1599 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1722 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
| 1600 cc = greater_equal; | 1723 cc = greater_equal; |
| 1601 __ pop(rdx); | 1724 __ movq(rdx, result_register()); |
| 1602 __ pop(rax); | 1725 __ pop(rax); |
| 1603 break; | 1726 break; |
| 1604 case Token::GTE: | 1727 case Token::GTE: |
| 1605 cc = greater_equal; | 1728 cc = greater_equal; |
| 1606 __ pop(rax); | |
| 1607 __ pop(rdx); | 1729 __ pop(rdx); |
| 1608 break; | 1730 break; |
| 1609 case Token::IN: | 1731 case Token::IN: |
| 1610 case Token::INSTANCEOF: | 1732 case Token::INSTANCEOF: |
| 1611 default: | 1733 default: |
| 1612 UNREACHABLE(); | 1734 UNREACHABLE(); |
| 1613 } | 1735 } |
| 1614 | 1736 |
| 1615 // The comparison stub expects the smi vs. smi case to be handled | 1737 // The comparison stub expects the smi vs. smi case to be handled |
| 1616 // before it is called. | 1738 // before it is called. |
| 1617 Label slow_case; | 1739 Label slow_case; |
| 1618 __ JumpIfNotBothSmi(rax, rdx, &slow_case); | 1740 __ JumpIfNotBothSmi(rax, rdx, &slow_case); |
| 1619 __ SmiCompare(rdx, rax); | 1741 __ SmiCompare(rdx, rax); |
| 1620 __ j(cc, if_true); | 1742 __ j(cc, if_true); |
| 1621 __ jmp(if_false); | 1743 __ jmp(if_false); |
| 1622 | 1744 |
| 1623 __ bind(&slow_case); | 1745 __ bind(&slow_case); |
| 1624 CompareStub stub(cc, strict); | 1746 CompareStub stub(cc, strict); |
| 1625 __ CallStub(&stub); | 1747 __ CallStub(&stub); |
| 1626 __ testq(rax, rax); | 1748 __ testq(rax, rax); |
| 1627 __ j(cc, if_true); | 1749 __ j(cc, if_true); |
| 1628 __ jmp(if_false); | 1750 __ jmp(if_false); |
| 1629 } | 1751 } |
| 1630 } | 1752 } |
| 1631 | 1753 |
| 1632 // Convert the result of the comparison into one expected for this | 1754 // Convert the result of the comparison into one expected for this |
| 1633 // expression's context. | 1755 // expression's context. |
| 1634 switch (expr->context()) { | 1756 Apply(expr->context(), if_true, if_false); |
| 1635 case Expression::kUninitialized: | |
| 1636 UNREACHABLE(); | |
| 1637 break; | |
| 1638 | |
| 1639 case Expression::kEffect: | |
| 1640 __ bind(&done); | |
| 1641 break; | |
| 1642 | |
| 1643 case Expression::kValue: | |
| 1644 __ bind(&push_true); | |
| 1645 __ PushRoot(Heap::kTrueValueRootIndex); | |
| 1646 __ jmp(&done); | |
| 1647 __ bind(&push_false); | |
| 1648 __ PushRoot(Heap::kFalseValueRootIndex); | |
| 1649 __ bind(&done); | |
| 1650 break; | |
| 1651 | |
| 1652 case Expression::kTest: | |
| 1653 break; | |
| 1654 | |
| 1655 case Expression::kValueTest: | |
| 1656 __ bind(&push_true); | |
| 1657 __ PushRoot(Heap::kTrueValueRootIndex); | |
| 1658 __ jmp(true_label_); | |
| 1659 break; | |
| 1660 | |
| 1661 case Expression::kTestValue: | |
| 1662 __ bind(&push_false); | |
| 1663 __ PushRoot(Heap::kFalseValueRootIndex); | |
| 1664 __ jmp(false_label_); | |
| 1665 break; | |
| 1666 } | |
| 1667 } | 1757 } |
| 1668 | 1758 |
| 1669 | 1759 |
| 1670 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1760 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 1671 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 1761 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1672 Apply(expr->context(), rax); | 1762 Apply(expr->context(), rax); |
| 1673 } | 1763 } |
| 1674 | 1764 |
| 1675 | 1765 |
| 1676 Register FastCodeGenerator::result_register() { return rax; } | 1766 Register FastCodeGenerator::result_register() { return rax; } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 __ movq(Operand(rsp, 0), rdx); | 1811 __ movq(Operand(rsp, 0), rdx); |
| 1722 // And return. | 1812 // And return. |
| 1723 __ ret(0); | 1813 __ ret(0); |
| 1724 } | 1814 } |
| 1725 | 1815 |
| 1726 | 1816 |
| 1727 #undef __ | 1817 #undef __ |
| 1728 | 1818 |
| 1729 | 1819 |
| 1730 } } // namespace v8::internal | 1820 } } // namespace v8::internal |
| OLD | NEW |