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 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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, interceptor_holder, | 379 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
380 miss_label); | 380 miss_label); |
381 return; | 381 return; |
382 } | 382 } |
383 | 383 |
384 // Note: starting a frame here makes GC aware of pointers pushed below. | 384 // Save necessary data before invoking an interceptor. |
| 385 // Requires a frame to make GC aware of pushed pointers. |
385 __ EnterInternalFrame(); | 386 __ EnterInternalFrame(); |
386 | 387 |
387 if (lookup->type() == CALLBACKS) { | 388 if (lookup->type() == CALLBACKS && !receiver.is(holder)) { |
| 389 // CALLBACKS case needs a receiver to be passed into C++ callback. |
388 __ push(receiver); | 390 __ push(receiver); |
389 } | 391 } |
390 __ push(holder); | 392 __ push(holder); |
391 __ push(name_); | 393 __ push(name_); |
392 | 394 |
393 // Invoke an interceptor. Note: map checks from receiver to | 395 // Invoke an interceptor. Note: map checks from receiver to |
394 // interceptor's holder has been compiled before (see a caller | 396 // interceptor's holder has been compiled before (see a caller |
395 // of this method.) | 397 // of this method.) |
396 CompileCallLoadPropertyWithInterceptor(masm, | 398 CompileCallLoadPropertyWithInterceptor(masm, |
397 receiver, | 399 receiver, |
398 holder, | 400 holder, |
399 name_, | 401 name_, |
400 interceptor_holder); | 402 interceptor_holder); |
401 | 403 |
402 // Check if interceptor provided a value for property. If it's | 404 // Check if interceptor provided a value for property. If it's |
403 // the case, return immediately. | 405 // the case, return immediately. |
404 Label interceptor_failed; | 406 Label interceptor_failed; |
405 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 407 __ cmp(eax, Factory::no_interceptor_result_sentinel()); |
406 __ j(equal, &interceptor_failed); | 408 __ j(equal, &interceptor_failed); |
407 __ LeaveInternalFrame(); | 409 __ LeaveInternalFrame(); |
408 __ ret(0); | 410 __ ret(0); |
409 | 411 |
410 __ bind(&interceptor_failed); | 412 __ bind(&interceptor_failed); |
411 __ pop(name_); | 413 __ pop(name_); |
412 __ pop(holder); | 414 __ pop(holder); |
413 if (lookup->type() == CALLBACKS) { | 415 if (lookup->type() == CALLBACKS && !receiver.is(holder)) { |
414 __ pop(receiver); | 416 __ pop(receiver); |
415 } | 417 } |
416 | 418 |
417 __ LeaveInternalFrame(); | 419 __ LeaveInternalFrame(); |
418 | 420 |
419 if (lookup->type() == FIELD) { | 421 // Check that the maps from interceptor's holder to lookup's holder |
420 // We found FIELD property in prototype chain of interceptor's holder. | 422 // haven't changed. And load lookup's holder into |holder| register. |
421 // Check that the maps from interceptor's holder to field's holder | 423 if (interceptor_holder != lookup->holder()) { |
422 // haven't changed... | |
423 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, | 424 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, |
424 lookup->holder(), scratch1, | 425 lookup->holder(), scratch1, |
425 scratch2, | 426 scratch2, |
426 name, | 427 name, |
427 miss_label); | 428 miss_label); |
428 // ... and retrieve a field from field's holder. | 429 } |
| 430 |
| 431 if (lookup->type() == FIELD) { |
| 432 // We found FIELD property in prototype chain of interceptor's holder. |
| 433 // Retrieve a field from field's holder. |
429 stub_compiler->GenerateFastPropertyLoad(masm, eax, | 434 stub_compiler->GenerateFastPropertyLoad(masm, eax, |
430 holder, lookup->holder(), | 435 holder, lookup->holder(), |
431 lookup->GetFieldIndex()); | 436 lookup->GetFieldIndex()); |
432 __ ret(0); | 437 __ ret(0); |
433 } else { | 438 } else { |
434 // We found CALLBACKS property in prototype chain of interceptor's | 439 // We found CALLBACKS property in prototype chain of interceptor's |
435 // holder. | 440 // holder. |
436 ASSERT(lookup->type() == CALLBACKS); | 441 ASSERT(lookup->type() == CALLBACKS); |
437 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | 442 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); |
438 ASSERT(callback != NULL); | 443 ASSERT(callback != NULL); |
439 ASSERT(callback->getter() != NULL); | 444 ASSERT(callback->getter() != NULL); |
440 | 445 |
441 // Prepare for tail call: push receiver to stack after return address. | 446 // Tail call to runtime. |
442 Label cleanup; | 447 // Important invariant in CALLBACKS case: the code above must be |
| 448 // structured to never clobber |receiver| register. |
443 __ pop(scratch2); // return address | 449 __ pop(scratch2); // return address |
444 __ push(receiver); | 450 __ push(receiver); |
445 __ push(scratch2); | |
446 | |
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, | |
450 lookup->holder(), scratch1, | |
451 scratch2, | |
452 name, | |
453 &cleanup); | |
454 | |
455 // Continue tail call preparation: push remaining parameters after | |
456 // return address. | |
457 __ pop(scratch2); // return address | |
458 __ push(holder); | 451 __ push(holder); |
459 __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); | 452 __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); |
460 __ push(holder); | 453 __ push(holder); |
461 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); | 454 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); |
462 __ push(name_); | 455 __ push(name_); |
463 __ push(scratch2); // restore return address | 456 __ push(scratch2); // restore return address |
464 | 457 |
465 // Tail call to runtime. | |
466 ExternalReference ref = | 458 ExternalReference ref = |
467 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | 459 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
468 __ TailCallExternalReference(ref, 5, 1); | 460 __ TailCallExternalReference(ref, 5, 1); |
469 | |
470 // Clean up code: we pushed receiver after return address and | |
471 // need to remove it from there. | |
472 __ bind(&cleanup); | |
473 __ pop(scratch1); // return address. | |
474 __ pop(scratch2); // receiver. | |
475 __ push(scratch1); | |
476 } | 461 } |
477 } | 462 } |
478 | 463 |
479 | 464 |
480 void CompileRegular(MacroAssembler* masm, | 465 void CompileRegular(MacroAssembler* masm, |
481 Register receiver, | 466 Register receiver, |
482 Register holder, | 467 Register holder, |
483 Register scratch, | 468 Register scratch, |
484 JSObject* interceptor_holder, | 469 JSObject* interceptor_holder, |
485 Label* miss_label) { | 470 Label* miss_label) { |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 if (can_do_fast_api_call) { | 661 if (can_do_fast_api_call) { |
677 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); | 662 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); |
678 ReserveSpaceForFastApiCall(masm, scratch1); | 663 ReserveSpaceForFastApiCall(masm, scratch1); |
679 } | 664 } |
680 | 665 |
681 // Check that the maps from receiver to interceptor's holder | 666 // Check that the maps from receiver to interceptor's holder |
682 // haven't changed and thus we can invoke interceptor. | 667 // haven't changed and thus we can invoke interceptor. |
683 Label miss_cleanup; | 668 Label miss_cleanup; |
684 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 669 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
685 Register holder = | 670 Register holder = |
686 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 671 stub_compiler_->CheckPrototypes(object, receiver, |
687 scratch1, scratch2, name, | 672 interceptor_holder, scratch1, |
688 depth1, miss); | 673 scratch2, name, depth1, miss); |
689 | 674 |
690 // Invoke an interceptor and if it provides a value, | 675 // Invoke an interceptor and if it provides a value, |
691 // branch to |regular_invoke|. | 676 // branch to |regular_invoke|. |
692 Label regular_invoke; | 677 Label regular_invoke; |
693 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | 678 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
694 ®ular_invoke); | 679 ®ular_invoke); |
695 | 680 |
696 // Interceptor returned nothing for this property. Try to use cached | 681 // Interceptor returned nothing for this property. Try to use cached |
697 // constant function. | 682 // constant function. |
698 | 683 |
699 // Check that the maps from interceptor's holder to constant function's | 684 // Check that the maps from interceptor's holder to constant function's |
700 // holder haven't changed and thus we can use cached constant function. | 685 // holder haven't changed and thus we can use cached constant function. |
701 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, | 686 if (interceptor_holder != lookup->holder()) { |
702 lookup->holder(), | 687 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
703 scratch1, scratch2, name, | 688 lookup->holder(), scratch1, |
704 depth2, miss); | 689 scratch2, name, depth2, miss); |
| 690 // CheckPrototypes has a side effect of fetching a 'holder' |
| 691 // for API (object which is instanceof for the signature). It's |
| 692 // safe to omit it here, as if present, it should be fetched |
| 693 // by the previous CheckPrototypes. |
| 694 ASSERT((depth2 == kInvalidProtoDepth) || (depth1 != kInvalidProtoDepth)); |
| 695 } |
705 | 696 |
706 // Invoke function. | 697 // Invoke function. |
707 if (can_do_fast_api_call) { | 698 if (can_do_fast_api_call) { |
708 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 699 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
709 } else { | 700 } else { |
710 __ InvokeFunction(optimization.constant_function(), arguments_, | 701 __ InvokeFunction(optimization.constant_function(), arguments_, |
711 JUMP_FUNCTION); | 702 JUMP_FUNCTION); |
712 } | 703 } |
713 | 704 |
714 // Deferred code for fast API call case---clean preallocated space. | 705 // Deferred code for fast API call case---clean preallocated space. |
(...skipping 1700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2415 // Return the generated code. | 2406 // Return the generated code. |
2416 return GetCode(); | 2407 return GetCode(); |
2417 } | 2408 } |
2418 | 2409 |
2419 | 2410 |
2420 #undef __ | 2411 #undef __ |
2421 | 2412 |
2422 } } // namespace v8::internal | 2413 } } // namespace v8::internal |
2423 | 2414 |
2424 #endif // V8_TARGET_ARCH_IA32 | 2415 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |