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 |