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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 86 |
87 // Jump to the function-specific construct stub. | 87 // Jump to the function-specific construct stub. |
88 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 88 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
89 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); | 89 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); |
90 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); | 90 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); |
91 __ jmp(Operand(ebx)); | 91 __ jmp(Operand(ebx)); |
92 | 92 |
93 // edi: called object | 93 // edi: called object |
94 // eax: number of arguments | 94 // eax: number of arguments |
95 __ bind(&non_function_call); | 95 __ bind(&non_function_call); |
96 | 96 // CALL_NON_FUNCTION expects the non-function constructor as receiver |
| 97 // (instead of the original receiver from the call site). The receiver is |
| 98 // stack element argc+1. |
| 99 __ mov(Operand(esp, eax, times_4, kPointerSize), edi); |
97 // Set expected number of arguments to zero (not changing eax). | 100 // Set expected number of arguments to zero (not changing eax). |
98 __ Set(ebx, Immediate(0)); | 101 __ Set(ebx, Immediate(0)); |
99 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 102 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
100 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | 103 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
101 RelocInfo::CODE_TARGET); | 104 RelocInfo::CODE_TARGET); |
102 } | 105 } |
103 | 106 |
104 | 107 |
105 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 108 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
106 bool is_api_function) { | 109 bool is_api_function) { |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 { Label done; | 433 { Label done; |
431 __ test(eax, Operand(eax)); | 434 __ test(eax, Operand(eax)); |
432 __ j(not_zero, &done, taken); | 435 __ j(not_zero, &done, taken); |
433 __ pop(ebx); | 436 __ pop(ebx); |
434 __ push(Immediate(Factory::undefined_value())); | 437 __ push(Immediate(Factory::undefined_value())); |
435 __ push(ebx); | 438 __ push(ebx); |
436 __ inc(eax); | 439 __ inc(eax); |
437 __ bind(&done); | 440 __ bind(&done); |
438 } | 441 } |
439 | 442 |
440 // 2. Get the function to call from the stack. | 443 // 2. Get the function to call (passed as receiver) from the stack, check |
441 { Label done, non_function, function; | 444 // if it is a function. |
442 // +1 ~ return address. | 445 Label non_function; |
443 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); | 446 { Label function; |
| 447 // 1 ~ return address. |
| 448 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
444 __ test(edi, Immediate(kSmiTagMask)); | 449 __ test(edi, Immediate(kSmiTagMask)); |
445 __ j(zero, &non_function, not_taken); | 450 __ j(zero, &non_function, not_taken); |
446 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 451 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
447 __ j(equal, &function, taken); | 452 __ j(not_equal, &non_function, not_taken); |
| 453 __ bind(&function); |
| 454 } |
448 | 455 |
449 // Non-function called: Clear the function to force exception. | 456 // 3a. Patch the first argument if necessary when calling a function. |
450 __ bind(&non_function); | 457 Label shift_arguments; |
451 __ xor_(edi, Operand(edi)); | 458 { Label convert_to_object, use_global_receiver, patch_receiver; |
452 __ jmp(&done); | 459 // Change context eagerly in case we need the global receiver. |
453 | |
454 // Function called: Change context eagerly to get the right global object. | |
455 __ bind(&function); | |
456 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 460 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
457 | 461 |
458 __ bind(&done); | 462 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. |
459 } | |
460 | |
461 // 3. Make sure first argument is an object; convert if necessary. | |
462 { Label call_to_object, use_global_receiver, patch_receiver, done; | |
463 __ mov(ebx, Operand(esp, eax, times_4, 0)); | |
464 | |
465 __ test(ebx, Immediate(kSmiTagMask)); | 463 __ test(ebx, Immediate(kSmiTagMask)); |
466 __ j(zero, &call_to_object); | 464 __ j(zero, &convert_to_object); |
467 | 465 |
468 __ cmp(ebx, Factory::null_value()); | 466 __ cmp(ebx, Factory::null_value()); |
469 __ j(equal, &use_global_receiver); | 467 __ j(equal, &use_global_receiver); |
470 __ cmp(ebx, Factory::undefined_value()); | 468 __ cmp(ebx, Factory::undefined_value()); |
471 __ j(equal, &use_global_receiver); | 469 __ j(equal, &use_global_receiver); |
472 | 470 |
473 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); | 471 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
474 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 472 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
475 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 473 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
476 __ j(less, &call_to_object); | 474 __ j(below, &convert_to_object); |
477 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 475 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
478 __ j(less_equal, &done); | 476 __ j(below_equal, &shift_arguments); |
479 | 477 |
480 __ bind(&call_to_object); | 478 __ bind(&convert_to_object); |
481 __ EnterInternalFrame(); // preserves eax, ebx, edi | 479 __ EnterInternalFrame(); // In order to preserve argument count. |
482 | |
483 // Store the arguments count on the stack (smi tagged). | |
484 __ SmiTag(eax); | 480 __ SmiTag(eax); |
485 __ push(eax); | 481 __ push(eax); |
486 | 482 |
487 __ push(edi); // save edi across the call | |
488 __ push(ebx); | 483 __ push(ebx); |
489 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 484 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
490 __ mov(ebx, eax); | 485 __ mov(ebx, eax); |
491 __ pop(edi); // restore edi after the call | |
492 | 486 |
493 // Get the arguments count and untag it. | |
494 __ pop(eax); | 487 __ pop(eax); |
495 __ SmiUntag(eax); | 488 __ SmiUntag(eax); |
496 | |
497 __ LeaveInternalFrame(); | 489 __ LeaveInternalFrame(); |
| 490 // Restore the function to edi. |
| 491 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
498 __ jmp(&patch_receiver); | 492 __ jmp(&patch_receiver); |
499 | 493 |
500 // Use the global receiver object from the called function as the receiver. | 494 // Use the global receiver object from the called function as the |
| 495 // receiver. |
501 __ bind(&use_global_receiver); | 496 __ bind(&use_global_receiver); |
502 const int kGlobalIndex = | 497 const int kGlobalIndex = |
503 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 498 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
504 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); | 499 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
505 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); | 500 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); |
506 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); | 501 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); |
507 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 502 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
508 | 503 |
509 __ bind(&patch_receiver); | 504 __ bind(&patch_receiver); |
510 __ mov(Operand(esp, eax, times_4, 0), ebx); | 505 __ mov(Operand(esp, eax, times_4, 0), ebx); |
511 | 506 |
512 __ bind(&done); | 507 __ jmp(&shift_arguments); |
513 } | 508 } |
514 | 509 |
515 // 4. Check that the function really is a function. | 510 // 3b. Patch the first argument when calling a non-function. The |
516 { Label done; | 511 // CALL_NON_FUNCTION builtin expects the non-function callee as |
517 __ test(edi, Operand(edi)); | 512 // receiver, so overwrite the first argument which will ultimately |
518 __ j(not_zero, &done, taken); | 513 // become the receiver. |
519 __ xor_(ebx, Operand(ebx)); | 514 __ bind(&non_function); |
520 // CALL_NON_FUNCTION will expect to find the non-function callee on the | 515 __ mov(Operand(esp, eax, times_4, 0), edi); |
521 // expression stack of the caller. Transfer it from receiver to the | 516 // Clear edi to indicate a non-function being called. |
522 // caller's expression stack (and make the first argument the receiver | 517 __ xor_(edi, Operand(edi)); |
523 // for CALL_NON_FUNCTION) by decrementing the argument count. | |
524 __ dec(eax); | |
525 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | |
526 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | |
527 RelocInfo::CODE_TARGET); | |
528 __ bind(&done); | |
529 } | |
530 | 518 |
531 // 5. Shift arguments and return address one slot down on the stack | 519 // 4. Shift arguments and return address one slot down on the stack |
532 // (overwriting the receiver). | 520 // (overwriting the original receiver). Adjust argument count to make |
| 521 // the original first argument the new receiver. |
| 522 __ bind(&shift_arguments); |
533 { Label loop; | 523 { Label loop; |
534 __ mov(ecx, eax); | 524 __ mov(ecx, eax); |
535 __ bind(&loop); | 525 __ bind(&loop); |
536 __ mov(ebx, Operand(esp, ecx, times_4, 0)); | 526 __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
537 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); | 527 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
538 __ dec(ecx); | 528 __ dec(ecx); |
539 __ j(not_sign, &loop); | 529 __ j(not_sign, &loop); // While non-negative (to copy return address). |
540 __ pop(ebx); // Discard copy of return address. | 530 __ pop(ebx); // Discard copy of return address. |
541 __ dec(eax); // One fewer argument (first argument is new receiver). | 531 __ dec(eax); // One fewer argument (first argument is new receiver). |
542 } | 532 } |
543 | 533 |
544 // 6. Get the code to call from the function and check that the number of | 534 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. |
545 // expected arguments matches what we're providing. | 535 { Label function; |
546 { __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 536 __ test(edi, Operand(edi)); |
547 __ mov(ebx, | 537 __ j(not_zero, &function, taken); |
548 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); | 538 __ xor_(ebx, Operand(ebx)); |
549 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); | 539 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
550 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 540 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
551 __ cmp(eax, Operand(ebx)); | 541 RelocInfo::CODE_TARGET); |
552 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); | 542 __ bind(&function); |
553 } | 543 } |
554 | 544 |
555 // 7. Jump (tail-call) to the code in register edx without checking arguments. | 545 // 5b. Get the code to call from the function and check that the number of |
| 546 // expected arguments matches what we're providing. If so, jump |
| 547 // (tail-call) to the code in register edx without checking arguments. |
| 548 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 549 __ mov(ebx, |
| 550 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 551 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
| 552 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 553 __ cmp(eax, Operand(ebx)); |
| 554 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); |
| 555 |
556 ParameterCount expected(0); | 556 ParameterCount expected(0); |
557 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); | 557 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); |
558 } | 558 } |
559 | 559 |
560 | 560 |
561 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 561 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
562 __ EnterInternalFrame(); | 562 __ EnterInternalFrame(); |
563 | 563 |
564 __ push(Operand(ebp, 4 * kPointerSize)); // push this | 564 __ push(Operand(ebp, 4 * kPointerSize)); // push this |
565 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments | 565 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments |
(...skipping 688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1254 // Dont adapt arguments. | 1254 // Dont adapt arguments. |
1255 // ------------------------------------------- | 1255 // ------------------------------------------- |
1256 __ bind(&dont_adapt_arguments); | 1256 __ bind(&dont_adapt_arguments); |
1257 __ jmp(Operand(edx)); | 1257 __ jmp(Operand(edx)); |
1258 } | 1258 } |
1259 | 1259 |
1260 | 1260 |
1261 #undef __ | 1261 #undef __ |
1262 | 1262 |
1263 } } // namespace v8::internal | 1263 } } // namespace v8::internal |
OLD | NEW |