| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 } | 230 } |
| 231 | 231 |
| 232 | 232 |
| 233 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | 233 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( |
| 234 Token::Value op, Expression* left, Expression* right) { | 234 Token::Value op, Expression* left, Expression* right) { |
| 235 ASSERT(ShouldInlineSmiCase(op)); | 235 ASSERT(ShouldInlineSmiCase(op)); |
| 236 return kNoConstants; | 236 return kNoConstants; |
| 237 } | 237 } |
| 238 | 238 |
| 239 | 239 |
| 240 void FullCodeGenerator::Apply(Expression::Context context, Register reg) { | 240 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
| 241 switch (context) { | 241 } |
| 242 case Expression::kUninitialized: | |
| 243 UNREACHABLE(); | |
| 244 | 242 |
| 245 case Expression::kEffect: | |
| 246 // Nothing to do. | |
| 247 break; | |
| 248 | 243 |
| 249 case Expression::kValue: | 244 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
| 250 // Move value into place. | 245 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 251 switch (location_) { | 246 __ movq(result_register(), slot_operand); |
| 252 case kAccumulator: | 247 } |
| 253 if (!reg.is(result_register())) __ movq(result_register(), reg); | |
| 254 break; | |
| 255 case kStack: | |
| 256 __ push(reg); | |
| 257 break; | |
| 258 } | |
| 259 break; | |
| 260 | 248 |
| 261 case Expression::kTest: | 249 |
| 262 // For simplicity we always test the accumulator register. | 250 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
| 263 if (!reg.is(result_register())) __ movq(result_register(), reg); | 251 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 264 DoTest(true_label_, false_label_, fall_through_); | 252 __ push(slot_operand); |
| 265 break; | 253 } |
| 254 |
| 255 |
| 256 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
| 257 codegen()->Move(result_register(), slot); |
| 258 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 259 } |
| 260 |
| 261 |
| 262 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
| 263 } |
| 264 |
| 265 |
| 266 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 267 Heap::RootListIndex index) const { |
| 268 __ LoadRoot(result_register(), index); |
| 269 } |
| 270 |
| 271 |
| 272 void FullCodeGenerator::StackValueContext::Plug( |
| 273 Heap::RootListIndex index) const { |
| 274 __ PushRoot(index); |
| 275 } |
| 276 |
| 277 |
| 278 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { |
| 279 if (index == Heap::kUndefinedValueRootIndex || |
| 280 index == Heap::kNullValueRootIndex || |
| 281 index == Heap::kFalseValueRootIndex) { |
| 282 __ jmp(false_label_); |
| 283 } else if (index == Heap::kTrueValueRootIndex) { |
| 284 __ jmp(true_label_); |
| 285 } else { |
| 286 __ LoadRoot(result_register(), index); |
| 287 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 266 } | 288 } |
| 267 } | 289 } |
| 268 | 290 |
| 269 | 291 |
| 270 void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) { | 292 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
| 271 switch (context) { | 293 } |
| 272 case Expression::kUninitialized: | 294 |
| 273 UNREACHABLE(); | 295 |
| 274 case Expression::kEffect: | 296 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 275 // Nothing to do. | 297 Handle<Object> lit) const { |
| 276 break; | 298 __ Move(result_register(), lit); |
| 277 case Expression::kValue: { | 299 } |
| 278 MemOperand slot_operand = EmitSlotSearch(slot, result_register()); | 300 |
| 279 switch (location_) { | 301 |
| 280 case kAccumulator: | 302 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { |
| 281 __ movq(result_register(), slot_operand); | 303 __ Push(lit); |
| 282 break; | 304 } |
| 283 case kStack: | 305 |
| 284 // Memory operands can be pushed directly. | 306 |
| 285 __ push(slot_operand); | 307 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { |
| 286 break; | 308 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. |
| 287 } | 309 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { |
| 288 break; | 310 __ jmp(false_label_); |
| 311 } else if (lit->IsTrue() || lit->IsJSObject()) { |
| 312 __ jmp(true_label_); |
| 313 } else if (lit->IsString()) { |
| 314 if (String::cast(*lit)->length() == 0) { |
| 315 __ jmp(false_label_); |
| 316 } else { |
| 317 __ jmp(true_label_); |
| 289 } | 318 } |
| 290 | 319 } else if (lit->IsSmi()) { |
| 291 case Expression::kTest: | 320 if (Smi::cast(*lit)->value() == 0) { |
| 292 Move(result_register(), slot); | 321 __ jmp(false_label_); |
| 293 DoTest(true_label_, false_label_, fall_through_); | 322 } else { |
| 294 break; | 323 __ jmp(true_label_); |
| 324 } |
| 325 } else { |
| 326 // For simplicity we always test the accumulator register. |
| 327 __ Move(result_register(), lit); |
| 328 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 295 } | 329 } |
| 296 } | 330 } |
| 297 | 331 |
| 298 | 332 |
| 299 void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) { | 333 void FullCodeGenerator::StackValueContext::DropAndPlug(int count, |
| 300 switch (context) { | 334 Register reg) const { |
| 301 case Expression::kUninitialized: | 335 ASSERT(count > 0); |
| 302 UNREACHABLE(); | 336 if (count > 1) __ Drop(count - 1); |
| 303 case Expression::kEffect: | 337 __ movq(Operand(rsp, 0), reg); |
| 304 // Nothing to do. | 338 } |
| 305 break; | |
| 306 case Expression::kValue: | |
| 307 switch (location_) { | |
| 308 case kAccumulator: | |
| 309 __ Move(result_register(), lit->handle()); | |
| 310 break; | |
| 311 case kStack: | |
| 312 __ Push(lit->handle()); | |
| 313 break; | |
| 314 } | |
| 315 break; | |
| 316 | 339 |
| 317 case Expression::kTest: | 340 |
| 318 __ Move(result_register(), lit->handle()); | 341 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 319 DoTest(true_label_, false_label_, fall_through_); | 342 Label* materialize_false) const { |
| 320 break; | 343 ASSERT_EQ(materialize_true, materialize_false); |
| 344 __ bind(materialize_true); |
| 345 } |
| 346 |
| 347 |
| 348 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 349 Label* materialize_true, |
| 350 Label* materialize_false) const { |
| 351 Label done; |
| 352 __ bind(materialize_true); |
| 353 __ Move(result_register(), Factory::true_value()); |
| 354 __ jmp(&done); |
| 355 __ bind(materialize_false); |
| 356 __ Move(result_register(), Factory::false_value()); |
| 357 __ bind(&done); |
| 358 } |
| 359 |
| 360 |
| 361 void FullCodeGenerator::StackValueContext::Plug( |
| 362 Label* materialize_true, |
| 363 Label* materialize_false) const { |
| 364 Label done; |
| 365 __ bind(materialize_true); |
| 366 __ Push(Factory::true_value()); |
| 367 __ jmp(&done); |
| 368 __ bind(materialize_false); |
| 369 __ Push(Factory::false_value()); |
| 370 __ bind(&done); |
| 371 } |
| 372 |
| 373 |
| 374 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 375 Label* materialize_false) const { |
| 376 } |
| 377 |
| 378 |
| 379 void FullCodeGenerator::EffectContext::Plug(bool flag) const { |
| 380 } |
| 381 |
| 382 |
| 383 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { |
| 384 Heap::RootListIndex value_root_index = |
| 385 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
| 386 __ LoadRoot(result_register(), value_root_index); |
| 387 } |
| 388 |
| 389 |
| 390 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
| 391 Heap::RootListIndex value_root_index = |
| 392 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
| 393 __ PushRoot(value_root_index); |
| 394 } |
| 395 |
| 396 |
| 397 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
| 398 if (flag) { |
| 399 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 400 } else { |
| 401 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 321 } | 402 } |
| 322 } | 403 } |
| 323 | 404 |
| 324 | |
| 325 void FullCodeGenerator::ApplyTOS(Expression::Context context) { | |
| 326 switch (context) { | |
| 327 case Expression::kUninitialized: | |
| 328 UNREACHABLE(); | |
| 329 | |
| 330 case Expression::kEffect: | |
| 331 __ Drop(1); | |
| 332 break; | |
| 333 | |
| 334 case Expression::kValue: | |
| 335 switch (location_) { | |
| 336 case kAccumulator: | |
| 337 __ pop(result_register()); | |
| 338 break; | |
| 339 case kStack: | |
| 340 break; | |
| 341 } | |
| 342 break; | |
| 343 | |
| 344 case Expression::kTest: | |
| 345 __ pop(result_register()); | |
| 346 DoTest(true_label_, false_label_, fall_through_); | |
| 347 break; | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 | |
| 352 void FullCodeGenerator::DropAndApply(int count, | |
| 353 Expression::Context context, | |
| 354 Register reg) { | |
| 355 ASSERT(count > 0); | |
| 356 ASSERT(!reg.is(rsp)); | |
| 357 switch (context) { | |
| 358 case Expression::kUninitialized: | |
| 359 UNREACHABLE(); | |
| 360 | |
| 361 case Expression::kEffect: | |
| 362 __ Drop(count); | |
| 363 break; | |
| 364 | |
| 365 case Expression::kValue: | |
| 366 switch (location_) { | |
| 367 case kAccumulator: | |
| 368 __ Drop(count); | |
| 369 if (!reg.is(result_register())) __ movq(result_register(), reg); | |
| 370 break; | |
| 371 case kStack: | |
| 372 if (count > 1) __ Drop(count - 1); | |
| 373 __ movq(Operand(rsp, 0), reg); | |
| 374 break; | |
| 375 } | |
| 376 break; | |
| 377 | |
| 378 case Expression::kTest: | |
| 379 __ Drop(count); | |
| 380 if (!reg.is(result_register())) __ movq(result_register(), reg); | |
| 381 DoTest(true_label_, false_label_, fall_through_); | |
| 382 break; | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 | |
| 387 void FullCodeGenerator::Apply(Expression::Context context, | |
| 388 Label* materialize_true, | |
| 389 Label* materialize_false) { | |
| 390 switch (context) { | |
| 391 case Expression::kUninitialized: | |
| 392 | |
| 393 case Expression::kEffect: | |
| 394 ASSERT_EQ(materialize_true, materialize_false); | |
| 395 __ bind(materialize_true); | |
| 396 break; | |
| 397 | |
| 398 case Expression::kValue: { | |
| 399 Label done; | |
| 400 switch (location_) { | |
| 401 case kAccumulator: | |
| 402 __ bind(materialize_true); | |
| 403 __ Move(result_register(), Factory::true_value()); | |
| 404 __ jmp(&done); | |
| 405 __ bind(materialize_false); | |
| 406 __ Move(result_register(), Factory::false_value()); | |
| 407 break; | |
| 408 case kStack: | |
| 409 __ bind(materialize_true); | |
| 410 __ Push(Factory::true_value()); | |
| 411 __ jmp(&done); | |
| 412 __ bind(materialize_false); | |
| 413 __ Push(Factory::false_value()); | |
| 414 break; | |
| 415 } | |
| 416 __ bind(&done); | |
| 417 break; | |
| 418 } | |
| 419 | |
| 420 case Expression::kTest: | |
| 421 break; | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 | |
| 426 // Convert constant control flow (true or false) to the result expected for | |
| 427 // a given expression context. | |
| 428 void FullCodeGenerator::Apply(Expression::Context context, bool flag) { | |
| 429 switch (context) { | |
| 430 case Expression::kUninitialized: | |
| 431 UNREACHABLE(); | |
| 432 break; | |
| 433 case Expression::kEffect: | |
| 434 break; | |
| 435 case Expression::kValue: { | |
| 436 Heap::RootListIndex value_root_index = | |
| 437 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | |
| 438 switch (location_) { | |
| 439 case kAccumulator: | |
| 440 __ LoadRoot(result_register(), value_root_index); | |
| 441 break; | |
| 442 case kStack: | |
| 443 __ PushRoot(value_root_index); | |
| 444 break; | |
| 445 } | |
| 446 break; | |
| 447 } | |
| 448 case Expression::kTest: | |
| 449 if (flag) { | |
| 450 if (true_label_ != fall_through_) __ jmp(true_label_); | |
| 451 } else { | |
| 452 if (false_label_ != fall_through_) __ jmp(false_label_); | |
| 453 } | |
| 454 break; | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 | 405 |
| 459 void FullCodeGenerator::DoTest(Label* if_true, | 406 void FullCodeGenerator::DoTest(Label* if_true, |
| 460 Label* if_false, | 407 Label* if_false, |
| 461 Label* fall_through) { | 408 Label* fall_through) { |
| 462 // Emit the inlined tests assumed by the stub. | 409 // Emit the inlined tests assumed by the stub. |
| 463 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); | 410 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 464 __ j(equal, if_false); | 411 __ j(equal, if_false); |
| 465 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); | 412 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); |
| 466 __ j(equal, if_true); | 413 __ j(equal, if_true); |
| 467 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); | 414 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 Property* prop = variable->AsProperty(); | 495 Property* prop = variable->AsProperty(); |
| 549 | 496 |
| 550 if (slot != NULL) { | 497 if (slot != NULL) { |
| 551 switch (slot->type()) { | 498 switch (slot->type()) { |
| 552 case Slot::PARAMETER: | 499 case Slot::PARAMETER: |
| 553 case Slot::LOCAL: | 500 case Slot::LOCAL: |
| 554 if (mode == Variable::CONST) { | 501 if (mode == Variable::CONST) { |
| 555 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 502 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 556 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); | 503 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); |
| 557 } else if (function != NULL) { | 504 } else if (function != NULL) { |
| 558 VisitForValue(function, kAccumulator); | 505 VisitForAccumulatorValue(function); |
| 559 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); | 506 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
| 560 } | 507 } |
| 561 break; | 508 break; |
| 562 | 509 |
| 563 case Slot::CONTEXT: | 510 case Slot::CONTEXT: |
| 564 // We bypass the general EmitSlotSearch because we know more about | 511 // We bypass the general EmitSlotSearch because we know more about |
| 565 // this specific context. | 512 // this specific context. |
| 566 | 513 |
| 567 // The variable in the decl always resides in the current context. | 514 // The variable in the decl always resides in the current context. |
| 568 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 515 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 569 if (FLAG_debug_code) { | 516 if (FLAG_debug_code) { |
| 570 // Check if we have the correct context pointer. | 517 // Check if we have the correct context pointer. |
| 571 __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); | 518 __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
| 572 __ cmpq(rbx, rsi); | 519 __ cmpq(rbx, rsi); |
| 573 __ Check(equal, "Unexpected declaration in current context."); | 520 __ Check(equal, "Unexpected declaration in current context."); |
| 574 } | 521 } |
| 575 if (mode == Variable::CONST) { | 522 if (mode == Variable::CONST) { |
| 576 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 523 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 577 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); | 524 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); |
| 578 // No write barrier since the hole value is in old space. | 525 // No write barrier since the hole value is in old space. |
| 579 } else if (function != NULL) { | 526 } else if (function != NULL) { |
| 580 VisitForValue(function, kAccumulator); | 527 VisitForAccumulatorValue(function); |
| 581 __ movq(ContextOperand(rsi, slot->index()), result_register()); | 528 __ movq(ContextOperand(rsi, slot->index()), result_register()); |
| 582 int offset = Context::SlotOffset(slot->index()); | 529 int offset = Context::SlotOffset(slot->index()); |
| 583 __ movq(rbx, rsi); | 530 __ movq(rbx, rsi); |
| 584 __ RecordWrite(rbx, offset, result_register(), rcx); | 531 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 585 } | 532 } |
| 586 break; | 533 break; |
| 587 | 534 |
| 588 case Slot::LOOKUP: { | 535 case Slot::LOOKUP: { |
| 589 __ push(rsi); | 536 __ push(rsi); |
| 590 __ Push(variable->name()); | 537 __ Push(variable->name()); |
| 591 // Declaration nodes are always introduced in one of two modes. | 538 // Declaration nodes are always introduced in one of two modes. |
| 592 ASSERT(mode == Variable::VAR || mode == Variable::CONST); | 539 ASSERT(mode == Variable::VAR || mode == Variable::CONST); |
| 593 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; | 540 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; |
| 594 __ Push(Smi::FromInt(attr)); | 541 __ Push(Smi::FromInt(attr)); |
| 595 // Push initial value, if any. | 542 // Push initial value, if any. |
| 596 // Note: For variables we must not push an initial value (such as | 543 // Note: For variables we must not push an initial value (such as |
| 597 // 'undefined') because we may have a (legal) redeclaration and we | 544 // 'undefined') because we may have a (legal) redeclaration and we |
| 598 // must not destroy the current value. | 545 // must not destroy the current value. |
| 599 if (mode == Variable::CONST) { | 546 if (mode == Variable::CONST) { |
| 600 __ PushRoot(Heap::kTheHoleValueRootIndex); | 547 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 601 } else if (function != NULL) { | 548 } else if (function != NULL) { |
| 602 VisitForValue(function, kStack); | 549 VisitForStackValue(function); |
| 603 } else { | 550 } else { |
| 604 __ Push(Smi::FromInt(0)); // no initial value! | 551 __ Push(Smi::FromInt(0)); // no initial value! |
| 605 } | 552 } |
| 606 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 553 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 607 break; | 554 break; |
| 608 } | 555 } |
| 609 } | 556 } |
| 610 | 557 |
| 611 } else if (prop != NULL) { | 558 } else if (prop != NULL) { |
| 612 if (function != NULL || mode == Variable::CONST) { | 559 if (function != NULL || mode == Variable::CONST) { |
| 613 // We are declaring a function or constant that rewrites to a | 560 // We are declaring a function or constant that rewrites to a |
| 614 // property. Use (keyed) IC to set the initial value. | 561 // property. Use (keyed) IC to set the initial value. |
| 615 VisitForValue(prop->obj(), kStack); | 562 VisitForStackValue(prop->obj()); |
| 616 if (function != NULL) { | 563 if (function != NULL) { |
| 617 VisitForValue(prop->key(), kStack); | 564 VisitForStackValue(prop->key()); |
| 618 VisitForValue(function, kAccumulator); | 565 VisitForAccumulatorValue(function); |
| 619 __ pop(rcx); | 566 __ pop(rcx); |
| 620 } else { | 567 } else { |
| 621 VisitForValue(prop->key(), kAccumulator); | 568 VisitForAccumulatorValue(prop->key()); |
| 622 __ movq(rcx, result_register()); | 569 __ movq(rcx, result_register()); |
| 623 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); | 570 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); |
| 624 } | 571 } |
| 625 __ pop(rdx); | 572 __ pop(rdx); |
| 626 | 573 |
| 627 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 574 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 628 __ call(ic, RelocInfo::CODE_TARGET); | 575 __ call(ic, RelocInfo::CODE_TARGET); |
| 629 // Absence of a test rax instruction following the call | 576 // Absence of a test rax instruction following the call |
| 630 // indicates that none of the load was inlined. | 577 // indicates that none of the load was inlined. |
| 631 __ nop(); | 578 __ nop(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 647 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 594 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 648 // Return value is ignored. | 595 // Return value is ignored. |
| 649 } | 596 } |
| 650 | 597 |
| 651 | 598 |
| 652 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 599 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 653 Comment cmnt(masm_, "[ SwitchStatement"); | 600 Comment cmnt(masm_, "[ SwitchStatement"); |
| 654 Breakable nested_statement(this, stmt); | 601 Breakable nested_statement(this, stmt); |
| 655 SetStatementPosition(stmt); | 602 SetStatementPosition(stmt); |
| 656 // Keep the switch value on the stack until a case matches. | 603 // Keep the switch value on the stack until a case matches. |
| 657 VisitForValue(stmt->tag(), kStack); | 604 VisitForStackValue(stmt->tag()); |
| 658 | 605 |
| 659 ZoneList<CaseClause*>* clauses = stmt->cases(); | 606 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 660 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 607 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 661 | 608 |
| 662 Label next_test; // Recycled for each test. | 609 Label next_test; // Recycled for each test. |
| 663 // Compile all the tests with branches to their bodies. | 610 // Compile all the tests with branches to their bodies. |
| 664 for (int i = 0; i < clauses->length(); i++) { | 611 for (int i = 0; i < clauses->length(); i++) { |
| 665 CaseClause* clause = clauses->at(i); | 612 CaseClause* clause = clauses->at(i); |
| 666 // The default is not a test, but remember it as final fall through. | 613 // The default is not a test, but remember it as final fall through. |
| 667 if (clause->is_default()) { | 614 if (clause->is_default()) { |
| 668 default_clause = clause; | 615 default_clause = clause; |
| 669 continue; | 616 continue; |
| 670 } | 617 } |
| 671 | 618 |
| 672 Comment cmnt(masm_, "[ Case comparison"); | 619 Comment cmnt(masm_, "[ Case comparison"); |
| 673 __ bind(&next_test); | 620 __ bind(&next_test); |
| 674 next_test.Unuse(); | 621 next_test.Unuse(); |
| 675 | 622 |
| 676 // Compile the label expression. | 623 // Compile the label expression. |
| 677 VisitForValue(clause->label(), kAccumulator); | 624 VisitForAccumulatorValue(clause->label()); |
| 678 | 625 |
| 679 // Perform the comparison as if via '==='. | 626 // Perform the comparison as if via '==='. |
| 680 if (ShouldInlineSmiCase(Token::EQ_STRICT)) { | 627 if (ShouldInlineSmiCase(Token::EQ_STRICT)) { |
| 681 Label slow_case; | 628 Label slow_case; |
| 682 __ movq(rdx, Operand(rsp, 0)); // Switch value. | 629 __ movq(rdx, Operand(rsp, 0)); // Switch value. |
| 683 __ JumpIfNotBothSmi(rdx, rax, &slow_case); | 630 __ JumpIfNotBothSmi(rdx, rax, &slow_case); |
| 684 __ SmiCompare(rdx, rax); | 631 __ SmiCompare(rdx, rax); |
| 685 __ j(not_equal, &next_test); | 632 __ j(not_equal, &next_test); |
| 686 __ Drop(1); // Switch value is no longer needed. | 633 __ Drop(1); // Switch value is no longer needed. |
| 687 __ jmp(clause->body_target()->entry_label()); | 634 __ jmp(clause->body_target()->entry_label()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 Comment cmnt(masm_, "[ ForInStatement"); | 669 Comment cmnt(masm_, "[ ForInStatement"); |
| 723 SetStatementPosition(stmt); | 670 SetStatementPosition(stmt); |
| 724 | 671 |
| 725 Label loop, exit; | 672 Label loop, exit; |
| 726 ForIn loop_statement(this, stmt); | 673 ForIn loop_statement(this, stmt); |
| 727 increment_loop_depth(); | 674 increment_loop_depth(); |
| 728 | 675 |
| 729 // Get the object to enumerate over. Both SpiderMonkey and JSC | 676 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 730 // ignore null and undefined in contrast to the specification; see | 677 // ignore null and undefined in contrast to the specification; see |
| 731 // ECMA-262 section 12.6.4. | 678 // ECMA-262 section 12.6.4. |
| 732 VisitForValue(stmt->enumerable(), kAccumulator); | 679 VisitForAccumulatorValue(stmt->enumerable()); |
| 733 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 680 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 734 __ j(equal, &exit); | 681 __ j(equal, &exit); |
| 735 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 682 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 736 __ j(equal, &exit); | 683 __ j(equal, &exit); |
| 737 | 684 |
| 738 // Convert the object to a JS object. | 685 // Convert the object to a JS object. |
| 739 Label convert, done_convert; | 686 Label convert, done_convert; |
| 740 __ JumpIfSmi(rax, &convert); | 687 __ JumpIfSmi(rax, &convert); |
| 741 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 688 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 742 __ j(above_equal, &done_convert); | 689 __ j(above_equal, &done_convert); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 860 // space for nested functions that don't need literals cloning. | 807 // space for nested functions that don't need literals cloning. |
| 861 if (scope()->is_function_scope() && info->num_literals() == 0) { | 808 if (scope()->is_function_scope() && info->num_literals() == 0) { |
| 862 FastNewClosureStub stub; | 809 FastNewClosureStub stub; |
| 863 __ Push(info); | 810 __ Push(info); |
| 864 __ CallStub(&stub); | 811 __ CallStub(&stub); |
| 865 } else { | 812 } else { |
| 866 __ push(rsi); | 813 __ push(rsi); |
| 867 __ Push(info); | 814 __ Push(info); |
| 868 __ CallRuntime(Runtime::kNewClosure, 2); | 815 __ CallRuntime(Runtime::kNewClosure, 2); |
| 869 } | 816 } |
| 870 Apply(context_, rax); | 817 context()->Plug(rax); |
| 871 } | 818 } |
| 872 | 819 |
| 873 | 820 |
| 874 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 821 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 875 Comment cmnt(masm_, "[ VariableProxy"); | 822 Comment cmnt(masm_, "[ VariableProxy"); |
| 876 EmitVariableLoad(expr->var(), context_); | 823 EmitVariableLoad(expr->var()); |
| 877 } | 824 } |
| 878 | 825 |
| 879 | 826 |
| 880 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( | 827 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( |
| 881 Slot* slot, | 828 Slot* slot, |
| 882 TypeofState typeof_state, | 829 TypeofState typeof_state, |
| 883 Label* slow) { | 830 Label* slow) { |
| 884 Register context = rsi; | 831 Register context = rsi; |
| 885 Register temp = rdx; | 832 Register temp = rdx; |
| 886 | 833 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 963 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1017 __ call(ic, RelocInfo::CODE_TARGET); | 964 __ call(ic, RelocInfo::CODE_TARGET); |
| 1018 __ jmp(done); | 965 __ jmp(done); |
| 1019 } | 966 } |
| 1020 } | 967 } |
| 1021 } | 968 } |
| 1022 } | 969 } |
| 1023 } | 970 } |
| 1024 | 971 |
| 1025 | 972 |
| 1026 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 973 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1027 Expression::Context context) { | |
| 1028 // Four cases: non-this global variables, lookup slots, all other | 974 // Four cases: non-this global variables, lookup slots, all other |
| 1029 // types of slots, and parameters that rewrite to explicit property | 975 // types of slots, and parameters that rewrite to explicit property |
| 1030 // accesses on the arguments object. | 976 // accesses on the arguments object. |
| 1031 Slot* slot = var->slot(); | 977 Slot* slot = var->slot(); |
| 1032 Property* property = var->AsProperty(); | 978 Property* property = var->AsProperty(); |
| 1033 | 979 |
| 1034 if (var->is_global() && !var->is_this()) { | 980 if (var->is_global() && !var->is_this()) { |
| 1035 Comment cmnt(masm_, "Global variable"); | 981 Comment cmnt(masm_, "Global variable"); |
| 1036 // Use inline caching. Variable name is passed in rcx and the global | 982 // Use inline caching. Variable name is passed in rcx and the global |
| 1037 // object on the stack. | 983 // object on the stack. |
| 1038 __ Move(rcx, var->name()); | 984 __ Move(rcx, var->name()); |
| 1039 __ movq(rax, CodeGenerator::GlobalObject()); | 985 __ movq(rax, CodeGenerator::GlobalObject()); |
| 1040 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 986 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1041 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 987 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1042 // A test rax instruction following the call is used by the IC to | 988 // A test rax instruction following the call is used by the IC to |
| 1043 // indicate that the inobject property case was inlined. Ensure there | 989 // indicate that the inobject property case was inlined. Ensure there |
| 1044 // is no test rax instruction here. | 990 // is no test rax instruction here. |
| 1045 __ nop(); | 991 __ nop(); |
| 1046 Apply(context, rax); | 992 context()->Plug(rax); |
| 1047 | 993 |
| 1048 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 994 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1049 Label done, slow; | 995 Label done, slow; |
| 1050 | 996 |
| 1051 // Generate code for loading from variables potentially shadowed | 997 // Generate code for loading from variables potentially shadowed |
| 1052 // by eval-introduced variables. | 998 // by eval-introduced variables. |
| 1053 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 999 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1054 | 1000 |
| 1055 __ bind(&slow); | 1001 __ bind(&slow); |
| 1056 Comment cmnt(masm_, "Lookup slot"); | 1002 Comment cmnt(masm_, "Lookup slot"); |
| 1057 __ push(rsi); // Context. | 1003 __ push(rsi); // Context. |
| 1058 __ Push(var->name()); | 1004 __ Push(var->name()); |
| 1059 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1005 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1060 __ bind(&done); | 1006 __ bind(&done); |
| 1061 | 1007 |
| 1062 Apply(context, rax); | 1008 context()->Plug(rax); |
| 1063 | 1009 |
| 1064 } else if (slot != NULL) { | 1010 } else if (slot != NULL) { |
| 1065 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1011 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1066 ? "Context slot" | 1012 ? "Context slot" |
| 1067 : "Stack slot"); | 1013 : "Stack slot"); |
| 1068 if (var->mode() == Variable::CONST) { | 1014 if (var->mode() == Variable::CONST) { |
| 1069 // Constants may be the hole value if they have not been initialized. | 1015 // Constants may be the hole value if they have not been initialized. |
| 1070 // Unhole them. | 1016 // Unhole them. |
| 1071 Label done; | 1017 Label done; |
| 1072 MemOperand slot_operand = EmitSlotSearch(slot, rax); | 1018 MemOperand slot_operand = EmitSlotSearch(slot, rax); |
| 1073 __ movq(rax, slot_operand); | 1019 __ movq(rax, slot_operand); |
| 1074 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1020 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1075 __ j(not_equal, &done); | 1021 __ j(not_equal, &done); |
| 1076 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1022 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1077 __ bind(&done); | 1023 __ bind(&done); |
| 1078 Apply(context, rax); | 1024 context()->Plug(rax); |
| 1079 } else { | 1025 } else { |
| 1080 Apply(context, slot); | 1026 context()->Plug(slot); |
| 1081 } | 1027 } |
| 1082 | 1028 |
| 1083 } else { | 1029 } else { |
| 1084 Comment cmnt(masm_, "Rewritten parameter"); | 1030 Comment cmnt(masm_, "Rewritten parameter"); |
| 1085 ASSERT_NOT_NULL(property); | 1031 ASSERT_NOT_NULL(property); |
| 1086 // Rewritten parameter accesses are of the form "slot[literal]". | 1032 // Rewritten parameter accesses are of the form "slot[literal]". |
| 1087 | 1033 |
| 1088 // Assert that the object is in a slot. | 1034 // Assert that the object is in a slot. |
| 1089 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | 1035 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 1090 ASSERT_NOT_NULL(object_var); | 1036 ASSERT_NOT_NULL(object_var); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1102 | 1048 |
| 1103 // Load the key. | 1049 // Load the key. |
| 1104 __ Move(rax, key_literal->handle()); | 1050 __ Move(rax, key_literal->handle()); |
| 1105 | 1051 |
| 1106 // Do a keyed property load. | 1052 // Do a keyed property load. |
| 1107 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1053 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1108 __ call(ic, RelocInfo::CODE_TARGET); | 1054 __ call(ic, RelocInfo::CODE_TARGET); |
| 1109 // Notice: We must not have a "test rax, ..." instruction after the | 1055 // Notice: We must not have a "test rax, ..." instruction after the |
| 1110 // call. It is treated specially by the LoadIC code. | 1056 // call. It is treated specially by the LoadIC code. |
| 1111 __ nop(); | 1057 __ nop(); |
| 1112 Apply(context, rax); | 1058 context()->Plug(rax); |
| 1113 } | 1059 } |
| 1114 } | 1060 } |
| 1115 | 1061 |
| 1116 | 1062 |
| 1117 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1063 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1118 Comment cmnt(masm_, "[ RegExpLiteral"); | 1064 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1119 Label materialized; | 1065 Label materialized; |
| 1120 // Registers will be used as follows: | 1066 // Registers will be used as follows: |
| 1121 // rdi = JS function. | 1067 // rdi = JS function. |
| 1122 // rcx = literals array. | 1068 // rcx = literals array. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1157 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { | 1103 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { |
| 1158 __ movq(rdx, FieldOperand(rbx, i)); | 1104 __ movq(rdx, FieldOperand(rbx, i)); |
| 1159 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); | 1105 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); |
| 1160 __ movq(FieldOperand(rax, i), rdx); | 1106 __ movq(FieldOperand(rax, i), rdx); |
| 1161 __ movq(FieldOperand(rax, i + kPointerSize), rcx); | 1107 __ movq(FieldOperand(rax, i + kPointerSize), rcx); |
| 1162 } | 1108 } |
| 1163 if ((size % (2 * kPointerSize)) != 0) { | 1109 if ((size % (2 * kPointerSize)) != 0) { |
| 1164 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); | 1110 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); |
| 1165 __ movq(FieldOperand(rax, size - kPointerSize), rdx); | 1111 __ movq(FieldOperand(rax, size - kPointerSize), rdx); |
| 1166 } | 1112 } |
| 1167 Apply(context_, rax); | 1113 context()->Plug(rax); |
| 1168 } | 1114 } |
| 1169 | 1115 |
| 1170 | 1116 |
| 1171 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 1117 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 1172 Comment cmnt(masm_, "[ ObjectLiteral"); | 1118 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 1173 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 1119 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1174 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 1120 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 1175 __ Push(Smi::FromInt(expr->literal_index())); | 1121 __ Push(Smi::FromInt(expr->literal_index())); |
| 1176 __ Push(expr->constant_properties()); | 1122 __ Push(expr->constant_properties()); |
| 1177 __ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0)); | 1123 __ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1196 result_saved = true; | 1142 result_saved = true; |
| 1197 } | 1143 } |
| 1198 switch (property->kind()) { | 1144 switch (property->kind()) { |
| 1199 case ObjectLiteral::Property::CONSTANT: | 1145 case ObjectLiteral::Property::CONSTANT: |
| 1200 UNREACHABLE(); | 1146 UNREACHABLE(); |
| 1201 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1147 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1202 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1148 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1203 // Fall through. | 1149 // Fall through. |
| 1204 case ObjectLiteral::Property::COMPUTED: | 1150 case ObjectLiteral::Property::COMPUTED: |
| 1205 if (key->handle()->IsSymbol()) { | 1151 if (key->handle()->IsSymbol()) { |
| 1206 VisitForValue(value, kAccumulator); | 1152 VisitForAccumulatorValue(value); |
| 1207 __ Move(rcx, key->handle()); | 1153 __ Move(rcx, key->handle()); |
| 1208 __ movq(rdx, Operand(rsp, 0)); | 1154 __ movq(rdx, Operand(rsp, 0)); |
| 1209 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1155 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1210 __ call(ic, RelocInfo::CODE_TARGET); | 1156 __ call(ic, RelocInfo::CODE_TARGET); |
| 1211 __ nop(); | 1157 __ nop(); |
| 1212 break; | 1158 break; |
| 1213 } | 1159 } |
| 1214 // Fall through. | 1160 // Fall through. |
| 1215 case ObjectLiteral::Property::PROTOTYPE: | 1161 case ObjectLiteral::Property::PROTOTYPE: |
| 1216 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1162 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1217 VisitForValue(key, kStack); | 1163 VisitForStackValue(key); |
| 1218 VisitForValue(value, kStack); | 1164 VisitForStackValue(value); |
| 1219 __ CallRuntime(Runtime::kSetProperty, 3); | 1165 __ CallRuntime(Runtime::kSetProperty, 3); |
| 1220 break; | 1166 break; |
| 1221 case ObjectLiteral::Property::SETTER: | 1167 case ObjectLiteral::Property::SETTER: |
| 1222 case ObjectLiteral::Property::GETTER: | 1168 case ObjectLiteral::Property::GETTER: |
| 1223 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1169 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1224 VisitForValue(key, kStack); | 1170 VisitForStackValue(key); |
| 1225 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 1171 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
| 1226 Smi::FromInt(1) : | 1172 Smi::FromInt(1) : |
| 1227 Smi::FromInt(0)); | 1173 Smi::FromInt(0)); |
| 1228 VisitForValue(value, kStack); | 1174 VisitForStackValue(value); |
| 1229 __ CallRuntime(Runtime::kDefineAccessor, 4); | 1175 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 1230 break; | 1176 break; |
| 1231 } | 1177 } |
| 1232 } | 1178 } |
| 1233 | 1179 |
| 1234 if (result_saved) { | 1180 if (result_saved) { |
| 1235 ApplyTOS(context_); | 1181 context()->PlugTOS(); |
| 1236 } else { | 1182 } else { |
| 1237 Apply(context_, rax); | 1183 context()->Plug(rax); |
| 1238 } | 1184 } |
| 1239 } | 1185 } |
| 1240 | 1186 |
| 1241 | 1187 |
| 1242 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1188 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 1243 Comment cmnt(masm_, "[ ArrayLiteral"); | 1189 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1244 | 1190 |
| 1245 ZoneList<Expression*>* subexprs = expr->values(); | 1191 ZoneList<Expression*>* subexprs = expr->values(); |
| 1246 int length = subexprs->length(); | 1192 int length = subexprs->length(); |
| 1247 | 1193 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1274 // is already set in the cloned array. | 1220 // is already set in the cloned array. |
| 1275 if (subexpr->AsLiteral() != NULL || | 1221 if (subexpr->AsLiteral() != NULL || |
| 1276 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 1222 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 1277 continue; | 1223 continue; |
| 1278 } | 1224 } |
| 1279 | 1225 |
| 1280 if (!result_saved) { | 1226 if (!result_saved) { |
| 1281 __ push(rax); | 1227 __ push(rax); |
| 1282 result_saved = true; | 1228 result_saved = true; |
| 1283 } | 1229 } |
| 1284 VisitForValue(subexpr, kAccumulator); | 1230 VisitForAccumulatorValue(subexpr); |
| 1285 | 1231 |
| 1286 // Store the subexpression value in the array's elements. | 1232 // Store the subexpression value in the array's elements. |
| 1287 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1233 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
| 1288 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1234 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 1289 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1235 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1290 __ movq(FieldOperand(rbx, offset), result_register()); | 1236 __ movq(FieldOperand(rbx, offset), result_register()); |
| 1291 | 1237 |
| 1292 // Update the write barrier for the array store. | 1238 // Update the write barrier for the array store. |
| 1293 __ RecordWrite(rbx, offset, result_register(), rcx); | 1239 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 1294 } | 1240 } |
| 1295 | 1241 |
| 1296 if (result_saved) { | 1242 if (result_saved) { |
| 1297 ApplyTOS(context_); | 1243 context()->PlugTOS(); |
| 1298 } else { | 1244 } else { |
| 1299 Apply(context_, rax); | 1245 context()->Plug(rax); |
| 1300 } | 1246 } |
| 1301 } | 1247 } |
| 1302 | 1248 |
| 1303 | 1249 |
| 1304 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1250 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1305 Comment cmnt(masm_, "[ Assignment"); | 1251 Comment cmnt(masm_, "[ Assignment"); |
| 1306 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1252 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1307 // on the left-hand side. | 1253 // on the left-hand side. |
| 1308 if (!expr->target()->IsValidLeftHandSide()) { | 1254 if (!expr->target()->IsValidLeftHandSide()) { |
| 1309 VisitForEffect(expr->target()); | 1255 VisitForEffect(expr->target()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1322 } | 1268 } |
| 1323 | 1269 |
| 1324 // Evaluate LHS expression. | 1270 // Evaluate LHS expression. |
| 1325 switch (assign_type) { | 1271 switch (assign_type) { |
| 1326 case VARIABLE: | 1272 case VARIABLE: |
| 1327 // Nothing to do here. | 1273 // Nothing to do here. |
| 1328 break; | 1274 break; |
| 1329 case NAMED_PROPERTY: | 1275 case NAMED_PROPERTY: |
| 1330 if (expr->is_compound()) { | 1276 if (expr->is_compound()) { |
| 1331 // We need the receiver both on the stack and in the accumulator. | 1277 // We need the receiver both on the stack and in the accumulator. |
| 1332 VisitForValue(property->obj(), kAccumulator); | 1278 VisitForAccumulatorValue(property->obj()); |
| 1333 __ push(result_register()); | 1279 __ push(result_register()); |
| 1334 } else { | 1280 } else { |
| 1335 VisitForValue(property->obj(), kStack); | 1281 VisitForStackValue(property->obj()); |
| 1336 } | 1282 } |
| 1337 break; | 1283 break; |
| 1338 case KEYED_PROPERTY: | 1284 case KEYED_PROPERTY: |
| 1339 if (expr->is_compound()) { | 1285 if (expr->is_compound()) { |
| 1340 VisitForValue(property->obj(), kStack); | 1286 VisitForStackValue(property->obj()); |
| 1341 VisitForValue(property->key(), kAccumulator); | 1287 VisitForAccumulatorValue(property->key()); |
| 1342 __ movq(rdx, Operand(rsp, 0)); | 1288 __ movq(rdx, Operand(rsp, 0)); |
| 1343 __ push(rax); | 1289 __ push(rax); |
| 1344 } else { | 1290 } else { |
| 1345 VisitForValue(property->obj(), kStack); | 1291 VisitForStackValue(property->obj()); |
| 1346 VisitForValue(property->key(), kStack); | 1292 VisitForStackValue(property->key()); |
| 1347 } | 1293 } |
| 1348 break; | 1294 break; |
| 1349 } | 1295 } |
| 1350 | 1296 |
| 1351 if (expr->is_compound()) { | 1297 if (expr->is_compound()) { |
| 1352 Location saved_location = location_; | 1298 { AccumulatorValueContext context(this); |
| 1353 location_ = kAccumulator; | 1299 switch (assign_type) { |
| 1354 switch (assign_type) { | 1300 case VARIABLE: |
| 1355 case VARIABLE: | 1301 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); |
| 1356 EmitVariableLoad(expr->target()->AsVariableProxy()->var(), | 1302 break; |
| 1357 Expression::kValue); | 1303 case NAMED_PROPERTY: |
| 1358 break; | 1304 EmitNamedPropertyLoad(property); |
| 1359 case NAMED_PROPERTY: | 1305 break; |
| 1360 EmitNamedPropertyLoad(property); | 1306 case KEYED_PROPERTY: |
| 1361 break; | 1307 EmitKeyedPropertyLoad(property); |
| 1362 case KEYED_PROPERTY: | 1308 break; |
| 1363 EmitKeyedPropertyLoad(property); | 1309 } |
| 1364 break; | |
| 1365 } | 1310 } |
| 1366 | 1311 |
| 1367 Token::Value op = expr->binary_op(); | 1312 Token::Value op = expr->binary_op(); |
| 1368 ConstantOperand constant = ShouldInlineSmiCase(op) | 1313 ConstantOperand constant = ShouldInlineSmiCase(op) |
| 1369 ? GetConstantOperand(op, expr->target(), expr->value()) | 1314 ? GetConstantOperand(op, expr->target(), expr->value()) |
| 1370 : kNoConstants; | 1315 : kNoConstants; |
| 1371 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1316 ASSERT(constant == kRightConstant || constant == kNoConstants); |
| 1372 if (constant == kNoConstants) { | 1317 if (constant == kNoConstants) { |
| 1373 __ push(rax); // Left operand goes on the stack. | 1318 __ push(rax); // Left operand goes on the stack. |
| 1374 VisitForValue(expr->value(), kAccumulator); | 1319 VisitForAccumulatorValue(expr->value()); |
| 1375 } | 1320 } |
| 1376 | 1321 |
| 1377 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1322 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1378 ? OVERWRITE_RIGHT | 1323 ? OVERWRITE_RIGHT |
| 1379 : NO_OVERWRITE; | 1324 : NO_OVERWRITE; |
| 1380 SetSourcePosition(expr->position() + 1); | 1325 SetSourcePosition(expr->position() + 1); |
| 1326 AccumulatorValueContext context(this); |
| 1381 if (ShouldInlineSmiCase(op)) { | 1327 if (ShouldInlineSmiCase(op)) { |
| 1382 EmitInlineSmiBinaryOp(expr, | 1328 EmitInlineSmiBinaryOp(expr, |
| 1383 op, | 1329 op, |
| 1384 Expression::kValue, | |
| 1385 mode, | 1330 mode, |
| 1386 expr->target(), | 1331 expr->target(), |
| 1387 expr->value(), | 1332 expr->value(), |
| 1388 constant); | 1333 constant); |
| 1389 } else { | 1334 } else { |
| 1390 EmitBinaryOp(op, Expression::kValue, mode); | 1335 EmitBinaryOp(op, mode); |
| 1391 } | 1336 } |
| 1392 location_ = saved_location; | |
| 1393 | |
| 1394 } else { | 1337 } else { |
| 1395 VisitForValue(expr->value(), kAccumulator); | 1338 VisitForAccumulatorValue(expr->value()); |
| 1396 } | 1339 } |
| 1397 | 1340 |
| 1398 // Record source position before possible IC call. | 1341 // Record source position before possible IC call. |
| 1399 SetSourcePosition(expr->position()); | 1342 SetSourcePosition(expr->position()); |
| 1400 | 1343 |
| 1401 // Store the value. | 1344 // Store the value. |
| 1402 switch (assign_type) { | 1345 switch (assign_type) { |
| 1403 case VARIABLE: | 1346 case VARIABLE: |
| 1404 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1347 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1405 expr->op(), | 1348 expr->op()); |
| 1406 context_); | |
| 1407 break; | 1349 break; |
| 1408 case NAMED_PROPERTY: | 1350 case NAMED_PROPERTY: |
| 1409 EmitNamedPropertyAssignment(expr); | 1351 EmitNamedPropertyAssignment(expr); |
| 1410 break; | 1352 break; |
| 1411 case KEYED_PROPERTY: | 1353 case KEYED_PROPERTY: |
| 1412 EmitKeyedPropertyAssignment(expr); | 1354 EmitKeyedPropertyAssignment(expr); |
| 1413 break; | 1355 break; |
| 1414 } | 1356 } |
| 1415 } | 1357 } |
| 1416 | 1358 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1428 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1370 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1429 SetSourcePosition(prop->position()); | 1371 SetSourcePosition(prop->position()); |
| 1430 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1372 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1431 __ Call(ic, RelocInfo::CODE_TARGET); | 1373 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1432 __ nop(); | 1374 __ nop(); |
| 1433 } | 1375 } |
| 1434 | 1376 |
| 1435 | 1377 |
| 1436 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1378 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
| 1437 Token::Value op, | 1379 Token::Value op, |
| 1438 Expression::Context context, | |
| 1439 OverwriteMode mode, | 1380 OverwriteMode mode, |
| 1440 Expression* left, | 1381 Expression* left, |
| 1441 Expression* right, | 1382 Expression* right, |
| 1442 ConstantOperand constant) { | 1383 ConstantOperand constant) { |
| 1443 ASSERT(constant == kNoConstants); // Only handled case. | 1384 ASSERT(constant == kNoConstants); // Only handled case. |
| 1444 | 1385 |
| 1445 // Do combined smi check of the operands. Left operand is on the | 1386 // Do combined smi check of the operands. Left operand is on the |
| 1446 // stack (popped into rdx). Right operand is in rax but moved into | 1387 // stack (popped into rdx). Right operand is in rax but moved into |
| 1447 // rcx to make the shifts easier. | 1388 // rcx to make the shifts easier. |
| 1448 Label done, stub_call, smi_case; | 1389 Label done, stub_call, smi_case; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1490 break; | 1431 break; |
| 1491 case Token::BIT_XOR: | 1432 case Token::BIT_XOR: |
| 1492 __ SmiXor(rax, rdx, rcx); | 1433 __ SmiXor(rax, rdx, rcx); |
| 1493 break; | 1434 break; |
| 1494 default: | 1435 default: |
| 1495 UNREACHABLE(); | 1436 UNREACHABLE(); |
| 1496 break; | 1437 break; |
| 1497 } | 1438 } |
| 1498 | 1439 |
| 1499 __ bind(&done); | 1440 __ bind(&done); |
| 1500 Apply(context, rax); | 1441 context()->Plug(rax); |
| 1501 } | 1442 } |
| 1502 | 1443 |
| 1503 | 1444 |
| 1504 void FullCodeGenerator::EmitBinaryOp(Token::Value op, | 1445 void FullCodeGenerator::EmitBinaryOp(Token::Value op, |
| 1505 Expression::Context context, | |
| 1506 OverwriteMode mode) { | 1446 OverwriteMode mode) { |
| 1507 GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS); | 1447 GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS); |
| 1508 if (stub.ArgsInRegistersSupported()) { | 1448 if (stub.ArgsInRegistersSupported()) { |
| 1509 __ pop(rdx); | 1449 __ pop(rdx); |
| 1510 stub.GenerateCall(masm_, rdx, rax); | 1450 stub.GenerateCall(masm_, rdx, rax); |
| 1511 } else { | 1451 } else { |
| 1512 __ push(result_register()); | 1452 __ push(result_register()); |
| 1513 __ CallStub(&stub); | 1453 __ CallStub(&stub); |
| 1514 } | 1454 } |
| 1515 Apply(context, rax); | 1455 context()->Plug(rax); |
| 1516 } | 1456 } |
| 1517 | 1457 |
| 1518 | 1458 |
| 1519 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 1459 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 1520 // Invalid left-hand sides are rewritten to have a 'throw | 1460 // Invalid left-hand sides are rewritten to have a 'throw |
| 1521 // ReferenceError' on the left-hand side. | 1461 // ReferenceError' on the left-hand side. |
| 1522 if (!expr->IsValidLeftHandSide()) { | 1462 if (!expr->IsValidLeftHandSide()) { |
| 1523 VisitForEffect(expr); | 1463 VisitForEffect(expr); |
| 1524 return; | 1464 return; |
| 1525 } | 1465 } |
| 1526 | 1466 |
| 1527 // Left-hand side can only be a property, a global or a (parameter or local) | 1467 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1528 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1468 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1529 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1469 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1530 LhsKind assign_type = VARIABLE; | 1470 LhsKind assign_type = VARIABLE; |
| 1531 Property* prop = expr->AsProperty(); | 1471 Property* prop = expr->AsProperty(); |
| 1532 if (prop != NULL) { | 1472 if (prop != NULL) { |
| 1533 assign_type = (prop->key()->IsPropertyName()) | 1473 assign_type = (prop->key()->IsPropertyName()) |
| 1534 ? NAMED_PROPERTY | 1474 ? NAMED_PROPERTY |
| 1535 : KEYED_PROPERTY; | 1475 : KEYED_PROPERTY; |
| 1536 } | 1476 } |
| 1537 | 1477 |
| 1538 switch (assign_type) { | 1478 switch (assign_type) { |
| 1539 case VARIABLE: { | 1479 case VARIABLE: { |
| 1540 Variable* var = expr->AsVariableProxy()->var(); | 1480 Variable* var = expr->AsVariableProxy()->var(); |
| 1541 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect); | 1481 EffectContext context(this); |
| 1482 EmitVariableAssignment(var, Token::ASSIGN); |
| 1542 break; | 1483 break; |
| 1543 } | 1484 } |
| 1544 case NAMED_PROPERTY: { | 1485 case NAMED_PROPERTY: { |
| 1545 __ push(rax); // Preserve value. | 1486 __ push(rax); // Preserve value. |
| 1546 VisitForValue(prop->obj(), kAccumulator); | 1487 VisitForAccumulatorValue(prop->obj()); |
| 1547 __ movq(rdx, rax); | 1488 __ movq(rdx, rax); |
| 1548 __ pop(rax); // Restore value. | 1489 __ pop(rax); // Restore value. |
| 1549 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1490 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1550 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1491 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1551 __ call(ic, RelocInfo::CODE_TARGET); | 1492 __ call(ic, RelocInfo::CODE_TARGET); |
| 1552 __ nop(); // Signal no inlined code. | 1493 __ nop(); // Signal no inlined code. |
| 1553 break; | 1494 break; |
| 1554 } | 1495 } |
| 1555 case KEYED_PROPERTY: { | 1496 case KEYED_PROPERTY: { |
| 1556 __ push(rax); // Preserve value. | 1497 __ push(rax); // Preserve value. |
| 1557 VisitForValue(prop->obj(), kStack); | 1498 VisitForStackValue(prop->obj()); |
| 1558 VisitForValue(prop->key(), kAccumulator); | 1499 VisitForAccumulatorValue(prop->key()); |
| 1559 __ movq(rcx, rax); | 1500 __ movq(rcx, rax); |
| 1560 __ pop(rdx); | 1501 __ pop(rdx); |
| 1561 __ pop(rax); | 1502 __ pop(rax); |
| 1562 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1503 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1563 __ call(ic, RelocInfo::CODE_TARGET); | 1504 __ call(ic, RelocInfo::CODE_TARGET); |
| 1564 __ nop(); // Signal no inlined code. | 1505 __ nop(); // Signal no inlined code. |
| 1565 break; | 1506 break; |
| 1566 } | 1507 } |
| 1567 } | 1508 } |
| 1568 } | 1509 } |
| 1569 | 1510 |
| 1570 | 1511 |
| 1571 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1512 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1572 Token::Value op, | 1513 Token::Value op) { |
| 1573 Expression::Context context) { | |
| 1574 // Left-hand sides that rewrite to explicit property accesses do not reach | 1514 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1575 // here. | 1515 // here. |
| 1576 ASSERT(var != NULL); | 1516 ASSERT(var != NULL); |
| 1577 ASSERT(var->is_global() || var->slot() != NULL); | 1517 ASSERT(var->is_global() || var->slot() != NULL); |
| 1578 | 1518 |
| 1579 if (var->is_global()) { | 1519 if (var->is_global()) { |
| 1580 ASSERT(!var->is_this()); | 1520 ASSERT(!var->is_this()); |
| 1581 // Assignment to a global variable. Use inline caching for the | 1521 // Assignment to a global variable. Use inline caching for the |
| 1582 // assignment. Right-hand-side value is passed in rax, variable name in | 1522 // assignment. Right-hand-side value is passed in rax, variable name in |
| 1583 // rcx, and the global object on the stack. | 1523 // rcx, and the global object on the stack. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1633 // The runtime will ignore const redeclaration. | 1573 // The runtime will ignore const redeclaration. |
| 1634 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1574 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1635 } else { | 1575 } else { |
| 1636 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1576 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 1637 } | 1577 } |
| 1638 break; | 1578 break; |
| 1639 } | 1579 } |
| 1640 __ bind(&done); | 1580 __ bind(&done); |
| 1641 } | 1581 } |
| 1642 | 1582 |
| 1643 Apply(context, rax); | 1583 context()->Plug(rax); |
| 1644 } | 1584 } |
| 1645 | 1585 |
| 1646 | 1586 |
| 1647 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1587 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 1648 // Assignment to a property, using a named store IC. | 1588 // Assignment to a property, using a named store IC. |
| 1649 Property* prop = expr->target()->AsProperty(); | 1589 Property* prop = expr->target()->AsProperty(); |
| 1650 ASSERT(prop != NULL); | 1590 ASSERT(prop != NULL); |
| 1651 ASSERT(prop->key()->AsLiteral() != NULL); | 1591 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1652 | 1592 |
| 1653 // If the assignment starts a block of assignments to the same object, | 1593 // If the assignment starts a block of assignments to the same object, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1671 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1611 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1672 __ Call(ic, RelocInfo::CODE_TARGET); | 1612 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1673 __ nop(); | 1613 __ nop(); |
| 1674 | 1614 |
| 1675 // If the assignment ends an initialization block, revert to fast case. | 1615 // If the assignment ends an initialization block, revert to fast case. |
| 1676 if (expr->ends_initialization_block()) { | 1616 if (expr->ends_initialization_block()) { |
| 1677 __ push(rax); // Result of assignment, saved even if not needed. | 1617 __ push(rax); // Result of assignment, saved even if not needed. |
| 1678 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1618 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 1679 __ CallRuntime(Runtime::kToFastProperties, 1); | 1619 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1680 __ pop(rax); | 1620 __ pop(rax); |
| 1681 DropAndApply(1, context_, rax); | 1621 context()->DropAndPlug(1, rax); |
| 1682 } else { | 1622 } else { |
| 1683 Apply(context_, rax); | 1623 context()->Plug(rax); |
| 1684 } | 1624 } |
| 1685 } | 1625 } |
| 1686 | 1626 |
| 1687 | 1627 |
| 1688 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1628 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 1689 // Assignment to a property, using a keyed store IC. | 1629 // Assignment to a property, using a keyed store IC. |
| 1690 | 1630 |
| 1691 // If the assignment starts a block of assignments to the same object, | 1631 // If the assignment starts a block of assignments to the same object, |
| 1692 // change to slow case to avoid the quadratic behavior of repeatedly | 1632 // change to slow case to avoid the quadratic behavior of repeatedly |
| 1693 // adding fast properties. | 1633 // adding fast properties. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1715 | 1655 |
| 1716 // If the assignment ends an initialization block, revert to fast case. | 1656 // If the assignment ends an initialization block, revert to fast case. |
| 1717 if (expr->ends_initialization_block()) { | 1657 if (expr->ends_initialization_block()) { |
| 1718 __ pop(rdx); | 1658 __ pop(rdx); |
| 1719 __ push(rax); // Result of assignment, saved even if not needed. | 1659 __ push(rax); // Result of assignment, saved even if not needed. |
| 1720 __ push(rdx); | 1660 __ push(rdx); |
| 1721 __ CallRuntime(Runtime::kToFastProperties, 1); | 1661 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1722 __ pop(rax); | 1662 __ pop(rax); |
| 1723 } | 1663 } |
| 1724 | 1664 |
| 1725 Apply(context_, rax); | 1665 context()->Plug(rax); |
| 1726 } | 1666 } |
| 1727 | 1667 |
| 1728 | 1668 |
| 1729 void FullCodeGenerator::VisitProperty(Property* expr) { | 1669 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 1730 Comment cmnt(masm_, "[ Property"); | 1670 Comment cmnt(masm_, "[ Property"); |
| 1731 Expression* key = expr->key(); | 1671 Expression* key = expr->key(); |
| 1732 | 1672 |
| 1733 if (key->IsPropertyName()) { | 1673 if (key->IsPropertyName()) { |
| 1734 VisitForValue(expr->obj(), kAccumulator); | 1674 VisitForAccumulatorValue(expr->obj()); |
| 1735 EmitNamedPropertyLoad(expr); | 1675 EmitNamedPropertyLoad(expr); |
| 1736 Apply(context_, rax); | 1676 context()->Plug(rax); |
| 1737 } else { | 1677 } else { |
| 1738 VisitForValue(expr->obj(), kStack); | 1678 VisitForStackValue(expr->obj()); |
| 1739 VisitForValue(expr->key(), kAccumulator); | 1679 VisitForAccumulatorValue(expr->key()); |
| 1740 __ pop(rdx); | 1680 __ pop(rdx); |
| 1741 EmitKeyedPropertyLoad(expr); | 1681 EmitKeyedPropertyLoad(expr); |
| 1742 Apply(context_, rax); | 1682 context()->Plug(rax); |
| 1743 } | 1683 } |
| 1744 } | 1684 } |
| 1745 | 1685 |
| 1746 | 1686 |
| 1747 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 1687 void FullCodeGenerator::EmitCallWithIC(Call* expr, |
| 1748 Handle<Object> name, | 1688 Handle<Object> name, |
| 1749 RelocInfo::Mode mode) { | 1689 RelocInfo::Mode mode) { |
| 1750 // Code common for calls using the IC. | 1690 // Code common for calls using the IC. |
| 1751 ZoneList<Expression*>* args = expr->arguments(); | 1691 ZoneList<Expression*>* args = expr->arguments(); |
| 1752 int arg_count = args->length(); | 1692 int arg_count = args->length(); |
| 1753 for (int i = 0; i < arg_count; i++) { | 1693 for (int i = 0; i < arg_count; i++) { |
| 1754 VisitForValue(args->at(i), kStack); | 1694 VisitForStackValue(args->at(i)); |
| 1755 } | 1695 } |
| 1756 __ Move(rcx, name); | 1696 __ Move(rcx, name); |
| 1757 // Record source position for debugger. | 1697 // Record source position for debugger. |
| 1758 SetSourcePosition(expr->position()); | 1698 SetSourcePosition(expr->position()); |
| 1759 // Call the IC initialization code. | 1699 // Call the IC initialization code. |
| 1760 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1700 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1761 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1701 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 1762 in_loop); | 1702 in_loop); |
| 1763 __ Call(ic, mode); | 1703 __ Call(ic, mode); |
| 1764 // Restore context register. | 1704 // Restore context register. |
| 1765 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1705 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1766 Apply(context_, rax); | 1706 context()->Plug(rax); |
| 1767 } | 1707 } |
| 1768 | 1708 |
| 1769 | 1709 |
| 1770 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 1710 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 1771 Expression* key, | 1711 Expression* key, |
| 1772 RelocInfo::Mode mode) { | 1712 RelocInfo::Mode mode) { |
| 1773 // Code common for calls using the IC. | 1713 // Code common for calls using the IC. |
| 1774 ZoneList<Expression*>* args = expr->arguments(); | 1714 ZoneList<Expression*>* args = expr->arguments(); |
| 1775 int arg_count = args->length(); | 1715 int arg_count = args->length(); |
| 1776 for (int i = 0; i < arg_count; i++) { | 1716 for (int i = 0; i < arg_count; i++) { |
| 1777 VisitForValue(args->at(i), kStack); | 1717 VisitForStackValue(args->at(i)); |
| 1778 } | 1718 } |
| 1779 VisitForValue(key, kAccumulator); | 1719 VisitForAccumulatorValue(key); |
| 1780 __ movq(rcx, rax); | 1720 __ movq(rcx, rax); |
| 1781 // Record source position for debugger. | 1721 // Record source position for debugger. |
| 1782 SetSourcePosition(expr->position()); | 1722 SetSourcePosition(expr->position()); |
| 1783 // Call the IC initialization code. | 1723 // Call the IC initialization code. |
| 1784 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1724 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1785 Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count, | 1725 Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count, |
| 1786 in_loop); | 1726 in_loop); |
| 1787 __ Call(ic, mode); | 1727 __ Call(ic, mode); |
| 1788 // Restore context register. | 1728 // Restore context register. |
| 1789 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1729 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1790 Apply(context_, rax); | 1730 context()->Plug(rax); |
| 1791 } | 1731 } |
| 1792 | 1732 |
| 1793 | 1733 |
| 1794 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 1734 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 1795 // Code common for calls using the call stub. | 1735 // Code common for calls using the call stub. |
| 1796 ZoneList<Expression*>* args = expr->arguments(); | 1736 ZoneList<Expression*>* args = expr->arguments(); |
| 1797 int arg_count = args->length(); | 1737 int arg_count = args->length(); |
| 1798 for (int i = 0; i < arg_count; i++) { | 1738 for (int i = 0; i < arg_count; i++) { |
| 1799 VisitForValue(args->at(i), kStack); | 1739 VisitForStackValue(args->at(i)); |
| 1800 } | 1740 } |
| 1801 // Record source position for debugger. | 1741 // Record source position for debugger. |
| 1802 SetSourcePosition(expr->position()); | 1742 SetSourcePosition(expr->position()); |
| 1803 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1743 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1804 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1744 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1805 __ CallStub(&stub); | 1745 __ CallStub(&stub); |
| 1806 // Restore context register. | 1746 // Restore context register. |
| 1807 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1747 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1808 // Discard the function left on TOS. | 1748 // Discard the function left on TOS. |
| 1809 DropAndApply(1, context_, rax); | 1749 context()->DropAndPlug(1, rax); |
| 1810 } | 1750 } |
| 1811 | 1751 |
| 1812 | 1752 |
| 1813 void FullCodeGenerator::VisitCall(Call* expr) { | 1753 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1814 Comment cmnt(masm_, "[ Call"); | 1754 Comment cmnt(masm_, "[ Call"); |
| 1815 Expression* fun = expr->expression(); | 1755 Expression* fun = expr->expression(); |
| 1816 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1756 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 1817 | 1757 |
| 1818 if (var != NULL && var->is_possibly_eval()) { | 1758 if (var != NULL && var->is_possibly_eval()) { |
| 1819 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 1759 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 1820 // resolve the function we need to call and the receiver of the | 1760 // resolve the function we need to call and the receiver of the |
| 1821 // call. The we call the resolved function using the given | 1761 // call. The we call the resolved function using the given |
| 1822 // arguments. | 1762 // arguments. |
| 1823 VisitForValue(fun, kStack); | 1763 VisitForStackValue(fun); |
| 1824 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. | 1764 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. |
| 1825 | 1765 |
| 1826 // Push the arguments. | 1766 // Push the arguments. |
| 1827 ZoneList<Expression*>* args = expr->arguments(); | 1767 ZoneList<Expression*>* args = expr->arguments(); |
| 1828 int arg_count = args->length(); | 1768 int arg_count = args->length(); |
| 1829 for (int i = 0; i < arg_count; i++) { | 1769 for (int i = 0; i < arg_count; i++) { |
| 1830 VisitForValue(args->at(i), kStack); | 1770 VisitForStackValue(args->at(i)); |
| 1831 } | 1771 } |
| 1832 | 1772 |
| 1833 // Push copy of the function - found below the arguments. | 1773 // Push copy of the function - found below the arguments. |
| 1834 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); | 1774 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 1835 | 1775 |
| 1836 // Push copy of the first argument or undefined if it doesn't exist. | 1776 // Push copy of the first argument or undefined if it doesn't exist. |
| 1837 if (arg_count > 0) { | 1777 if (arg_count > 0) { |
| 1838 __ push(Operand(rsp, arg_count * kPointerSize)); | 1778 __ push(Operand(rsp, arg_count * kPointerSize)); |
| 1839 } else { | 1779 } else { |
| 1840 __ PushRoot(Heap::kUndefinedValueRootIndex); | 1780 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1841 } | 1781 } |
| 1842 | 1782 |
| 1843 // Push the receiver of the enclosing function and do runtime call. | 1783 // Push the receiver of the enclosing function and do runtime call. |
| 1844 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); | 1784 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 1845 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); | 1785 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); |
| 1846 | 1786 |
| 1847 // The runtime call returns a pair of values in rax (function) and | 1787 // The runtime call returns a pair of values in rax (function) and |
| 1848 // rdx (receiver). Touch up the stack with the right values. | 1788 // rdx (receiver). Touch up the stack with the right values. |
| 1849 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); | 1789 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); |
| 1850 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); | 1790 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); |
| 1851 | 1791 |
| 1852 // Record source position for debugger. | 1792 // Record source position for debugger. |
| 1853 SetSourcePosition(expr->position()); | 1793 SetSourcePosition(expr->position()); |
| 1854 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1794 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1855 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1795 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1856 __ CallStub(&stub); | 1796 __ CallStub(&stub); |
| 1857 // Restore context register. | 1797 // Restore context register. |
| 1858 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1798 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1859 DropAndApply(1, context_, rax); | 1799 context()->DropAndPlug(1, rax); |
| 1860 } else if (var != NULL && !var->is_this() && var->is_global()) { | 1800 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 1861 // Call to a global variable. | 1801 // Call to a global variable. |
| 1862 // Push global object as receiver for the call IC lookup. | 1802 // Push global object as receiver for the call IC lookup. |
| 1863 __ push(CodeGenerator::GlobalObject()); | 1803 __ push(CodeGenerator::GlobalObject()); |
| 1864 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 1804 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
| 1865 } else if (var != NULL && var->slot() != NULL && | 1805 } else if (var != NULL && var->slot() != NULL && |
| 1866 var->slot()->type() == Slot::LOOKUP) { | 1806 var->slot()->type() == Slot::LOOKUP) { |
| 1867 // Call to a lookup slot (dynamically introduced variable). | 1807 // Call to a lookup slot (dynamically introduced variable). |
| 1868 Label slow, done; | 1808 Label slow, done; |
| 1869 | 1809 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1899 } | 1839 } |
| 1900 | 1840 |
| 1901 EmitCallWithStub(expr); | 1841 EmitCallWithStub(expr); |
| 1902 | 1842 |
| 1903 } else if (fun->AsProperty() != NULL) { | 1843 } else if (fun->AsProperty() != NULL) { |
| 1904 // Call to an object property. | 1844 // Call to an object property. |
| 1905 Property* prop = fun->AsProperty(); | 1845 Property* prop = fun->AsProperty(); |
| 1906 Literal* key = prop->key()->AsLiteral(); | 1846 Literal* key = prop->key()->AsLiteral(); |
| 1907 if (key != NULL && key->handle()->IsSymbol()) { | 1847 if (key != NULL && key->handle()->IsSymbol()) { |
| 1908 // Call to a named property, use call IC. | 1848 // Call to a named property, use call IC. |
| 1909 VisitForValue(prop->obj(), kStack); | 1849 VisitForStackValue(prop->obj()); |
| 1910 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1850 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 1911 } else { | 1851 } else { |
| 1912 // Call to a keyed property. | 1852 // Call to a keyed property. |
| 1913 // For a synthetic property use keyed load IC followed by function call, | 1853 // For a synthetic property use keyed load IC followed by function call, |
| 1914 // for a regular property use KeyedCallIC. | 1854 // for a regular property use KeyedCallIC. |
| 1915 VisitForValue(prop->obj(), kStack); | 1855 VisitForStackValue(prop->obj()); |
| 1916 if (prop->is_synthetic()) { | 1856 if (prop->is_synthetic()) { |
| 1917 VisitForValue(prop->key(), kAccumulator); | 1857 VisitForAccumulatorValue(prop->key()); |
| 1918 __ movq(rdx, Operand(rsp, 0)); | 1858 __ movq(rdx, Operand(rsp, 0)); |
| 1919 // Record source code position for IC call. | 1859 // Record source code position for IC call. |
| 1920 SetSourcePosition(prop->position()); | 1860 SetSourcePosition(prop->position()); |
| 1921 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1861 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1922 __ call(ic, RelocInfo::CODE_TARGET); | 1862 __ call(ic, RelocInfo::CODE_TARGET); |
| 1923 // By emitting a nop we make sure that we do not have a "test rax,..." | 1863 // By emitting a nop we make sure that we do not have a "test rax,..." |
| 1924 // instruction after the call as it is treated specially | 1864 // instruction after the call as it is treated specially |
| 1925 // by the LoadIC code. | 1865 // by the LoadIC code. |
| 1926 __ nop(); | 1866 __ nop(); |
| 1927 // Pop receiver. | 1867 // Pop receiver. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1939 } else { | 1879 } else { |
| 1940 // Call to some other expression. If the expression is an anonymous | 1880 // Call to some other expression. If the expression is an anonymous |
| 1941 // function literal not called in a loop, mark it as one that should | 1881 // function literal not called in a loop, mark it as one that should |
| 1942 // also use the fast code generator. | 1882 // also use the fast code generator. |
| 1943 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 1883 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 1944 if (lit != NULL && | 1884 if (lit != NULL && |
| 1945 lit->name()->Equals(Heap::empty_string()) && | 1885 lit->name()->Equals(Heap::empty_string()) && |
| 1946 loop_depth() == 0) { | 1886 loop_depth() == 0) { |
| 1947 lit->set_try_full_codegen(true); | 1887 lit->set_try_full_codegen(true); |
| 1948 } | 1888 } |
| 1949 VisitForValue(fun, kStack); | 1889 VisitForStackValue(fun); |
| 1950 // Load global receiver object. | 1890 // Load global receiver object. |
| 1951 __ movq(rbx, CodeGenerator::GlobalObject()); | 1891 __ movq(rbx, CodeGenerator::GlobalObject()); |
| 1952 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 1892 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
| 1953 // Emit function call. | 1893 // Emit function call. |
| 1954 EmitCallWithStub(expr); | 1894 EmitCallWithStub(expr); |
| 1955 } | 1895 } |
| 1956 } | 1896 } |
| 1957 | 1897 |
| 1958 | 1898 |
| 1959 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 1899 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 1960 Comment cmnt(masm_, "[ CallNew"); | 1900 Comment cmnt(masm_, "[ CallNew"); |
| 1961 // According to ECMA-262, section 11.2.2, page 44, the function | 1901 // According to ECMA-262, section 11.2.2, page 44, the function |
| 1962 // expression in new calls must be evaluated before the | 1902 // expression in new calls must be evaluated before the |
| 1963 // arguments. | 1903 // arguments. |
| 1964 | 1904 |
| 1965 // Push constructor on the stack. If it's not a function it's used as | 1905 // Push constructor on the stack. If it's not a function it's used as |
| 1966 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is | 1906 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is |
| 1967 // ignored. | 1907 // ignored. |
| 1968 VisitForValue(expr->expression(), kStack); | 1908 VisitForStackValue(expr->expression()); |
| 1969 | 1909 |
| 1970 // Push the arguments ("left-to-right") on the stack. | 1910 // Push the arguments ("left-to-right") on the stack. |
| 1971 ZoneList<Expression*>* args = expr->arguments(); | 1911 ZoneList<Expression*>* args = expr->arguments(); |
| 1972 int arg_count = args->length(); | 1912 int arg_count = args->length(); |
| 1973 for (int i = 0; i < arg_count; i++) { | 1913 for (int i = 0; i < arg_count; i++) { |
| 1974 VisitForValue(args->at(i), kStack); | 1914 VisitForStackValue(args->at(i)); |
| 1975 } | 1915 } |
| 1976 | 1916 |
| 1977 // Call the construct call builtin that handles allocation and | 1917 // Call the construct call builtin that handles allocation and |
| 1978 // constructor invocation. | 1918 // constructor invocation. |
| 1979 SetSourcePosition(expr->position()); | 1919 SetSourcePosition(expr->position()); |
| 1980 | 1920 |
| 1981 // Load function and argument count into rdi and rax. | 1921 // Load function and argument count into rdi and rax. |
| 1982 __ Set(rax, arg_count); | 1922 __ Set(rax, arg_count); |
| 1983 __ movq(rdi, Operand(rsp, arg_count * kPointerSize)); | 1923 __ movq(rdi, Operand(rsp, arg_count * kPointerSize)); |
| 1984 | 1924 |
| 1985 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 1925 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); |
| 1986 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 1926 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 1987 Apply(context_, rax); | 1927 context()->Plug(rax); |
| 1988 } | 1928 } |
| 1989 | 1929 |
| 1990 | 1930 |
| 1991 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { | 1931 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { |
| 1992 ASSERT(args->length() == 1); | 1932 ASSERT(args->length() == 1); |
| 1993 | 1933 |
| 1994 VisitForValue(args->at(0), kAccumulator); | 1934 VisitForAccumulatorValue(args->at(0)); |
| 1995 | 1935 |
| 1996 Label materialize_true, materialize_false; | 1936 Label materialize_true, materialize_false; |
| 1997 Label* if_true = NULL; | 1937 Label* if_true = NULL; |
| 1998 Label* if_false = NULL; | 1938 Label* if_false = NULL; |
| 1999 Label* fall_through = NULL; | 1939 Label* fall_through = NULL; |
| 2000 PrepareTest(&materialize_true, &materialize_false, | 1940 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2001 &if_true, &if_false, &fall_through); | 1941 &if_true, &if_false, &fall_through); |
| 2002 | 1942 |
| 2003 __ JumpIfSmi(rax, if_true); | 1943 __ JumpIfSmi(rax, if_true); |
| 2004 __ jmp(if_false); | 1944 __ jmp(if_false); |
| 2005 | 1945 |
| 2006 Apply(context_, if_true, if_false); | 1946 context()->Plug(if_true, if_false); |
| 2007 } | 1947 } |
| 2008 | 1948 |
| 2009 | 1949 |
| 2010 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 1950 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2011 ASSERT(args->length() == 1); | 1951 ASSERT(args->length() == 1); |
| 2012 | 1952 |
| 2013 VisitForValue(args->at(0), kAccumulator); | 1953 VisitForAccumulatorValue(args->at(0)); |
| 2014 | 1954 |
| 2015 Label materialize_true, materialize_false; | 1955 Label materialize_true, materialize_false; |
| 2016 Label* if_true = NULL; | 1956 Label* if_true = NULL; |
| 2017 Label* if_false = NULL; | 1957 Label* if_false = NULL; |
| 2018 Label* fall_through = NULL; | 1958 Label* fall_through = NULL; |
| 2019 PrepareTest(&materialize_true, &materialize_false, | 1959 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2020 &if_true, &if_false, &fall_through); | 1960 &if_true, &if_false, &fall_through); |
| 2021 | 1961 |
| 2022 Condition positive_smi = __ CheckPositiveSmi(rax); | 1962 Condition positive_smi = __ CheckPositiveSmi(rax); |
| 2023 Split(positive_smi, if_true, if_false, fall_through); | 1963 Split(positive_smi, if_true, if_false, fall_through); |
| 2024 | 1964 |
| 2025 Apply(context_, if_true, if_false); | 1965 context()->Plug(if_true, if_false); |
| 2026 } | 1966 } |
| 2027 | 1967 |
| 2028 | 1968 |
| 2029 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 1969 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
| 2030 ASSERT(args->length() == 1); | 1970 ASSERT(args->length() == 1); |
| 2031 | 1971 |
| 2032 VisitForValue(args->at(0), kAccumulator); | 1972 VisitForAccumulatorValue(args->at(0)); |
| 2033 | 1973 |
| 2034 Label materialize_true, materialize_false; | 1974 Label materialize_true, materialize_false; |
| 2035 Label* if_true = NULL; | 1975 Label* if_true = NULL; |
| 2036 Label* if_false = NULL; | 1976 Label* if_false = NULL; |
| 2037 Label* fall_through = NULL; | 1977 Label* fall_through = NULL; |
| 2038 PrepareTest(&materialize_true, &materialize_false, | 1978 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2039 &if_true, &if_false, &fall_through); | 1979 &if_true, &if_false, &fall_through); |
| 2040 | 1980 |
| 2041 __ JumpIfSmi(rax, if_false); | 1981 __ JumpIfSmi(rax, if_false); |
| 2042 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 1982 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 2043 __ j(equal, if_true); | 1983 __ j(equal, if_true); |
| 2044 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 1984 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2045 // Undetectable objects behave like undefined when tested with typeof. | 1985 // Undetectable objects behave like undefined when tested with typeof. |
| 2046 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 1986 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2047 Immediate(1 << Map::kIsUndetectable)); | 1987 Immediate(1 << Map::kIsUndetectable)); |
| 2048 __ j(not_zero, if_false); | 1988 __ j(not_zero, if_false); |
| 2049 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1989 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2050 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 1990 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 2051 __ j(below, if_false); | 1991 __ j(below, if_false); |
| 2052 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 1992 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); |
| 2053 Split(below_equal, if_true, if_false, fall_through); | 1993 Split(below_equal, if_true, if_false, fall_through); |
| 2054 | 1994 |
| 2055 Apply(context_, if_true, if_false); | 1995 context()->Plug(if_true, if_false); |
| 2056 } | 1996 } |
| 2057 | 1997 |
| 2058 | 1998 |
| 2059 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 1999 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2060 ASSERT(args->length() == 1); | 2000 ASSERT(args->length() == 1); |
| 2061 | 2001 |
| 2062 VisitForValue(args->at(0), kAccumulator); | 2002 VisitForAccumulatorValue(args->at(0)); |
| 2063 | 2003 |
| 2064 Label materialize_true, materialize_false; | 2004 Label materialize_true, materialize_false; |
| 2065 Label* if_true = NULL; | 2005 Label* if_true = NULL; |
| 2066 Label* if_false = NULL; | 2006 Label* if_false = NULL; |
| 2067 Label* fall_through = NULL; | 2007 Label* fall_through = NULL; |
| 2068 PrepareTest(&materialize_true, &materialize_false, | 2008 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2069 &if_true, &if_false, &fall_through); | 2009 &if_true, &if_false, &fall_through); |
| 2070 | 2010 |
| 2071 __ JumpIfSmi(rax, if_false); | 2011 __ JumpIfSmi(rax, if_false); |
| 2072 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2012 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2073 Split(above_equal, if_true, if_false, fall_through); | 2013 Split(above_equal, if_true, if_false, fall_through); |
| 2074 | 2014 |
| 2075 Apply(context_, if_true, if_false); | 2015 context()->Plug(if_true, if_false); |
| 2076 } | 2016 } |
| 2077 | 2017 |
| 2078 | 2018 |
| 2079 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2019 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2080 ASSERT(args->length() == 1); | 2020 ASSERT(args->length() == 1); |
| 2081 | 2021 |
| 2082 VisitForValue(args->at(0), kAccumulator); | 2022 VisitForAccumulatorValue(args->at(0)); |
| 2083 | 2023 |
| 2084 Label materialize_true, materialize_false; | 2024 Label materialize_true, materialize_false; |
| 2085 Label* if_true = NULL; | 2025 Label* if_true = NULL; |
| 2086 Label* if_false = NULL; | 2026 Label* if_false = NULL; |
| 2087 Label* fall_through = NULL; | 2027 Label* fall_through = NULL; |
| 2088 PrepareTest(&materialize_true, &materialize_false, | 2028 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2089 &if_true, &if_false, &fall_through); | 2029 &if_true, &if_false, &fall_through); |
| 2090 | 2030 |
| 2091 __ JumpIfSmi(rax, if_false); | 2031 __ JumpIfSmi(rax, if_false); |
| 2092 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2032 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2093 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2033 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2094 Immediate(1 << Map::kIsUndetectable)); | 2034 Immediate(1 << Map::kIsUndetectable)); |
| 2095 Split(not_zero, if_true, if_false, fall_through); | 2035 Split(not_zero, if_true, if_false, fall_through); |
| 2096 | 2036 |
| 2097 Apply(context_, if_true, if_false); | 2037 context()->Plug(if_true, if_false); |
| 2098 } | 2038 } |
| 2099 | 2039 |
| 2100 | 2040 |
| 2101 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2041 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
| 2102 ZoneList<Expression*>* args) { | 2042 ZoneList<Expression*>* args) { |
| 2103 ASSERT(args->length() == 1); | 2043 ASSERT(args->length() == 1); |
| 2104 | 2044 |
| 2105 VisitForValue(args->at(0), kAccumulator); | 2045 VisitForAccumulatorValue(args->at(0)); |
| 2106 | 2046 |
| 2107 Label materialize_true, materialize_false; | 2047 Label materialize_true, materialize_false; |
| 2108 Label* if_true = NULL; | 2048 Label* if_true = NULL; |
| 2109 Label* if_false = NULL; | 2049 Label* if_false = NULL; |
| 2110 Label* fall_through = NULL; | 2050 Label* fall_through = NULL; |
| 2111 PrepareTest(&materialize_true, &materialize_false, | 2051 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2112 &if_true, &if_false, &fall_through); | 2052 &if_true, &if_false, &fall_through); |
| 2113 | 2053 |
| 2114 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2054 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
| 2115 // used in a few functions in runtime.js which should not normally be hit by | 2055 // used in a few functions in runtime.js which should not normally be hit by |
| 2116 // this compiler. | 2056 // this compiler. |
| 2117 __ jmp(if_false); | 2057 __ jmp(if_false); |
| 2118 Apply(context_, if_true, if_false); | 2058 context()->Plug(if_true, if_false); |
| 2119 } | 2059 } |
| 2120 | 2060 |
| 2121 | 2061 |
| 2122 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2062 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
| 2123 ASSERT(args->length() == 1); | 2063 ASSERT(args->length() == 1); |
| 2124 | 2064 |
| 2125 VisitForValue(args->at(0), kAccumulator); | 2065 VisitForAccumulatorValue(args->at(0)); |
| 2126 | 2066 |
| 2127 Label materialize_true, materialize_false; | 2067 Label materialize_true, materialize_false; |
| 2128 Label* if_true = NULL; | 2068 Label* if_true = NULL; |
| 2129 Label* if_false = NULL; | 2069 Label* if_false = NULL; |
| 2130 Label* fall_through = NULL; | 2070 Label* fall_through = NULL; |
| 2131 PrepareTest(&materialize_true, &materialize_false, | 2071 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2132 &if_true, &if_false, &fall_through); | 2072 &if_true, &if_false, &fall_through); |
| 2133 | 2073 |
| 2134 __ JumpIfSmi(rax, if_false); | 2074 __ JumpIfSmi(rax, if_false); |
| 2135 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2075 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2136 Split(equal, if_true, if_false, fall_through); | 2076 Split(equal, if_true, if_false, fall_through); |
| 2137 | 2077 |
| 2138 Apply(context_, if_true, if_false); | 2078 context()->Plug(if_true, if_false); |
| 2139 } | 2079 } |
| 2140 | 2080 |
| 2141 | 2081 |
| 2142 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2082 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2143 ASSERT(args->length() == 1); | 2083 ASSERT(args->length() == 1); |
| 2144 | 2084 |
| 2145 VisitForValue(args->at(0), kAccumulator); | 2085 VisitForAccumulatorValue(args->at(0)); |
| 2146 | 2086 |
| 2147 Label materialize_true, materialize_false; | 2087 Label materialize_true, materialize_false; |
| 2148 Label* if_true = NULL; | 2088 Label* if_true = NULL; |
| 2149 Label* if_false = NULL; | 2089 Label* if_false = NULL; |
| 2150 Label* fall_through = NULL; | 2090 Label* fall_through = NULL; |
| 2151 PrepareTest(&materialize_true, &materialize_false, | 2091 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2152 &if_true, &if_false, &fall_through); | 2092 &if_true, &if_false, &fall_through); |
| 2153 | 2093 |
| 2154 __ JumpIfSmi(rax, if_false); | 2094 __ JumpIfSmi(rax, if_false); |
| 2155 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); | 2095 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); |
| 2156 Split(equal, if_true, if_false, fall_through); | 2096 Split(equal, if_true, if_false, fall_through); |
| 2157 | 2097 |
| 2158 Apply(context_, if_true, if_false); | 2098 context()->Plug(if_true, if_false); |
| 2159 } | 2099 } |
| 2160 | 2100 |
| 2161 | 2101 |
| 2162 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2102 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2163 ASSERT(args->length() == 1); | 2103 ASSERT(args->length() == 1); |
| 2164 | 2104 |
| 2165 VisitForValue(args->at(0), kAccumulator); | 2105 VisitForAccumulatorValue(args->at(0)); |
| 2166 | 2106 |
| 2167 Label materialize_true, materialize_false; | 2107 Label materialize_true, materialize_false; |
| 2168 Label* if_true = NULL; | 2108 Label* if_true = NULL; |
| 2169 Label* if_false = NULL; | 2109 Label* if_false = NULL; |
| 2170 Label* fall_through = NULL; | 2110 Label* fall_through = NULL; |
| 2171 PrepareTest(&materialize_true, &materialize_false, | 2111 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2172 &if_true, &if_false, &fall_through); | 2112 &if_true, &if_false, &fall_through); |
| 2173 | 2113 |
| 2174 __ JumpIfSmi(rax, if_false); | 2114 __ JumpIfSmi(rax, if_false); |
| 2175 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); | 2115 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); |
| 2176 Split(equal, if_true, if_false, fall_through); | 2116 Split(equal, if_true, if_false, fall_through); |
| 2177 | 2117 |
| 2178 Apply(context_, if_true, if_false); | 2118 context()->Plug(if_true, if_false); |
| 2179 } | 2119 } |
| 2180 | 2120 |
| 2181 | 2121 |
| 2182 | 2122 |
| 2183 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2123 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| 2184 ASSERT(args->length() == 0); | 2124 ASSERT(args->length() == 0); |
| 2185 | 2125 |
| 2186 Label materialize_true, materialize_false; | 2126 Label materialize_true, materialize_false; |
| 2187 Label* if_true = NULL; | 2127 Label* if_true = NULL; |
| 2188 Label* if_false = NULL; | 2128 Label* if_false = NULL; |
| 2189 Label* fall_through = NULL; | 2129 Label* fall_through = NULL; |
| 2190 PrepareTest(&materialize_true, &materialize_false, | 2130 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2191 &if_true, &if_false, &fall_through); | 2131 &if_true, &if_false, &fall_through); |
| 2192 | 2132 |
| 2193 // Get the frame pointer for the calling frame. | 2133 // Get the frame pointer for the calling frame. |
| 2194 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2134 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2195 | 2135 |
| 2196 // Skip the arguments adaptor frame if it exists. | 2136 // Skip the arguments adaptor frame if it exists. |
| 2197 Label check_frame_marker; | 2137 Label check_frame_marker; |
| 2198 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2138 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), |
| 2199 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2139 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2200 __ j(not_equal, &check_frame_marker); | 2140 __ j(not_equal, &check_frame_marker); |
| 2201 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2141 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 2202 | 2142 |
| 2203 // Check the marker in the calling frame. | 2143 // Check the marker in the calling frame. |
| 2204 __ bind(&check_frame_marker); | 2144 __ bind(&check_frame_marker); |
| 2205 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2145 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), |
| 2206 Smi::FromInt(StackFrame::CONSTRUCT)); | 2146 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2207 Split(equal, if_true, if_false, fall_through); | 2147 Split(equal, if_true, if_false, fall_through); |
| 2208 | 2148 |
| 2209 Apply(context_, if_true, if_false); | 2149 context()->Plug(if_true, if_false); |
| 2210 } | 2150 } |
| 2211 | 2151 |
| 2212 | 2152 |
| 2213 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2153 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2214 ASSERT(args->length() == 2); | 2154 ASSERT(args->length() == 2); |
| 2215 | 2155 |
| 2216 // Load the two objects into registers and perform the comparison. | 2156 // Load the two objects into registers and perform the comparison. |
| 2217 VisitForValue(args->at(0), kStack); | 2157 VisitForStackValue(args->at(0)); |
| 2218 VisitForValue(args->at(1), kAccumulator); | 2158 VisitForAccumulatorValue(args->at(1)); |
| 2219 | 2159 |
| 2220 Label materialize_true, materialize_false; | 2160 Label materialize_true, materialize_false; |
| 2221 Label* if_true = NULL; | 2161 Label* if_true = NULL; |
| 2222 Label* if_false = NULL; | 2162 Label* if_false = NULL; |
| 2223 Label* fall_through = NULL; | 2163 Label* fall_through = NULL; |
| 2224 PrepareTest(&materialize_true, &materialize_false, | 2164 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2225 &if_true, &if_false, &fall_through); | 2165 &if_true, &if_false, &fall_through); |
| 2226 | 2166 |
| 2227 __ pop(rbx); | 2167 __ pop(rbx); |
| 2228 __ cmpq(rax, rbx); | 2168 __ cmpq(rax, rbx); |
| 2229 Split(equal, if_true, if_false, fall_through); | 2169 Split(equal, if_true, if_false, fall_through); |
| 2230 | 2170 |
| 2231 Apply(context_, if_true, if_false); | 2171 context()->Plug(if_true, if_false); |
| 2232 } | 2172 } |
| 2233 | 2173 |
| 2234 | 2174 |
| 2235 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2175 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2236 ASSERT(args->length() == 1); | 2176 ASSERT(args->length() == 1); |
| 2237 | 2177 |
| 2238 // ArgumentsAccessStub expects the key in rdx and the formal | 2178 // ArgumentsAccessStub expects the key in rdx and the formal |
| 2239 // parameter count in rax. | 2179 // parameter count in rax. |
| 2240 VisitForValue(args->at(0), kAccumulator); | 2180 VisitForAccumulatorValue(args->at(0)); |
| 2241 __ movq(rdx, rax); | 2181 __ movq(rdx, rax); |
| 2242 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2182 __ Move(rax, Smi::FromInt(scope()->num_parameters())); |
| 2243 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2183 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2244 __ CallStub(&stub); | 2184 __ CallStub(&stub); |
| 2245 Apply(context_, rax); | 2185 context()->Plug(rax); |
| 2246 } | 2186 } |
| 2247 | 2187 |
| 2248 | 2188 |
| 2249 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2189 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2250 ASSERT(args->length() == 0); | 2190 ASSERT(args->length() == 0); |
| 2251 | 2191 |
| 2252 Label exit; | 2192 Label exit; |
| 2253 // Get the number of formal parameters. | 2193 // Get the number of formal parameters. |
| 2254 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2194 __ Move(rax, Smi::FromInt(scope()->num_parameters())); |
| 2255 | 2195 |
| 2256 // Check if the calling frame is an arguments adaptor frame. | 2196 // Check if the calling frame is an arguments adaptor frame. |
| 2257 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2197 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2258 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), | 2198 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 2259 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2199 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2260 __ j(not_equal, &exit); | 2200 __ j(not_equal, &exit); |
| 2261 | 2201 |
| 2262 // Arguments adaptor case: Read the arguments length from the | 2202 // Arguments adaptor case: Read the arguments length from the |
| 2263 // adaptor frame. | 2203 // adaptor frame. |
| 2264 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2204 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2265 | 2205 |
| 2266 __ bind(&exit); | 2206 __ bind(&exit); |
| 2267 if (FLAG_debug_code) __ AbortIfNotSmi(rax); | 2207 if (FLAG_debug_code) __ AbortIfNotSmi(rax); |
| 2268 Apply(context_, rax); | 2208 context()->Plug(rax); |
| 2269 } | 2209 } |
| 2270 | 2210 |
| 2271 | 2211 |
| 2272 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { | 2212 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
| 2273 ASSERT(args->length() == 1); | 2213 ASSERT(args->length() == 1); |
| 2274 Label done, null, function, non_function_constructor; | 2214 Label done, null, function, non_function_constructor; |
| 2275 | 2215 |
| 2276 VisitForValue(args->at(0), kAccumulator); | 2216 VisitForAccumulatorValue(args->at(0)); |
| 2277 | 2217 |
| 2278 // If the object is a smi, we return null. | 2218 // If the object is a smi, we return null. |
| 2279 __ JumpIfSmi(rax, &null); | 2219 __ JumpIfSmi(rax, &null); |
| 2280 | 2220 |
| 2281 // Check that the object is a JS object but take special care of JS | 2221 // Check that the object is a JS object but take special care of JS |
| 2282 // functions to make sure they have 'Function' as their class. | 2222 // functions to make sure they have 'Function' as their class. |
| 2283 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); // Map is now in rax. | 2223 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); // Map is now in rax. |
| 2284 __ j(below, &null); | 2224 __ j(below, &null); |
| 2285 | 2225 |
| 2286 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 2226 // As long as JS_FUNCTION_TYPE is the last instance type and it is |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2312 __ Move(rax, Factory::Object_symbol()); | 2252 __ Move(rax, Factory::Object_symbol()); |
| 2313 __ jmp(&done); | 2253 __ jmp(&done); |
| 2314 | 2254 |
| 2315 // Non-JS objects have class null. | 2255 // Non-JS objects have class null. |
| 2316 __ bind(&null); | 2256 __ bind(&null); |
| 2317 __ LoadRoot(rax, Heap::kNullValueRootIndex); | 2257 __ LoadRoot(rax, Heap::kNullValueRootIndex); |
| 2318 | 2258 |
| 2319 // All done. | 2259 // All done. |
| 2320 __ bind(&done); | 2260 __ bind(&done); |
| 2321 | 2261 |
| 2322 Apply(context_, rax); | 2262 context()->Plug(rax); |
| 2323 } | 2263 } |
| 2324 | 2264 |
| 2325 | 2265 |
| 2326 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { | 2266 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { |
| 2327 // Conditionally generate a log call. | 2267 // Conditionally generate a log call. |
| 2328 // Args: | 2268 // Args: |
| 2329 // 0 (literal string): The type of logging (corresponds to the flags). | 2269 // 0 (literal string): The type of logging (corresponds to the flags). |
| 2330 // This is used to determine whether or not to generate the log call. | 2270 // This is used to determine whether or not to generate the log call. |
| 2331 // 1 (string): Format string. Access the string at argument index 2 | 2271 // 1 (string): Format string. Access the string at argument index 2 |
| 2332 // with '%2s' (see Logger::LogRuntime for all the formats). | 2272 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 2333 // 2 (array): Arguments to the format string. | 2273 // 2 (array): Arguments to the format string. |
| 2334 ASSERT_EQ(args->length(), 3); | 2274 ASSERT_EQ(args->length(), 3); |
| 2335 #ifdef ENABLE_LOGGING_AND_PROFILING | 2275 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2336 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { | 2276 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { |
| 2337 VisitForValue(args->at(1), kStack); | 2277 VisitForStackValue(args->at(1)); |
| 2338 VisitForValue(args->at(2), kStack); | 2278 VisitForStackValue(args->at(2)); |
| 2339 __ CallRuntime(Runtime::kLog, 2); | 2279 __ CallRuntime(Runtime::kLog, 2); |
| 2340 } | 2280 } |
| 2341 #endif | 2281 #endif |
| 2342 // Finally, we're expected to leave a value on the top of the stack. | 2282 // Finally, we're expected to leave a value on the top of the stack. |
| 2343 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 2283 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 2344 Apply(context_, rax); | 2284 context()->Plug(rax); |
| 2345 } | 2285 } |
| 2346 | 2286 |
| 2347 | 2287 |
| 2348 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { | 2288 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { |
| 2349 ASSERT(args->length() == 0); | 2289 ASSERT(args->length() == 0); |
| 2350 | 2290 |
| 2351 Label slow_allocate_heapnumber; | 2291 Label slow_allocate_heapnumber; |
| 2352 Label heapnumber_allocated; | 2292 Label heapnumber_allocated; |
| 2353 | 2293 |
| 2354 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber); | 2294 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2371 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 2311 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 2372 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 2312 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 2373 __ movd(xmm1, rcx); | 2313 __ movd(xmm1, rcx); |
| 2374 __ movd(xmm0, rax); | 2314 __ movd(xmm0, rax); |
| 2375 __ cvtss2sd(xmm1, xmm1); | 2315 __ cvtss2sd(xmm1, xmm1); |
| 2376 __ xorpd(xmm0, xmm1); | 2316 __ xorpd(xmm0, xmm1); |
| 2377 __ subsd(xmm0, xmm1); | 2317 __ subsd(xmm0, xmm1); |
| 2378 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); | 2318 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); |
| 2379 | 2319 |
| 2380 __ movq(rax, rbx); | 2320 __ movq(rax, rbx); |
| 2381 Apply(context_, rax); | 2321 context()->Plug(rax); |
| 2382 } | 2322 } |
| 2383 | 2323 |
| 2384 | 2324 |
| 2385 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) { | 2325 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) { |
| 2386 // Load the arguments on the stack and call the stub. | 2326 // Load the arguments on the stack and call the stub. |
| 2387 SubStringStub stub; | 2327 SubStringStub stub; |
| 2388 ASSERT(args->length() == 3); | 2328 ASSERT(args->length() == 3); |
| 2389 VisitForValue(args->at(0), kStack); | 2329 VisitForStackValue(args->at(0)); |
| 2390 VisitForValue(args->at(1), kStack); | 2330 VisitForStackValue(args->at(1)); |
| 2391 VisitForValue(args->at(2), kStack); | 2331 VisitForStackValue(args->at(2)); |
| 2392 __ CallStub(&stub); | 2332 __ CallStub(&stub); |
| 2393 Apply(context_, rax); | 2333 context()->Plug(rax); |
| 2394 } | 2334 } |
| 2395 | 2335 |
| 2396 | 2336 |
| 2397 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) { | 2337 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) { |
| 2398 // Load the arguments on the stack and call the stub. | 2338 // Load the arguments on the stack and call the stub. |
| 2399 RegExpExecStub stub; | 2339 RegExpExecStub stub; |
| 2400 ASSERT(args->length() == 4); | 2340 ASSERT(args->length() == 4); |
| 2401 VisitForValue(args->at(0), kStack); | 2341 VisitForStackValue(args->at(0)); |
| 2402 VisitForValue(args->at(1), kStack); | 2342 VisitForStackValue(args->at(1)); |
| 2403 VisitForValue(args->at(2), kStack); | 2343 VisitForStackValue(args->at(2)); |
| 2404 VisitForValue(args->at(3), kStack); | 2344 VisitForStackValue(args->at(3)); |
| 2405 __ CallStub(&stub); | 2345 __ CallStub(&stub); |
| 2406 Apply(context_, rax); | 2346 context()->Plug(rax); |
| 2407 } | 2347 } |
| 2408 | 2348 |
| 2409 | 2349 |
| 2410 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { | 2350 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { |
| 2411 ASSERT(args->length() == 1); | 2351 ASSERT(args->length() == 1); |
| 2412 | 2352 |
| 2413 VisitForValue(args->at(0), kAccumulator); // Load the object. | 2353 VisitForAccumulatorValue(args->at(0)); // Load the object. |
| 2414 | 2354 |
| 2415 Label done; | 2355 Label done; |
| 2416 // If the object is a smi return the object. | 2356 // If the object is a smi return the object. |
| 2417 __ JumpIfSmi(rax, &done); | 2357 __ JumpIfSmi(rax, &done); |
| 2418 // If the object is not a value type, return the object. | 2358 // If the object is not a value type, return the object. |
| 2419 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx); | 2359 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx); |
| 2420 __ j(not_equal, &done); | 2360 __ j(not_equal, &done); |
| 2421 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset)); | 2361 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset)); |
| 2422 | 2362 |
| 2423 __ bind(&done); | 2363 __ bind(&done); |
| 2424 Apply(context_, rax); | 2364 context()->Plug(rax); |
| 2425 } | 2365 } |
| 2426 | 2366 |
| 2427 | 2367 |
| 2428 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { | 2368 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { |
| 2429 // Load the arguments on the stack and call the runtime function. | 2369 // Load the arguments on the stack and call the runtime function. |
| 2430 ASSERT(args->length() == 2); | 2370 ASSERT(args->length() == 2); |
| 2431 VisitForValue(args->at(0), kStack); | 2371 VisitForStackValue(args->at(0)); |
| 2432 VisitForValue(args->at(1), kStack); | 2372 VisitForStackValue(args->at(1)); |
| 2433 __ CallRuntime(Runtime::kMath_pow, 2); | 2373 __ CallRuntime(Runtime::kMath_pow, 2); |
| 2434 Apply(context_, rax); | 2374 context()->Plug(rax); |
| 2435 } | 2375 } |
| 2436 | 2376 |
| 2437 | 2377 |
| 2438 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { | 2378 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2439 ASSERT(args->length() == 2); | 2379 ASSERT(args->length() == 2); |
| 2440 | 2380 |
| 2441 VisitForValue(args->at(0), kStack); // Load the object. | 2381 VisitForStackValue(args->at(0)); // Load the object. |
| 2442 VisitForValue(args->at(1), kAccumulator); // Load the value. | 2382 VisitForAccumulatorValue(args->at(1)); // Load the value. |
| 2443 __ pop(rbx); // rax = value. rbx = object. | 2383 __ pop(rbx); // rax = value. rbx = object. |
| 2444 | 2384 |
| 2445 Label done; | 2385 Label done; |
| 2446 // If the object is a smi, return the value. | 2386 // If the object is a smi, return the value. |
| 2447 __ JumpIfSmi(rbx, &done); | 2387 __ JumpIfSmi(rbx, &done); |
| 2448 | 2388 |
| 2449 // If the object is not a value type, return the value. | 2389 // If the object is not a value type, return the value. |
| 2450 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); | 2390 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); |
| 2451 __ j(not_equal, &done); | 2391 __ j(not_equal, &done); |
| 2452 | 2392 |
| 2453 // Store the value. | 2393 // Store the value. |
| 2454 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); | 2394 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); |
| 2455 // Update the write barrier. Save the value as it will be | 2395 // Update the write barrier. Save the value as it will be |
| 2456 // overwritten by the write barrier code and is needed afterward. | 2396 // overwritten by the write barrier code and is needed afterward. |
| 2457 __ movq(rdx, rax); | 2397 __ movq(rdx, rax); |
| 2458 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx); | 2398 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx); |
| 2459 | 2399 |
| 2460 __ bind(&done); | 2400 __ bind(&done); |
| 2461 Apply(context_, rax); | 2401 context()->Plug(rax); |
| 2462 } | 2402 } |
| 2463 | 2403 |
| 2464 | 2404 |
| 2465 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2405 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
| 2466 ASSERT_EQ(args->length(), 1); | 2406 ASSERT_EQ(args->length(), 1); |
| 2467 | 2407 |
| 2468 // Load the argument on the stack and call the stub. | 2408 // Load the argument on the stack and call the stub. |
| 2469 VisitForValue(args->at(0), kStack); | 2409 VisitForStackValue(args->at(0)); |
| 2470 | 2410 |
| 2471 NumberToStringStub stub; | 2411 NumberToStringStub stub; |
| 2472 __ CallStub(&stub); | 2412 __ CallStub(&stub); |
| 2473 Apply(context_, rax); | 2413 context()->Plug(rax); |
| 2474 } | 2414 } |
| 2475 | 2415 |
| 2476 | 2416 |
| 2477 void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) { | 2417 void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) { |
| 2478 ASSERT(args->length() == 1); | 2418 ASSERT(args->length() == 1); |
| 2479 | 2419 |
| 2480 VisitForValue(args->at(0), kAccumulator); | 2420 VisitForAccumulatorValue(args->at(0)); |
| 2481 | 2421 |
| 2482 Label done; | 2422 Label done; |
| 2483 StringCharFromCodeGenerator generator(rax, rbx); | 2423 StringCharFromCodeGenerator generator(rax, rbx); |
| 2484 generator.GenerateFast(masm_); | 2424 generator.GenerateFast(masm_); |
| 2485 __ jmp(&done); | 2425 __ jmp(&done); |
| 2486 | 2426 |
| 2487 NopRuntimeCallHelper call_helper; | 2427 NopRuntimeCallHelper call_helper; |
| 2488 generator.GenerateSlow(masm_, call_helper); | 2428 generator.GenerateSlow(masm_, call_helper); |
| 2489 | 2429 |
| 2490 __ bind(&done); | 2430 __ bind(&done); |
| 2491 Apply(context_, rbx); | 2431 context()->Plug(rbx); |
| 2492 } | 2432 } |
| 2493 | 2433 |
| 2494 | 2434 |
| 2495 void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) { | 2435 void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) { |
| 2496 ASSERT(args->length() == 2); | 2436 ASSERT(args->length() == 2); |
| 2497 | 2437 |
| 2498 VisitForValue(args->at(0), kStack); | 2438 VisitForStackValue(args->at(0)); |
| 2499 VisitForValue(args->at(1), kAccumulator); | 2439 VisitForAccumulatorValue(args->at(1)); |
| 2500 | 2440 |
| 2501 Register object = rbx; | 2441 Register object = rbx; |
| 2502 Register index = rax; | 2442 Register index = rax; |
| 2503 Register scratch = rcx; | 2443 Register scratch = rcx; |
| 2504 Register result = rdx; | 2444 Register result = rdx; |
| 2505 | 2445 |
| 2506 __ pop(object); | 2446 __ pop(object); |
| 2507 | 2447 |
| 2508 Label need_conversion; | 2448 Label need_conversion; |
| 2509 Label index_out_of_range; | 2449 Label index_out_of_range; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2528 __ bind(&need_conversion); | 2468 __ bind(&need_conversion); |
| 2529 // Move the undefined value into the result register, which will | 2469 // Move the undefined value into the result register, which will |
| 2530 // trigger conversion. | 2470 // trigger conversion. |
| 2531 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | 2471 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
| 2532 __ jmp(&done); | 2472 __ jmp(&done); |
| 2533 | 2473 |
| 2534 NopRuntimeCallHelper call_helper; | 2474 NopRuntimeCallHelper call_helper; |
| 2535 generator.GenerateSlow(masm_, call_helper); | 2475 generator.GenerateSlow(masm_, call_helper); |
| 2536 | 2476 |
| 2537 __ bind(&done); | 2477 __ bind(&done); |
| 2538 Apply(context_, result); | 2478 context()->Plug(result); |
| 2539 } | 2479 } |
| 2540 | 2480 |
| 2541 | 2481 |
| 2542 void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) { | 2482 void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) { |
| 2543 ASSERT(args->length() == 2); | 2483 ASSERT(args->length() == 2); |
| 2544 | 2484 |
| 2545 VisitForValue(args->at(0), kStack); | 2485 VisitForStackValue(args->at(0)); |
| 2546 VisitForValue(args->at(1), kAccumulator); | 2486 VisitForAccumulatorValue(args->at(1)); |
| 2547 | 2487 |
| 2548 Register object = rbx; | 2488 Register object = rbx; |
| 2549 Register index = rax; | 2489 Register index = rax; |
| 2550 Register scratch1 = rcx; | 2490 Register scratch1 = rcx; |
| 2551 Register scratch2 = rdx; | 2491 Register scratch2 = rdx; |
| 2552 Register result = rax; | 2492 Register result = rax; |
| 2553 | 2493 |
| 2554 __ pop(object); | 2494 __ pop(object); |
| 2555 | 2495 |
| 2556 Label need_conversion; | 2496 Label need_conversion; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2577 __ bind(&need_conversion); | 2517 __ bind(&need_conversion); |
| 2578 // Move smi zero into the result register, which will trigger | 2518 // Move smi zero into the result register, which will trigger |
| 2579 // conversion. | 2519 // conversion. |
| 2580 __ Move(result, Smi::FromInt(0)); | 2520 __ Move(result, Smi::FromInt(0)); |
| 2581 __ jmp(&done); | 2521 __ jmp(&done); |
| 2582 | 2522 |
| 2583 NopRuntimeCallHelper call_helper; | 2523 NopRuntimeCallHelper call_helper; |
| 2584 generator.GenerateSlow(masm_, call_helper); | 2524 generator.GenerateSlow(masm_, call_helper); |
| 2585 | 2525 |
| 2586 __ bind(&done); | 2526 __ bind(&done); |
| 2587 Apply(context_, result); | 2527 context()->Plug(result); |
| 2588 } | 2528 } |
| 2589 | 2529 |
| 2590 | 2530 |
| 2591 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) { | 2531 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) { |
| 2592 ASSERT_EQ(2, args->length()); | 2532 ASSERT_EQ(2, args->length()); |
| 2593 | 2533 |
| 2594 VisitForValue(args->at(0), kStack); | 2534 VisitForStackValue(args->at(0)); |
| 2595 VisitForValue(args->at(1), kStack); | 2535 VisitForStackValue(args->at(1)); |
| 2596 | 2536 |
| 2597 StringAddStub stub(NO_STRING_ADD_FLAGS); | 2537 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 2598 __ CallStub(&stub); | 2538 __ CallStub(&stub); |
| 2599 Apply(context_, rax); | 2539 context()->Plug(rax); |
| 2600 } | 2540 } |
| 2601 | 2541 |
| 2602 | 2542 |
| 2603 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) { | 2543 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) { |
| 2604 ASSERT_EQ(2, args->length()); | 2544 ASSERT_EQ(2, args->length()); |
| 2605 | 2545 |
| 2606 VisitForValue(args->at(0), kStack); | 2546 VisitForStackValue(args->at(0)); |
| 2607 VisitForValue(args->at(1), kStack); | 2547 VisitForStackValue(args->at(1)); |
| 2608 | 2548 |
| 2609 StringCompareStub stub; | 2549 StringCompareStub stub; |
| 2610 __ CallStub(&stub); | 2550 __ CallStub(&stub); |
| 2611 Apply(context_, rax); | 2551 context()->Plug(rax); |
| 2612 } | 2552 } |
| 2613 | 2553 |
| 2614 | 2554 |
| 2615 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { | 2555 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { |
| 2616 // Load the argument on the stack and call the stub. | 2556 // Load the argument on the stack and call the stub. |
| 2617 TranscendentalCacheStub stub(TranscendentalCache::SIN); | 2557 TranscendentalCacheStub stub(TranscendentalCache::SIN); |
| 2618 ASSERT(args->length() == 1); | 2558 ASSERT(args->length() == 1); |
| 2619 VisitForValue(args->at(0), kStack); | 2559 VisitForStackValue(args->at(0)); |
| 2620 __ CallStub(&stub); | 2560 __ CallStub(&stub); |
| 2621 Apply(context_, rax); | 2561 context()->Plug(rax); |
| 2622 } | 2562 } |
| 2623 | 2563 |
| 2624 | 2564 |
| 2625 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { | 2565 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { |
| 2626 // Load the argument on the stack and call the stub. | 2566 // Load the argument on the stack and call the stub. |
| 2627 TranscendentalCacheStub stub(TranscendentalCache::COS); | 2567 TranscendentalCacheStub stub(TranscendentalCache::COS); |
| 2628 ASSERT(args->length() == 1); | 2568 ASSERT(args->length() == 1); |
| 2629 VisitForValue(args->at(0), kStack); | 2569 VisitForStackValue(args->at(0)); |
| 2630 __ CallStub(&stub); | 2570 __ CallStub(&stub); |
| 2631 Apply(context_, rax); | 2571 context()->Plug(rax); |
| 2632 } | 2572 } |
| 2633 | 2573 |
| 2634 | 2574 |
| 2635 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { | 2575 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { |
| 2636 // Load the argument on the stack and call the runtime function. | 2576 // Load the argument on the stack and call the runtime function. |
| 2637 ASSERT(args->length() == 1); | 2577 ASSERT(args->length() == 1); |
| 2638 VisitForValue(args->at(0), kStack); | 2578 VisitForStackValue(args->at(0)); |
| 2639 __ CallRuntime(Runtime::kMath_sqrt, 1); | 2579 __ CallRuntime(Runtime::kMath_sqrt, 1); |
| 2640 Apply(context_, rax); | 2580 context()->Plug(rax); |
| 2641 } | 2581 } |
| 2642 | 2582 |
| 2643 | 2583 |
| 2644 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) { | 2584 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) { |
| 2645 ASSERT(args->length() >= 2); | 2585 ASSERT(args->length() >= 2); |
| 2646 | 2586 |
| 2647 int arg_count = args->length() - 2; // For receiver and function. | 2587 int arg_count = args->length() - 2; // For receiver and function. |
| 2648 VisitForValue(args->at(0), kStack); // Receiver. | 2588 VisitForStackValue(args->at(0)); // Receiver. |
| 2649 for (int i = 0; i < arg_count; i++) { | 2589 for (int i = 0; i < arg_count; i++) { |
| 2650 VisitForValue(args->at(i + 1), kStack); | 2590 VisitForStackValue(args->at(i + 1)); |
| 2651 } | 2591 } |
| 2652 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function. | 2592 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function. |
| 2653 | 2593 |
| 2654 // InvokeFunction requires function in rdi. Move it in there. | 2594 // InvokeFunction requires function in rdi. Move it in there. |
| 2655 if (!result_register().is(rdi)) __ movq(rdi, result_register()); | 2595 if (!result_register().is(rdi)) __ movq(rdi, result_register()); |
| 2656 ParameterCount count(arg_count); | 2596 ParameterCount count(arg_count); |
| 2657 __ InvokeFunction(rdi, count, CALL_FUNCTION); | 2597 __ InvokeFunction(rdi, count, CALL_FUNCTION); |
| 2658 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2598 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2659 Apply(context_, rax); | 2599 context()->Plug(rax); |
| 2660 } | 2600 } |
| 2661 | 2601 |
| 2662 | 2602 |
| 2663 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { | 2603 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 2664 ASSERT(args->length() == 3); | 2604 ASSERT(args->length() == 3); |
| 2665 VisitForValue(args->at(0), kStack); | 2605 VisitForStackValue(args->at(0)); |
| 2666 VisitForValue(args->at(1), kStack); | 2606 VisitForStackValue(args->at(1)); |
| 2667 VisitForValue(args->at(2), kStack); | 2607 VisitForStackValue(args->at(2)); |
| 2668 __ CallRuntime(Runtime::kRegExpConstructResult, 3); | 2608 __ CallRuntime(Runtime::kRegExpConstructResult, 3); |
| 2669 Apply(context_, rax); | 2609 context()->Plug(rax); |
| 2670 } | 2610 } |
| 2671 | 2611 |
| 2672 | 2612 |
| 2673 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { | 2613 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { |
| 2674 ASSERT(args->length() == 3); | 2614 ASSERT(args->length() == 3); |
| 2675 VisitForValue(args->at(0), kStack); | 2615 VisitForStackValue(args->at(0)); |
| 2676 VisitForValue(args->at(1), kStack); | 2616 VisitForStackValue(args->at(1)); |
| 2677 VisitForValue(args->at(2), kStack); | 2617 VisitForStackValue(args->at(2)); |
| 2678 __ CallRuntime(Runtime::kSwapElements, 3); | 2618 __ CallRuntime(Runtime::kSwapElements, 3); |
| 2679 Apply(context_, rax); | 2619 context()->Plug(rax); |
| 2680 } | 2620 } |
| 2681 | 2621 |
| 2682 | 2622 |
| 2683 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { | 2623 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
| 2684 ASSERT_EQ(2, args->length()); | 2624 ASSERT_EQ(2, args->length()); |
| 2685 | 2625 |
| 2686 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 2626 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 2687 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 2627 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 2688 | 2628 |
| 2689 Handle<FixedArray> jsfunction_result_caches( | 2629 Handle<FixedArray> jsfunction_result_caches( |
| 2690 Top::global_context()->jsfunction_result_caches()); | 2630 Top::global_context()->jsfunction_result_caches()); |
| 2691 if (jsfunction_result_caches->length() <= cache_id) { | 2631 if (jsfunction_result_caches->length() <= cache_id) { |
| 2692 __ Abort("Attempt to use undefined cache."); | 2632 __ Abort("Attempt to use undefined cache."); |
| 2693 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 2633 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 2694 Apply(context_, rax); | 2634 context()->Plug(rax); |
| 2695 return; | 2635 return; |
| 2696 } | 2636 } |
| 2697 | 2637 |
| 2698 VisitForValue(args->at(1), kAccumulator); | 2638 VisitForAccumulatorValue(args->at(1)); |
| 2699 | 2639 |
| 2700 Register key = rax; | 2640 Register key = rax; |
| 2701 Register cache = rbx; | 2641 Register cache = rbx; |
| 2702 Register tmp = rcx; | 2642 Register tmp = rcx; |
| 2703 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX)); | 2643 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX)); |
| 2704 __ movq(cache, | 2644 __ movq(cache, |
| 2705 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); | 2645 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); |
| 2706 __ movq(cache, | 2646 __ movq(cache, |
| 2707 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | 2647 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
| 2708 __ movq(cache, | 2648 __ movq(cache, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2725 FixedArray::kHeaderSize + kPointerSize)); | 2665 FixedArray::kHeaderSize + kPointerSize)); |
| 2726 __ jmp(&done); | 2666 __ jmp(&done); |
| 2727 | 2667 |
| 2728 __ bind(¬_found); | 2668 __ bind(¬_found); |
| 2729 // Call runtime to perform the lookup. | 2669 // Call runtime to perform the lookup. |
| 2730 __ push(cache); | 2670 __ push(cache); |
| 2731 __ push(key); | 2671 __ push(key); |
| 2732 __ CallRuntime(Runtime::kGetFromCache, 2); | 2672 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 2733 | 2673 |
| 2734 __ bind(&done); | 2674 __ bind(&done); |
| 2735 Apply(context_, rax); | 2675 context()->Plug(rax); |
| 2736 } | 2676 } |
| 2737 | 2677 |
| 2738 | 2678 |
| 2739 void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) { | 2679 void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) { |
| 2740 ASSERT_EQ(2, args->length()); | 2680 ASSERT_EQ(2, args->length()); |
| 2741 | 2681 |
| 2742 Register right = rax; | 2682 Register right = rax; |
| 2743 Register left = rbx; | 2683 Register left = rbx; |
| 2744 Register tmp = rcx; | 2684 Register tmp = rcx; |
| 2745 | 2685 |
| 2746 VisitForValue(args->at(0), kStack); | 2686 VisitForStackValue(args->at(0)); |
| 2747 VisitForValue(args->at(1), kAccumulator); | 2687 VisitForAccumulatorValue(args->at(1)); |
| 2748 __ pop(left); | 2688 __ pop(left); |
| 2749 | 2689 |
| 2750 Label done, fail, ok; | 2690 Label done, fail, ok; |
| 2751 __ cmpq(left, right); | 2691 __ cmpq(left, right); |
| 2752 __ j(equal, &ok); | 2692 __ j(equal, &ok); |
| 2753 // Fail if either is a non-HeapObject. | 2693 // Fail if either is a non-HeapObject. |
| 2754 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp); | 2694 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp); |
| 2755 __ j(either_smi, &fail); | 2695 __ j(either_smi, &fail); |
| 2756 __ j(zero, &fail); | 2696 __ j(zero, &fail); |
| 2757 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset)); | 2697 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
| 2758 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset), | 2698 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset), |
| 2759 Immediate(JS_REGEXP_TYPE)); | 2699 Immediate(JS_REGEXP_TYPE)); |
| 2760 __ j(not_equal, &fail); | 2700 __ j(not_equal, &fail); |
| 2761 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset)); | 2701 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
| 2762 __ j(not_equal, &fail); | 2702 __ j(not_equal, &fail); |
| 2763 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | 2703 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
| 2764 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | 2704 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
| 2765 __ j(equal, &ok); | 2705 __ j(equal, &ok); |
| 2766 __ bind(&fail); | 2706 __ bind(&fail); |
| 2767 __ Move(rax, Factory::false_value()); | 2707 __ Move(rax, Factory::false_value()); |
| 2768 __ jmp(&done); | 2708 __ jmp(&done); |
| 2769 __ bind(&ok); | 2709 __ bind(&ok); |
| 2770 __ Move(rax, Factory::true_value()); | 2710 __ Move(rax, Factory::true_value()); |
| 2771 __ bind(&done); | 2711 __ bind(&done); |
| 2772 | 2712 |
| 2773 Apply(context_, rax); | 2713 context()->Plug(rax); |
| 2774 } | 2714 } |
| 2775 | 2715 |
| 2776 | 2716 |
| 2777 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { | 2717 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { |
| 2778 ASSERT(args->length() == 1); | 2718 ASSERT(args->length() == 1); |
| 2779 | 2719 |
| 2780 VisitForValue(args->at(0), kAccumulator); | 2720 VisitForAccumulatorValue(args->at(0)); |
| 2781 | 2721 |
| 2782 Label materialize_true, materialize_false; | 2722 Label materialize_true, materialize_false; |
| 2783 Label* if_true = NULL; | 2723 Label* if_true = NULL; |
| 2784 Label* if_false = NULL; | 2724 Label* if_false = NULL; |
| 2785 Label* fall_through = NULL; | 2725 Label* fall_through = NULL; |
| 2786 PrepareTest(&materialize_true, &materialize_false, | 2726 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2787 &if_true, &if_false, &fall_through); | 2727 &if_true, &if_false, &fall_through); |
| 2788 | 2728 |
| 2789 __ testl(FieldOperand(rax, String::kHashFieldOffset), | 2729 __ testl(FieldOperand(rax, String::kHashFieldOffset), |
| 2790 Immediate(String::kContainsCachedArrayIndexMask)); | 2730 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2791 __ j(zero, if_true); | 2731 __ j(zero, if_true); |
| 2792 __ jmp(if_false); | 2732 __ jmp(if_false); |
| 2793 | 2733 |
| 2794 Apply(context_, if_true, if_false); | 2734 context()->Plug(if_true, if_false); |
| 2795 } | 2735 } |
| 2796 | 2736 |
| 2797 | 2737 |
| 2798 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2738 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 2799 ASSERT(args->length() == 1); | 2739 ASSERT(args->length() == 1); |
| 2800 | 2740 |
| 2801 VisitForValue(args->at(0), kAccumulator); | 2741 VisitForAccumulatorValue(args->at(0)); |
| 2802 | 2742 |
| 2803 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); | 2743 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); |
| 2804 ASSERT(String::kHashShift >= kSmiTagSize); | 2744 ASSERT(String::kHashShift >= kSmiTagSize); |
| 2805 __ IndexFromHash(rax, rax); | 2745 __ IndexFromHash(rax, rax); |
| 2806 | 2746 |
| 2807 Apply(context_, rax); | 2747 context()->Plug(rax); |
| 2808 } | 2748 } |
| 2809 | 2749 |
| 2810 | 2750 |
| 2811 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 2751 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 2812 Handle<String> name = expr->name(); | 2752 Handle<String> name = expr->name(); |
| 2813 if (name->length() > 0 && name->Get(0) == '_') { | 2753 if (name->length() > 0 && name->Get(0) == '_') { |
| 2814 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 2754 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 2815 EmitInlineRuntimeCall(expr); | 2755 EmitInlineRuntimeCall(expr); |
| 2816 return; | 2756 return; |
| 2817 } | 2757 } |
| 2818 | 2758 |
| 2819 Comment cmnt(masm_, "[ CallRuntime"); | 2759 Comment cmnt(masm_, "[ CallRuntime"); |
| 2820 ZoneList<Expression*>* args = expr->arguments(); | 2760 ZoneList<Expression*>* args = expr->arguments(); |
| 2821 | 2761 |
| 2822 if (expr->is_jsruntime()) { | 2762 if (expr->is_jsruntime()) { |
| 2823 // Prepare for calling JS runtime function. | 2763 // Prepare for calling JS runtime function. |
| 2824 __ movq(rax, CodeGenerator::GlobalObject()); | 2764 __ movq(rax, CodeGenerator::GlobalObject()); |
| 2825 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); | 2765 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); |
| 2826 } | 2766 } |
| 2827 | 2767 |
| 2828 // Push the arguments ("left-to-right"). | 2768 // Push the arguments ("left-to-right"). |
| 2829 int arg_count = args->length(); | 2769 int arg_count = args->length(); |
| 2830 for (int i = 0; i < arg_count; i++) { | 2770 for (int i = 0; i < arg_count; i++) { |
| 2831 VisitForValue(args->at(i), kStack); | 2771 VisitForStackValue(args->at(i)); |
| 2832 } | 2772 } |
| 2833 | 2773 |
| 2834 if (expr->is_jsruntime()) { | 2774 if (expr->is_jsruntime()) { |
| 2835 // Call the JS runtime function using a call IC. | 2775 // Call the JS runtime function using a call IC. |
| 2836 __ Move(rcx, expr->name()); | 2776 __ Move(rcx, expr->name()); |
| 2837 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2777 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2838 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); | 2778 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); |
| 2839 __ call(ic, RelocInfo::CODE_TARGET); | 2779 __ call(ic, RelocInfo::CODE_TARGET); |
| 2840 // Restore context register. | 2780 // Restore context register. |
| 2841 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2781 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2842 } else { | 2782 } else { |
| 2843 __ CallRuntime(expr->function(), arg_count); | 2783 __ CallRuntime(expr->function(), arg_count); |
| 2844 } | 2784 } |
| 2845 Apply(context_, rax); | 2785 context()->Plug(rax); |
| 2846 } | 2786 } |
| 2847 | 2787 |
| 2848 | 2788 |
| 2849 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 2789 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 2850 switch (expr->op()) { | 2790 switch (expr->op()) { |
| 2851 case Token::DELETE: { | 2791 case Token::DELETE: { |
| 2852 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 2792 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 2853 Property* prop = expr->expression()->AsProperty(); | 2793 Property* prop = expr->expression()->AsProperty(); |
| 2854 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 2794 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 2855 if (prop == NULL && var == NULL) { | 2795 if (prop == NULL && var == NULL) { |
| 2856 // Result of deleting non-property, non-variable reference is true. | 2796 // Result of deleting non-property, non-variable reference is true. |
| 2857 // The subexpression may have side effects. | 2797 // The subexpression may have side effects. |
| 2858 VisitForEffect(expr->expression()); | 2798 VisitForEffect(expr->expression()); |
| 2859 Apply(context_, true); | 2799 context()->Plug(true); |
| 2860 } else if (var != NULL && | 2800 } else if (var != NULL && |
| 2861 !var->is_global() && | 2801 !var->is_global() && |
| 2862 var->slot() != NULL && | 2802 var->slot() != NULL && |
| 2863 var->slot()->type() != Slot::LOOKUP) { | 2803 var->slot()->type() != Slot::LOOKUP) { |
| 2864 // Result of deleting non-global, non-dynamic variables is false. | 2804 // Result of deleting non-global, non-dynamic variables is false. |
| 2865 // The subexpression does not have side effects. | 2805 // The subexpression does not have side effects. |
| 2866 Apply(context_, false); | 2806 context()->Plug(false); |
| 2867 } else { | 2807 } else { |
| 2868 // Property or variable reference. Call the delete builtin with | 2808 // Property or variable reference. Call the delete builtin with |
| 2869 // object and property name as arguments. | 2809 // object and property name as arguments. |
| 2870 if (prop != NULL) { | 2810 if (prop != NULL) { |
| 2871 VisitForValue(prop->obj(), kStack); | 2811 VisitForStackValue(prop->obj()); |
| 2872 VisitForValue(prop->key(), kStack); | 2812 VisitForStackValue(prop->key()); |
| 2873 } else if (var->is_global()) { | 2813 } else if (var->is_global()) { |
| 2874 __ push(CodeGenerator::GlobalObject()); | 2814 __ push(CodeGenerator::GlobalObject()); |
| 2875 __ Push(var->name()); | 2815 __ Push(var->name()); |
| 2876 } else { | 2816 } else { |
| 2877 // Non-global variable. Call the runtime to look up the context | 2817 // Non-global variable. Call the runtime to look up the context |
| 2878 // where the variable was introduced. | 2818 // where the variable was introduced. |
| 2879 __ push(context_register()); | 2819 __ push(context_register()); |
| 2880 __ Push(var->name()); | 2820 __ Push(var->name()); |
| 2881 __ CallRuntime(Runtime::kLookupContext, 2); | 2821 __ CallRuntime(Runtime::kLookupContext, 2); |
| 2882 __ push(rax); | 2822 __ push(rax); |
| 2883 __ Push(var->name()); | 2823 __ Push(var->name()); |
| 2884 } | 2824 } |
| 2885 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 2825 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 2886 Apply(context_, rax); | 2826 context()->Plug(rax); |
| 2887 } | 2827 } |
| 2888 break; | 2828 break; |
| 2889 } | 2829 } |
| 2890 | 2830 |
| 2891 case Token::VOID: { | 2831 case Token::VOID: { |
| 2892 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 2832 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 2893 VisitForEffect(expr->expression()); | 2833 VisitForEffect(expr->expression()); |
| 2894 switch (context_) { | 2834 context()->Plug(Heap::kUndefinedValueRootIndex); |
| 2895 case Expression::kUninitialized: | |
| 2896 UNREACHABLE(); | |
| 2897 break; | |
| 2898 case Expression::kEffect: | |
| 2899 break; | |
| 2900 case Expression::kValue: | |
| 2901 switch (location_) { | |
| 2902 case kAccumulator: | |
| 2903 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); | |
| 2904 break; | |
| 2905 case kStack: | |
| 2906 __ PushRoot(Heap::kUndefinedValueRootIndex); | |
| 2907 break; | |
| 2908 } | |
| 2909 break; | |
| 2910 case Expression::kTest: | |
| 2911 __ jmp(false_label_); | |
| 2912 break; | |
| 2913 } | |
| 2914 break; | 2835 break; |
| 2915 } | 2836 } |
| 2916 | 2837 |
| 2917 case Token::NOT: { | 2838 case Token::NOT: { |
| 2918 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 2839 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 2919 Label materialize_true, materialize_false; | 2840 Label materialize_true, materialize_false; |
| 2920 Label* if_true = NULL; | 2841 Label* if_true = NULL; |
| 2921 Label* if_false = NULL; | 2842 Label* if_false = NULL; |
| 2922 Label* fall_through = NULL; | 2843 Label* fall_through = NULL; |
| 2923 // Notice that the labels are swapped. | 2844 // Notice that the labels are swapped. |
| 2924 PrepareTest(&materialize_true, &materialize_false, | 2845 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2925 &if_false, &if_true, &fall_through); | 2846 &if_false, &if_true, &fall_through); |
| 2926 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 2847 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 2927 Apply(context_, if_false, if_true); // Labels swapped. | 2848 context()->Plug(if_false, if_true); // Labels swapped. |
| 2928 break; | 2849 break; |
| 2929 } | 2850 } |
| 2930 | 2851 |
| 2931 case Token::TYPEOF: { | 2852 case Token::TYPEOF: { |
| 2932 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 2853 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 2933 VisitForTypeofValue(expr->expression(), kStack); | 2854 { StackValueContext context(this); |
| 2855 VisitForTypeofValue(expr->expression()); |
| 2856 } |
| 2934 __ CallRuntime(Runtime::kTypeof, 1); | 2857 __ CallRuntime(Runtime::kTypeof, 1); |
| 2935 Apply(context_, rax); | 2858 context()->Plug(rax); |
| 2936 break; | 2859 break; |
| 2937 } | 2860 } |
| 2938 | 2861 |
| 2939 case Token::ADD: { | 2862 case Token::ADD: { |
| 2940 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 2863 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
| 2941 VisitForValue(expr->expression(), kAccumulator); | 2864 VisitForAccumulatorValue(expr->expression()); |
| 2942 Label no_conversion; | 2865 Label no_conversion; |
| 2943 Condition is_smi = masm_->CheckSmi(result_register()); | 2866 Condition is_smi = masm_->CheckSmi(result_register()); |
| 2944 __ j(is_smi, &no_conversion); | 2867 __ j(is_smi, &no_conversion); |
| 2945 __ push(result_register()); | 2868 __ push(result_register()); |
| 2946 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 2869 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 2947 __ bind(&no_conversion); | 2870 __ bind(&no_conversion); |
| 2948 Apply(context_, result_register()); | 2871 context()->Plug(result_register()); |
| 2949 break; | 2872 break; |
| 2950 } | 2873 } |
| 2951 | 2874 |
| 2952 case Token::SUB: { | 2875 case Token::SUB: { |
| 2953 Comment cmt(masm_, "[ UnaryOperation (SUB)"); | 2876 Comment cmt(masm_, "[ UnaryOperation (SUB)"); |
| 2954 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 2877 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 2955 UnaryOverwriteMode overwrite = | 2878 UnaryOverwriteMode overwrite = |
| 2956 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 2879 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 2957 GenericUnaryOpStub stub(Token::SUB, overwrite); | 2880 GenericUnaryOpStub stub(Token::SUB, overwrite); |
| 2958 // GenericUnaryOpStub expects the argument to be in the | 2881 // GenericUnaryOpStub expects the argument to be in the |
| 2959 // accumulator register rax. | 2882 // accumulator register rax. |
| 2960 VisitForValue(expr->expression(), kAccumulator); | 2883 VisitForAccumulatorValue(expr->expression()); |
| 2961 __ CallStub(&stub); | 2884 __ CallStub(&stub); |
| 2962 Apply(context_, rax); | 2885 context()->Plug(rax); |
| 2963 break; | 2886 break; |
| 2964 } | 2887 } |
| 2965 | 2888 |
| 2966 case Token::BIT_NOT: { | 2889 case Token::BIT_NOT: { |
| 2967 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); | 2890 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); |
| 2968 // The generic unary operation stub expects the argument to be | 2891 // The generic unary operation stub expects the argument to be |
| 2969 // in the accumulator register rax. | 2892 // in the accumulator register rax. |
| 2970 VisitForValue(expr->expression(), kAccumulator); | 2893 VisitForAccumulatorValue(expr->expression()); |
| 2971 Label done; | 2894 Label done; |
| 2972 if (ShouldInlineSmiCase(expr->op())) { | 2895 if (ShouldInlineSmiCase(expr->op())) { |
| 2973 Label call_stub; | 2896 Label call_stub; |
| 2974 __ JumpIfNotSmi(rax, &call_stub); | 2897 __ JumpIfNotSmi(rax, &call_stub); |
| 2975 __ SmiNot(rax, rax); | 2898 __ SmiNot(rax, rax); |
| 2976 __ jmp(&done); | 2899 __ jmp(&done); |
| 2977 __ bind(&call_stub); | 2900 __ bind(&call_stub); |
| 2978 } | 2901 } |
| 2979 bool overwrite = expr->expression()->ResultOverwriteAllowed(); | 2902 bool overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 2980 UnaryOverwriteMode mode = | 2903 UnaryOverwriteMode mode = |
| 2981 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 2904 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 2982 GenericUnaryOpStub stub(Token::BIT_NOT, mode); | 2905 GenericUnaryOpStub stub(Token::BIT_NOT, mode); |
| 2983 __ CallStub(&stub); | 2906 __ CallStub(&stub); |
| 2984 __ bind(&done); | 2907 __ bind(&done); |
| 2985 Apply(context_, rax); | 2908 context()->Plug(rax); |
| 2986 break; | 2909 break; |
| 2987 } | 2910 } |
| 2988 | 2911 |
| 2989 default: | 2912 default: |
| 2990 UNREACHABLE(); | 2913 UNREACHABLE(); |
| 2991 } | 2914 } |
| 2992 } | 2915 } |
| 2993 | 2916 |
| 2994 | 2917 |
| 2995 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 2918 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3011 // In case of a property we use the uninitialized expression context | 2934 // In case of a property we use the uninitialized expression context |
| 3012 // of the key to detect a named property. | 2935 // of the key to detect a named property. |
| 3013 if (prop != NULL) { | 2936 if (prop != NULL) { |
| 3014 assign_type = | 2937 assign_type = |
| 3015 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 2938 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3016 } | 2939 } |
| 3017 | 2940 |
| 3018 // Evaluate expression and get value. | 2941 // Evaluate expression and get value. |
| 3019 if (assign_type == VARIABLE) { | 2942 if (assign_type == VARIABLE) { |
| 3020 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 2943 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3021 Location saved_location = location_; | 2944 AccumulatorValueContext context(this); |
| 3022 location_ = kAccumulator; | 2945 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3023 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | |
| 3024 Expression::kValue); | |
| 3025 location_ = saved_location; | |
| 3026 } else { | 2946 } else { |
| 3027 // Reserve space for result of postfix operation. | 2947 // Reserve space for result of postfix operation. |
| 3028 if (expr->is_postfix() && context_ != Expression::kEffect) { | 2948 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3029 __ Push(Smi::FromInt(0)); | 2949 __ Push(Smi::FromInt(0)); |
| 3030 } | 2950 } |
| 3031 if (assign_type == NAMED_PROPERTY) { | 2951 if (assign_type == NAMED_PROPERTY) { |
| 3032 VisitForValue(prop->obj(), kAccumulator); | 2952 VisitForAccumulatorValue(prop->obj()); |
| 3033 __ push(rax); // Copy of receiver, needed for later store. | 2953 __ push(rax); // Copy of receiver, needed for later store. |
| 3034 EmitNamedPropertyLoad(prop); | 2954 EmitNamedPropertyLoad(prop); |
| 3035 } else { | 2955 } else { |
| 3036 VisitForValue(prop->obj(), kStack); | 2956 VisitForStackValue(prop->obj()); |
| 3037 VisitForValue(prop->key(), kAccumulator); | 2957 VisitForAccumulatorValue(prop->key()); |
| 3038 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 2958 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
| 3039 __ push(rax); // Copy of key, needed for later store. | 2959 __ push(rax); // Copy of key, needed for later store. |
| 3040 EmitKeyedPropertyLoad(prop); | 2960 EmitKeyedPropertyLoad(prop); |
| 3041 } | 2961 } |
| 3042 } | 2962 } |
| 3043 | 2963 |
| 3044 // Call ToNumber only if operand is not a smi. | 2964 // Call ToNumber only if operand is not a smi. |
| 3045 Label no_conversion; | 2965 Label no_conversion; |
| 3046 Condition is_smi; | 2966 Condition is_smi; |
| 3047 is_smi = masm_->CheckSmi(rax); | 2967 is_smi = masm_->CheckSmi(rax); |
| 3048 __ j(is_smi, &no_conversion); | 2968 __ j(is_smi, &no_conversion); |
| 3049 __ push(rax); | 2969 __ push(rax); |
| 3050 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 2970 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 3051 __ bind(&no_conversion); | 2971 __ bind(&no_conversion); |
| 3052 | 2972 |
| 3053 // Save result for postfix expressions. | 2973 // Save result for postfix expressions. |
| 3054 if (expr->is_postfix()) { | 2974 if (expr->is_postfix()) { |
| 3055 switch (context_) { | 2975 if (!context()->IsEffect()) { |
| 3056 case Expression::kUninitialized: | 2976 // Save the result on the stack. If we have a named or keyed property |
| 3057 UNREACHABLE(); | 2977 // we store the result under the receiver that is currently on top |
| 3058 case Expression::kEffect: | 2978 // of the stack. |
| 3059 // Do not save result. | 2979 switch (assign_type) { |
| 3060 break; | 2980 case VARIABLE: |
| 3061 case Expression::kValue: | 2981 __ push(rax); |
| 3062 case Expression::kTest: | 2982 break; |
| 3063 // Save the result on the stack. If we have a named or keyed property | 2983 case NAMED_PROPERTY: |
| 3064 // we store the result under the receiver that is currently on top | 2984 __ movq(Operand(rsp, kPointerSize), rax); |
| 3065 // of the stack. | 2985 break; |
| 3066 switch (assign_type) { | 2986 case KEYED_PROPERTY: |
| 3067 case VARIABLE: | 2987 __ movq(Operand(rsp, 2 * kPointerSize), rax); |
| 3068 __ push(rax); | 2988 break; |
| 3069 break; | 2989 } |
| 3070 case NAMED_PROPERTY: | |
| 3071 __ movq(Operand(rsp, kPointerSize), rax); | |
| 3072 break; | |
| 3073 case KEYED_PROPERTY: | |
| 3074 __ movq(Operand(rsp, 2 * kPointerSize), rax); | |
| 3075 break; | |
| 3076 } | |
| 3077 break; | |
| 3078 } | 2990 } |
| 3079 } | 2991 } |
| 3080 | 2992 |
| 3081 // Inline smi case if we are in a loop. | 2993 // Inline smi case if we are in a loop. |
| 3082 Label stub_call, done; | 2994 Label stub_call, done; |
| 3083 if (ShouldInlineSmiCase(expr->op())) { | 2995 if (ShouldInlineSmiCase(expr->op())) { |
| 3084 if (expr->op() == Token::INC) { | 2996 if (expr->op() == Token::INC) { |
| 3085 __ SmiAddConstant(rax, rax, Smi::FromInt(1)); | 2997 __ SmiAddConstant(rax, rax, Smi::FromInt(1)); |
| 3086 } else { | 2998 } else { |
| 3087 __ SmiSubConstant(rax, rax, Smi::FromInt(1)); | 2999 __ SmiSubConstant(rax, rax, Smi::FromInt(1)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3104 NO_OVERWRITE, | 3016 NO_OVERWRITE, |
| 3105 NO_GENERIC_BINARY_FLAGS); | 3017 NO_GENERIC_BINARY_FLAGS); |
| 3106 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); | 3018 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); |
| 3107 __ bind(&done); | 3019 __ bind(&done); |
| 3108 | 3020 |
| 3109 // Store the value returned in rax. | 3021 // Store the value returned in rax. |
| 3110 switch (assign_type) { | 3022 switch (assign_type) { |
| 3111 case VARIABLE: | 3023 case VARIABLE: |
| 3112 if (expr->is_postfix()) { | 3024 if (expr->is_postfix()) { |
| 3113 // Perform the assignment as if via '='. | 3025 // Perform the assignment as if via '='. |
| 3114 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3026 { EffectContext context(this); |
| 3115 Token::ASSIGN, | 3027 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3116 Expression::kEffect); | 3028 Token::ASSIGN); |
| 3029 } |
| 3117 // For all contexts except kEffect: We have the result on | 3030 // For all contexts except kEffect: We have the result on |
| 3118 // top of the stack. | 3031 // top of the stack. |
| 3119 if (context_ != Expression::kEffect) { | 3032 if (!context()->IsEffect()) { |
| 3120 ApplyTOS(context_); | 3033 context()->PlugTOS(); |
| 3121 } | 3034 } |
| 3122 } else { | 3035 } else { |
| 3123 // Perform the assignment as if via '='. | 3036 // Perform the assignment as if via '='. |
| 3124 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3037 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3125 Token::ASSIGN, | 3038 Token::ASSIGN); |
| 3126 context_); | |
| 3127 } | 3039 } |
| 3128 break; | 3040 break; |
| 3129 case NAMED_PROPERTY: { | 3041 case NAMED_PROPERTY: { |
| 3130 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3042 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 3131 __ pop(rdx); | 3043 __ pop(rdx); |
| 3132 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3044 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3133 __ call(ic, RelocInfo::CODE_TARGET); | 3045 __ call(ic, RelocInfo::CODE_TARGET); |
| 3134 // This nop signals to the IC that there is no inlined code at the call | 3046 // This nop signals to the IC that there is no inlined code at the call |
| 3135 // site for it to patch. | 3047 // site for it to patch. |
| 3136 __ nop(); | 3048 __ nop(); |
| 3137 if (expr->is_postfix()) { | 3049 if (expr->is_postfix()) { |
| 3138 if (context_ != Expression::kEffect) { | 3050 if (!context()->IsEffect()) { |
| 3139 ApplyTOS(context_); | 3051 context()->PlugTOS(); |
| 3140 } | 3052 } |
| 3141 } else { | 3053 } else { |
| 3142 Apply(context_, rax); | 3054 context()->Plug(rax); |
| 3143 } | 3055 } |
| 3144 break; | 3056 break; |
| 3145 } | 3057 } |
| 3146 case KEYED_PROPERTY: { | 3058 case KEYED_PROPERTY: { |
| 3147 __ pop(rcx); | 3059 __ pop(rcx); |
| 3148 __ pop(rdx); | 3060 __ pop(rdx); |
| 3149 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3061 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3150 __ call(ic, RelocInfo::CODE_TARGET); | 3062 __ call(ic, RelocInfo::CODE_TARGET); |
| 3151 // This nop signals to the IC that there is no inlined code at the call | 3063 // This nop signals to the IC that there is no inlined code at the call |
| 3152 // site for it to patch. | 3064 // site for it to patch. |
| 3153 __ nop(); | 3065 __ nop(); |
| 3154 if (expr->is_postfix()) { | 3066 if (expr->is_postfix()) { |
| 3155 if (context_ != Expression::kEffect) { | 3067 if (!context()->IsEffect()) { |
| 3156 ApplyTOS(context_); | 3068 context()->PlugTOS(); |
| 3157 } | 3069 } |
| 3158 } else { | 3070 } else { |
| 3159 Apply(context_, rax); | 3071 context()->Plug(rax); |
| 3160 } | 3072 } |
| 3161 break; | 3073 break; |
| 3162 } | 3074 } |
| 3163 } | 3075 } |
| 3164 } | 3076 } |
| 3165 | 3077 |
| 3166 | 3078 |
| 3167 void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) { | 3079 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3168 VariableProxy* proxy = expr->AsVariableProxy(); | 3080 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3081 ASSERT(!context()->IsEffect()); |
| 3082 ASSERT(!context()->IsTest()); |
| 3083 |
| 3169 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3084 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3170 Comment cmnt(masm_, "Global variable"); | 3085 Comment cmnt(masm_, "Global variable"); |
| 3171 __ Move(rcx, proxy->name()); | 3086 __ Move(rcx, proxy->name()); |
| 3172 __ movq(rax, CodeGenerator::GlobalObject()); | 3087 __ movq(rax, CodeGenerator::GlobalObject()); |
| 3173 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3088 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3174 // Use a regular load, not a contextual load, to avoid a reference | 3089 // Use a regular load, not a contextual load, to avoid a reference |
| 3175 // error. | 3090 // error. |
| 3176 __ Call(ic, RelocInfo::CODE_TARGET); | 3091 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3177 if (where == kStack) __ push(rax); | 3092 context()->Plug(rax); |
| 3178 } else if (proxy != NULL && | 3093 } else if (proxy != NULL && |
| 3179 proxy->var()->slot() != NULL && | 3094 proxy->var()->slot() != NULL && |
| 3180 proxy->var()->slot()->type() == Slot::LOOKUP) { | 3095 proxy->var()->slot()->type() == Slot::LOOKUP) { |
| 3181 Label done, slow; | 3096 Label done, slow; |
| 3182 | 3097 |
| 3183 // Generate code for loading from variables potentially shadowed | 3098 // Generate code for loading from variables potentially shadowed |
| 3184 // by eval-introduced variables. | 3099 // by eval-introduced variables. |
| 3185 Slot* slot = proxy->var()->slot(); | 3100 Slot* slot = proxy->var()->slot(); |
| 3186 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3101 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3187 | 3102 |
| 3188 __ bind(&slow); | 3103 __ bind(&slow); |
| 3189 __ push(rsi); | 3104 __ push(rsi); |
| 3190 __ Push(proxy->name()); | 3105 __ Push(proxy->name()); |
| 3191 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3106 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3192 __ bind(&done); | 3107 __ bind(&done); |
| 3193 | 3108 |
| 3194 if (where == kStack) __ push(rax); | 3109 context()->Plug(rax); |
| 3195 } else { | 3110 } else { |
| 3196 // This expression cannot throw a reference error at the top level. | 3111 // This expression cannot throw a reference error at the top level. |
| 3197 VisitForValue(expr, where); | 3112 Visit(expr); |
| 3198 } | 3113 } |
| 3199 } | 3114 } |
| 3200 | 3115 |
| 3201 | 3116 |
| 3202 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3117 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
| 3203 Expression* left, | 3118 Expression* left, |
| 3204 Expression* right, | 3119 Expression* right, |
| 3205 Label* if_true, | 3120 Label* if_true, |
| 3206 Label* if_false, | 3121 Label* if_false, |
| 3207 Label* fall_through) { | 3122 Label* fall_through) { |
| 3208 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | 3123 if (op != Token::EQ && op != Token::EQ_STRICT) return false; |
| 3209 | 3124 |
| 3210 // Check for the pattern: typeof <expression> == <string literal>. | 3125 // Check for the pattern: typeof <expression> == <string literal>. |
| 3211 Literal* right_literal = right->AsLiteral(); | 3126 Literal* right_literal = right->AsLiteral(); |
| 3212 if (right_literal == NULL) return false; | 3127 if (right_literal == NULL) return false; |
| 3213 Handle<Object> right_literal_value = right_literal->handle(); | 3128 Handle<Object> right_literal_value = right_literal->handle(); |
| 3214 if (!right_literal_value->IsString()) return false; | 3129 if (!right_literal_value->IsString()) return false; |
| 3215 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3130 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3216 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3131 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3217 Handle<String> check = Handle<String>::cast(right_literal_value); | 3132 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3218 | 3133 |
| 3219 VisitForTypeofValue(left_unary->expression(), kAccumulator); | 3134 { AccumulatorValueContext context(this); |
| 3135 VisitForTypeofValue(left_unary->expression()); |
| 3136 } |
| 3137 |
| 3220 if (check->Equals(Heap::number_symbol())) { | 3138 if (check->Equals(Heap::number_symbol())) { |
| 3221 Condition is_smi = masm_->CheckSmi(rax); | 3139 Condition is_smi = masm_->CheckSmi(rax); |
| 3222 __ j(is_smi, if_true); | 3140 __ j(is_smi, if_true); |
| 3223 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3141 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3224 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3142 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 3225 Split(equal, if_true, if_false, fall_through); | 3143 Split(equal, if_true, if_false, fall_through); |
| 3226 } else if (check->Equals(Heap::string_symbol())) { | 3144 } else if (check->Equals(Heap::string_symbol())) { |
| 3227 Condition is_smi = masm_->CheckSmi(rax); | 3145 Condition is_smi = masm_->CheckSmi(rax); |
| 3228 __ j(is_smi, if_false); | 3146 __ j(is_smi, if_false); |
| 3229 // Check for undetectable objects => false. | 3147 // Check for undetectable objects => false. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3284 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3202 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 3285 Comment cmnt(masm_, "[ CompareOperation"); | 3203 Comment cmnt(masm_, "[ CompareOperation"); |
| 3286 SetSourcePosition(expr->position()); | 3204 SetSourcePosition(expr->position()); |
| 3287 | 3205 |
| 3288 // Always perform the comparison for its control flow. Pack the result | 3206 // Always perform the comparison for its control flow. Pack the result |
| 3289 // into the expression's context after the comparison is performed. | 3207 // into the expression's context after the comparison is performed. |
| 3290 Label materialize_true, materialize_false; | 3208 Label materialize_true, materialize_false; |
| 3291 Label* if_true = NULL; | 3209 Label* if_true = NULL; |
| 3292 Label* if_false = NULL; | 3210 Label* if_false = NULL; |
| 3293 Label* fall_through = NULL; | 3211 Label* fall_through = NULL; |
| 3294 PrepareTest(&materialize_true, &materialize_false, | 3212 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3295 &if_true, &if_false, &fall_through); | 3213 &if_true, &if_false, &fall_through); |
| 3296 | 3214 |
| 3297 // First we try a fast inlined version of the compare when one of | 3215 // First we try a fast inlined version of the compare when one of |
| 3298 // the operands is a literal. | 3216 // the operands is a literal. |
| 3299 Token::Value op = expr->op(); | 3217 Token::Value op = expr->op(); |
| 3300 Expression* left = expr->left(); | 3218 Expression* left = expr->left(); |
| 3301 Expression* right = expr->right(); | 3219 Expression* right = expr->right(); |
| 3302 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | 3220 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
| 3303 Apply(context_, if_true, if_false); | 3221 context()->Plug(if_true, if_false); |
| 3304 return; | 3222 return; |
| 3305 } | 3223 } |
| 3306 | 3224 |
| 3307 VisitForValue(expr->left(), kStack); | 3225 VisitForStackValue(expr->left()); |
| 3308 switch (op) { | 3226 switch (op) { |
| 3309 case Token::IN: | 3227 case Token::IN: |
| 3310 VisitForValue(expr->right(), kStack); | 3228 VisitForStackValue(expr->right()); |
| 3311 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3229 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3312 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3230 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 3313 Split(equal, if_true, if_false, fall_through); | 3231 Split(equal, if_true, if_false, fall_through); |
| 3314 break; | 3232 break; |
| 3315 | 3233 |
| 3316 case Token::INSTANCEOF: { | 3234 case Token::INSTANCEOF: { |
| 3317 VisitForValue(expr->right(), kStack); | 3235 VisitForStackValue(expr->right()); |
| 3318 InstanceofStub stub; | 3236 InstanceofStub stub; |
| 3319 __ CallStub(&stub); | 3237 __ CallStub(&stub); |
| 3320 __ testq(rax, rax); | 3238 __ testq(rax, rax); |
| 3321 // The stub returns 0 for true. | 3239 // The stub returns 0 for true. |
| 3322 Split(zero, if_true, if_false, fall_through); | 3240 Split(zero, if_true, if_false, fall_through); |
| 3323 break; | 3241 break; |
| 3324 } | 3242 } |
| 3325 | 3243 |
| 3326 default: { | 3244 default: { |
| 3327 VisitForValue(expr->right(), kAccumulator); | 3245 VisitForAccumulatorValue(expr->right()); |
| 3328 Condition cc = no_condition; | 3246 Condition cc = no_condition; |
| 3329 bool strict = false; | 3247 bool strict = false; |
| 3330 switch (op) { | 3248 switch (op) { |
| 3331 case Token::EQ_STRICT: | 3249 case Token::EQ_STRICT: |
| 3332 strict = true; | 3250 strict = true; |
| 3333 // Fall through. | 3251 // Fall through. |
| 3334 case Token::EQ: | 3252 case Token::EQ: |
| 3335 cc = equal; | 3253 cc = equal; |
| 3336 __ pop(rdx); | 3254 __ pop(rdx); |
| 3337 break; | 3255 break; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3371 | 3289 |
| 3372 CompareStub stub(cc, strict); | 3290 CompareStub stub(cc, strict); |
| 3373 __ CallStub(&stub); | 3291 __ CallStub(&stub); |
| 3374 __ testq(rax, rax); | 3292 __ testq(rax, rax); |
| 3375 Split(cc, if_true, if_false, fall_through); | 3293 Split(cc, if_true, if_false, fall_through); |
| 3376 } | 3294 } |
| 3377 } | 3295 } |
| 3378 | 3296 |
| 3379 // Convert the result of the comparison into one expected for this | 3297 // Convert the result of the comparison into one expected for this |
| 3380 // expression's context. | 3298 // expression's context. |
| 3381 Apply(context_, if_true, if_false); | 3299 context()->Plug(if_true, if_false); |
| 3382 } | 3300 } |
| 3383 | 3301 |
| 3384 | 3302 |
| 3385 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3303 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
| 3386 Comment cmnt(masm_, "[ CompareToNull"); | 3304 Comment cmnt(masm_, "[ CompareToNull"); |
| 3387 Label materialize_true, materialize_false; | 3305 Label materialize_true, materialize_false; |
| 3388 Label* if_true = NULL; | 3306 Label* if_true = NULL; |
| 3389 Label* if_false = NULL; | 3307 Label* if_false = NULL; |
| 3390 Label* fall_through = NULL; | 3308 Label* fall_through = NULL; |
| 3391 PrepareTest(&materialize_true, &materialize_false, | 3309 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3392 &if_true, &if_false, &fall_through); | 3310 &if_true, &if_false, &fall_through); |
| 3393 | 3311 |
| 3394 VisitForValue(expr->expression(), kAccumulator); | 3312 VisitForAccumulatorValue(expr->expression()); |
| 3395 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3313 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 3396 if (expr->is_strict()) { | 3314 if (expr->is_strict()) { |
| 3397 Split(equal, if_true, if_false, fall_through); | 3315 Split(equal, if_true, if_false, fall_through); |
| 3398 } else { | 3316 } else { |
| 3399 __ j(equal, if_true); | 3317 __ j(equal, if_true); |
| 3400 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3318 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3401 __ j(equal, if_true); | 3319 __ j(equal, if_true); |
| 3402 Condition is_smi = masm_->CheckSmi(rax); | 3320 Condition is_smi = masm_->CheckSmi(rax); |
| 3403 __ j(is_smi, if_false); | 3321 __ j(is_smi, if_false); |
| 3404 // It can be an undetectable object. | 3322 // It can be an undetectable object. |
| 3405 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 3323 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3406 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3324 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 3407 Immediate(1 << Map::kIsUndetectable)); | 3325 Immediate(1 << Map::kIsUndetectable)); |
| 3408 Split(not_zero, if_true, if_false, fall_through); | 3326 Split(not_zero, if_true, if_false, fall_through); |
| 3409 } | 3327 } |
| 3410 Apply(context_, if_true, if_false); | 3328 context()->Plug(if_true, if_false); |
| 3411 } | 3329 } |
| 3412 | 3330 |
| 3413 | 3331 |
| 3414 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 3332 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 3415 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 3333 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3416 Apply(context_, rax); | 3334 context()->Plug(rax); |
| 3417 } | 3335 } |
| 3418 | 3336 |
| 3419 | 3337 |
| 3420 Register FullCodeGenerator::result_register() { return rax; } | 3338 Register FullCodeGenerator::result_register() { return rax; } |
| 3421 | 3339 |
| 3422 | 3340 |
| 3423 Register FullCodeGenerator::context_register() { return rsi; } | 3341 Register FullCodeGenerator::context_register() { return rsi; } |
| 3424 | 3342 |
| 3425 | 3343 |
| 3426 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3344 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3467 __ ret(0); | 3385 __ ret(0); |
| 3468 } | 3386 } |
| 3469 | 3387 |
| 3470 | 3388 |
| 3471 #undef __ | 3389 #undef __ |
| 3472 | 3390 |
| 3473 | 3391 |
| 3474 } } // namespace v8::internal | 3392 } } // namespace v8::internal |
| 3475 | 3393 |
| 3476 #endif // V8_TARGET_ARCH_X64 | 3394 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |