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