OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 class LoadInterceptorCompiler BASE_EMBEDDED { | 349 class LoadInterceptorCompiler BASE_EMBEDDED { |
350 public: | 350 public: |
351 explicit LoadInterceptorCompiler(Register name) : name_(name) {} | 351 explicit LoadInterceptorCompiler(Register name) : name_(name) {} |
352 | 352 |
353 void CompileCacheable(MacroAssembler* masm, | 353 void CompileCacheable(MacroAssembler* masm, |
354 StubCompiler* stub_compiler, | 354 StubCompiler* stub_compiler, |
355 Register receiver, | 355 Register receiver, |
356 Register holder, | 356 Register holder, |
357 Register scratch1, | 357 Register scratch1, |
358 Register scratch2, | 358 Register scratch2, |
359 JSObject* holder_obj, | 359 JSObject* interceptor_holder, |
360 LookupResult* lookup, | 360 LookupResult* lookup, |
361 String* name, | 361 String* name, |
362 Label* miss_label) { | 362 Label* miss_label) { |
363 AccessorInfo* callback = NULL; | 363 AccessorInfo* callback = NULL; |
364 bool optimize = false; | 364 bool optimize = false; |
365 // So far the most popular follow ups for interceptor loads are FIELD | 365 // So far the most popular follow ups for interceptor loads are FIELD |
366 // and CALLBACKS, so inline only them, other cases may be added | 366 // and CALLBACKS, so inline only them, other cases may be added |
367 // later. | 367 // later. |
368 if (lookup->type() == FIELD) { | 368 if (lookup->type() == FIELD) { |
369 optimize = true; | 369 optimize = true; |
370 } else if (lookup->type() == CALLBACKS) { | 370 } else if (lookup->type() == CALLBACKS) { |
371 Object* callback_object = lookup->GetCallbackObject(); | 371 Object* callback_object = lookup->GetCallbackObject(); |
372 if (callback_object->IsAccessorInfo()) { | 372 if (callback_object->IsAccessorInfo()) { |
373 callback = AccessorInfo::cast(callback_object); | 373 callback = AccessorInfo::cast(callback_object); |
374 optimize = callback->getter() != NULL; | 374 optimize = callback->getter() != NULL; |
375 } | 375 } |
376 } | 376 } |
377 | 377 |
378 if (!optimize) { | 378 if (!optimize) { |
379 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 379 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
| 380 miss_label); |
380 return; | 381 return; |
381 } | 382 } |
382 | 383 |
383 // Note: starting a frame here makes GC aware of pointers pushed below. | 384 // Note: starting a frame here makes GC aware of pointers pushed below. |
384 __ EnterInternalFrame(); | 385 __ EnterInternalFrame(); |
385 | 386 |
386 if (lookup->type() == CALLBACKS) { | 387 if (lookup->type() == CALLBACKS) { |
387 __ push(receiver); | 388 __ push(receiver); |
388 } | 389 } |
389 __ push(holder); | 390 __ push(holder); |
390 __ push(name_); | 391 __ push(name_); |
391 | 392 |
| 393 // Invoke an interceptor. Note: map checks from receiver to |
| 394 // interceptor's holder has been compiled before (see a caller |
| 395 // of this method.) |
392 CompileCallLoadPropertyWithInterceptor(masm, | 396 CompileCallLoadPropertyWithInterceptor(masm, |
393 receiver, | 397 receiver, |
394 holder, | 398 holder, |
395 name_, | 399 name_, |
396 holder_obj); | 400 interceptor_holder); |
397 | 401 |
| 402 // Check if interceptor provided a value for property. If it's |
| 403 // the case, return immediately. |
398 Label interceptor_failed; | 404 Label interceptor_failed; |
399 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 405 __ cmp(eax, Factory::no_interceptor_result_sentinel()); |
400 __ j(equal, &interceptor_failed); | 406 __ j(equal, &interceptor_failed); |
401 __ LeaveInternalFrame(); | 407 __ LeaveInternalFrame(); |
402 __ ret(0); | 408 __ ret(0); |
403 | 409 |
404 __ bind(&interceptor_failed); | 410 __ bind(&interceptor_failed); |
405 __ pop(name_); | 411 __ pop(name_); |
406 __ pop(holder); | 412 __ pop(holder); |
407 if (lookup->type() == CALLBACKS) { | 413 if (lookup->type() == CALLBACKS) { |
408 __ pop(receiver); | 414 __ pop(receiver); |
409 } | 415 } |
410 | 416 |
411 __ LeaveInternalFrame(); | 417 __ LeaveInternalFrame(); |
412 | 418 |
413 if (lookup->type() == FIELD) { | 419 if (lookup->type() == FIELD) { |
414 holder = stub_compiler->CheckPrototypes(holder_obj, holder, | 420 // We found FIELD property in prototype chain of interceptor's holder. |
| 421 // Check that the maps from interceptor's holder to field's holder |
| 422 // haven't changed... |
| 423 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, |
415 lookup->holder(), scratch1, | 424 lookup->holder(), scratch1, |
416 scratch2, | 425 scratch2, |
417 name, | 426 name, |
418 miss_label); | 427 miss_label); |
| 428 // ... and retrieve a field from field's holder. |
419 stub_compiler->GenerateFastPropertyLoad(masm, eax, | 429 stub_compiler->GenerateFastPropertyLoad(masm, eax, |
420 holder, lookup->holder(), | 430 holder, lookup->holder(), |
421 lookup->GetFieldIndex()); | 431 lookup->GetFieldIndex()); |
422 __ ret(0); | 432 __ ret(0); |
423 } else { | 433 } else { |
| 434 // We found CALLBACKS property in prototype chain of interceptor's |
| 435 // holder. |
424 ASSERT(lookup->type() == CALLBACKS); | 436 ASSERT(lookup->type() == CALLBACKS); |
425 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | 437 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); |
426 ASSERT(callback != NULL); | 438 ASSERT(callback != NULL); |
427 ASSERT(callback->getter() != NULL); | 439 ASSERT(callback->getter() != NULL); |
428 | 440 |
| 441 // Prepare for tail call: push receiver to stack after return address. |
429 Label cleanup; | 442 Label cleanup; |
430 __ pop(scratch2); | 443 __ pop(scratch2); // return address |
431 __ push(receiver); | 444 __ push(receiver); |
432 __ push(scratch2); | 445 __ push(scratch2); |
433 | 446 |
434 holder = stub_compiler->CheckPrototypes(holder_obj, holder, | 447 // Check that the maps from interceptor's holder to callback's holder |
| 448 // haven't changed. |
| 449 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, |
435 lookup->holder(), scratch1, | 450 lookup->holder(), scratch1, |
436 scratch2, | 451 scratch2, |
437 name, | 452 name, |
438 &cleanup); | 453 &cleanup); |
439 | 454 |
440 __ pop(scratch2); // save old return address | 455 // Continue tail call preparation: push remaining parameters after |
| 456 // return address. |
| 457 __ pop(scratch2); // return address |
441 __ push(holder); | 458 __ push(holder); |
442 __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); | 459 __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); |
443 __ push(holder); | 460 __ push(holder); |
444 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); | 461 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); |
445 __ push(name_); | 462 __ push(name_); |
446 __ push(scratch2); // restore old return address | 463 __ push(scratch2); // restore return address |
447 | 464 |
| 465 // Tail call to runtime. |
448 ExternalReference ref = | 466 ExternalReference ref = |
449 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | 467 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
450 __ TailCallExternalReference(ref, 5, 1); | 468 __ TailCallExternalReference(ref, 5, 1); |
451 | 469 |
| 470 // Clean up code: we pushed receiver after return address and |
| 471 // need to remove it from there. |
452 __ bind(&cleanup); | 472 __ bind(&cleanup); |
453 __ pop(scratch1); | 473 __ pop(scratch1); // return address. |
454 __ pop(scratch2); | 474 __ pop(scratch2); // receiver. |
455 __ push(scratch1); | 475 __ push(scratch1); |
456 } | 476 } |
457 } | 477 } |
458 | 478 |
459 | 479 |
460 void CompileRegular(MacroAssembler* masm, | 480 void CompileRegular(MacroAssembler* masm, |
461 Register receiver, | 481 Register receiver, |
462 Register holder, | 482 Register holder, |
463 Register scratch, | 483 Register scratch, |
464 JSObject* holder_obj, | 484 JSObject* interceptor_holder, |
465 Label* miss_label) { | 485 Label* miss_label) { |
466 __ pop(scratch); // save old return address | 486 __ pop(scratch); // save old return address |
467 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); | 487 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
468 __ push(scratch); // restore old return address | 488 __ push(scratch); // restore old return address |
469 | 489 |
470 ExternalReference ref = ExternalReference( | 490 ExternalReference ref = ExternalReference( |
471 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 491 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
472 __ TailCallExternalReference(ref, 5, 1); | 492 __ TailCallExternalReference(ref, 5, 1); |
473 } | 493 } |
474 | 494 |
475 private: | 495 private: |
476 Register name_; | 496 Register name_; |
477 }; | 497 }; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 miss); | 639 miss); |
620 } | 640 } |
621 } | 641 } |
622 | 642 |
623 private: | 643 private: |
624 void CompileCacheable(MacroAssembler* masm, | 644 void CompileCacheable(MacroAssembler* masm, |
625 JSObject* object, | 645 JSObject* object, |
626 Register receiver, | 646 Register receiver, |
627 Register scratch1, | 647 Register scratch1, |
628 Register scratch2, | 648 Register scratch2, |
629 JSObject* holder_obj, | 649 JSObject* interceptor_holder, |
630 LookupResult* lookup, | 650 LookupResult* lookup, |
631 String* name, | 651 String* name, |
632 const CallOptimization& optimization, | 652 const CallOptimization& optimization, |
633 Label* miss_label) { | 653 Label* miss_label) { |
634 ASSERT(optimization.is_constant_call()); | 654 ASSERT(optimization.is_constant_call()); |
635 ASSERT(!lookup->holder()->IsGlobalObject()); | 655 ASSERT(!lookup->holder()->IsGlobalObject()); |
636 | 656 |
637 int depth1 = kInvalidProtoDepth; | 657 int depth1 = kInvalidProtoDepth; |
638 int depth2 = kInvalidProtoDepth; | 658 int depth2 = kInvalidProtoDepth; |
639 bool can_do_fast_api_call = false; | 659 bool can_do_fast_api_call = false; |
640 if (optimization.is_simple_api_call() && | 660 if (optimization.is_simple_api_call() && |
641 !lookup->holder()->IsGlobalObject()) { | 661 !lookup->holder()->IsGlobalObject()) { |
642 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); | 662 depth1 = |
| 663 optimization.GetPrototypeDepthOfExpectedType(object, |
| 664 interceptor_holder); |
643 if (depth1 == kInvalidProtoDepth) { | 665 if (depth1 == kInvalidProtoDepth) { |
644 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, | 666 depth2 = |
645 lookup->holder()); | 667 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, |
| 668 lookup->holder()); |
646 } | 669 } |
647 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || | 670 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
648 (depth2 != kInvalidProtoDepth); | 671 (depth2 != kInvalidProtoDepth); |
649 } | 672 } |
650 | 673 |
651 __ IncrementCounter(&Counters::call_const_interceptor, 1); | 674 __ IncrementCounter(&Counters::call_const_interceptor, 1); |
652 | 675 |
653 if (can_do_fast_api_call) { | 676 if (can_do_fast_api_call) { |
654 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); | 677 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); |
655 ReserveSpaceForFastApiCall(masm, scratch1); | 678 ReserveSpaceForFastApiCall(masm, scratch1); |
656 } | 679 } |
657 | 680 |
| 681 // Check that the maps from receiver to interceptor's holder |
| 682 // haven't changed and thus we can invoke interceptor. |
658 Label miss_cleanup; | 683 Label miss_cleanup; |
659 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 684 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
660 Register holder = | 685 Register holder = |
661 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | 686 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
662 scratch1, scratch2, name, | 687 scratch1, scratch2, name, |
663 depth1, miss); | 688 depth1, miss); |
664 | 689 |
| 690 // Invoke an interceptor and if it provides a value, |
| 691 // branch to |regular_invoke|. |
665 Label regular_invoke; | 692 Label regular_invoke; |
666 LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke); | 693 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
| 694 ®ular_invoke); |
667 | 695 |
668 // Generate code for the failed interceptor case. | 696 // Interceptor returned nothing for this property. Try to use cached |
| 697 // constant function. |
669 | 698 |
670 // Check the lookup is still valid. | 699 // Check that the maps from interceptor's holder to constant function's |
671 stub_compiler_->CheckPrototypes(holder_obj, receiver, | 700 // holder haven't changed and thus we can use cached constant function. |
| 701 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
672 lookup->holder(), | 702 lookup->holder(), |
673 scratch1, scratch2, name, | 703 scratch1, scratch2, name, |
674 depth2, miss); | 704 depth2, miss); |
675 | 705 |
| 706 // Invoke function. |
676 if (can_do_fast_api_call) { | 707 if (can_do_fast_api_call) { |
677 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 708 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
678 } else { | 709 } else { |
679 __ InvokeFunction(optimization.constant_function(), arguments_, | 710 __ InvokeFunction(optimization.constant_function(), arguments_, |
680 JUMP_FUNCTION); | 711 JUMP_FUNCTION); |
681 } | 712 } |
682 | 713 |
| 714 // Deferred code for fast API call case---clean preallocated space. |
683 if (can_do_fast_api_call) { | 715 if (can_do_fast_api_call) { |
684 __ bind(&miss_cleanup); | 716 __ bind(&miss_cleanup); |
685 FreeSpaceForFastApiCall(masm, scratch1); | 717 FreeSpaceForFastApiCall(masm, scratch1); |
686 __ jmp(miss_label); | 718 __ jmp(miss_label); |
687 } | 719 } |
688 | 720 |
| 721 // Invoke a regular function. |
689 __ bind(®ular_invoke); | 722 __ bind(®ular_invoke); |
690 if (can_do_fast_api_call) { | 723 if (can_do_fast_api_call) { |
691 FreeSpaceForFastApiCall(masm, scratch1); | 724 FreeSpaceForFastApiCall(masm, scratch1); |
692 } | 725 } |
693 } | 726 } |
694 | 727 |
695 void CompileRegular(MacroAssembler* masm, | 728 void CompileRegular(MacroAssembler* masm, |
696 JSObject* object, | 729 JSObject* object, |
697 Register receiver, | 730 Register receiver, |
698 Register scratch1, | 731 Register scratch1, |
699 Register scratch2, | 732 Register scratch2, |
700 String* name, | 733 String* name, |
701 JSObject* holder_obj, | 734 JSObject* interceptor_holder, |
702 Label* miss_label) { | 735 Label* miss_label) { |
703 Register holder = | 736 Register holder = |
704 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | 737 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
705 scratch1, scratch2, name, | 738 scratch1, scratch2, name, |
706 miss_label); | 739 miss_label); |
707 | 740 |
708 __ EnterInternalFrame(); | 741 __ EnterInternalFrame(); |
709 // Save the name_ register across the call. | 742 // Save the name_ register across the call. |
710 __ push(name_); | 743 __ push(name_); |
711 | 744 |
712 PushInterceptorArguments(masm, | 745 PushInterceptorArguments(masm, |
713 receiver, | 746 receiver, |
714 holder, | 747 holder, |
715 name_, | 748 name_, |
716 holder_obj); | 749 interceptor_holder); |
717 | 750 |
718 __ CallExternalReference( | 751 __ CallExternalReference( |
719 ExternalReference( | 752 ExternalReference( |
720 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), | 753 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), |
721 5); | 754 5); |
722 | 755 |
723 // Restore the name_ register. | 756 // Restore the name_ register. |
724 __ pop(name_); | 757 __ pop(name_); |
725 __ LeaveInternalFrame(); | 758 __ LeaveInternalFrame(); |
726 } | 759 } |
(...skipping 1657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2384 // Return the generated code. | 2417 // Return the generated code. |
2385 return GetCode(); | 2418 return GetCode(); |
2386 } | 2419 } |
2387 | 2420 |
2388 | 2421 |
2389 #undef __ | 2422 #undef __ |
2390 | 2423 |
2391 } } // namespace v8::internal | 2424 } } // namespace v8::internal |
2392 | 2425 |
2393 #endif // V8_TARGET_ARCH_IA32 | 2426 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |