| 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 // 1 ~ return address. |
| 444 __ test(edi, Immediate(kSmiTagMask)); | 447 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
| 445 __ j(zero, &non_function, not_taken); | 448 __ test(edi, Immediate(kSmiTagMask)); |
| 446 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 449 __ j(zero, &non_function, not_taken); |
| 447 __ j(equal, &function, taken); | 450 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 451 __ j(not_equal, &non_function, not_taken); |
| 448 | 452 |
| 449 // Non-function called: Clear the function to force exception. | |
| 450 __ bind(&non_function); | |
| 451 __ xor_(edi, Operand(edi)); | |
| 452 __ jmp(&done); | |
| 453 | 453 |
| 454 // Function called: Change context eagerly to get the right global object. | 454 // 3a. Patch the first argument if necessary when calling a function. |
| 455 __ bind(&function); | 455 Label shift_arguments; |
| 456 { Label convert_to_object, use_global_receiver, patch_receiver; |
| 457 // Change context eagerly in case we need the global receiver. |
| 456 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 458 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 457 | 459 |
| 458 __ bind(&done); | 460 __ 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)); | 461 __ test(ebx, Immediate(kSmiTagMask)); |
| 466 __ j(zero, &call_to_object); | 462 __ j(zero, &convert_to_object); |
| 467 | 463 |
| 468 __ cmp(ebx, Factory::null_value()); | 464 __ cmp(ebx, Factory::null_value()); |
| 469 __ j(equal, &use_global_receiver); | 465 __ j(equal, &use_global_receiver); |
| 470 __ cmp(ebx, Factory::undefined_value()); | 466 __ cmp(ebx, Factory::undefined_value()); |
| 471 __ j(equal, &use_global_receiver); | 467 __ j(equal, &use_global_receiver); |
| 472 | 468 |
| 473 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); | 469 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
| 474 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 470 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 475 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 471 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 476 __ j(less, &call_to_object); | 472 __ j(below, &convert_to_object); |
| 477 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 473 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 478 __ j(less_equal, &done); | 474 __ j(below_equal, &shift_arguments); |
| 479 | 475 |
| 480 __ bind(&call_to_object); | 476 __ bind(&convert_to_object); |
| 481 __ EnterInternalFrame(); // preserves eax, ebx, edi | 477 __ EnterInternalFrame(); // In order to preserve argument count. |
| 482 | |
| 483 // Store the arguments count on the stack (smi tagged). | |
| 484 __ SmiTag(eax); | 478 __ SmiTag(eax); |
| 485 __ push(eax); | 479 __ push(eax); |
| 486 | 480 |
| 487 __ push(edi); // save edi across the call | |
| 488 __ push(ebx); | 481 __ push(ebx); |
| 489 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 482 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 490 __ mov(ebx, eax); | 483 __ mov(ebx, eax); |
| 491 __ pop(edi); // restore edi after the call | |
| 492 | 484 |
| 493 // Get the arguments count and untag it. | |
| 494 __ pop(eax); | 485 __ pop(eax); |
| 495 __ SmiUntag(eax); | 486 __ SmiUntag(eax); |
| 496 | |
| 497 __ LeaveInternalFrame(); | 487 __ LeaveInternalFrame(); |
| 488 // Restore the function to edi. |
| 489 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
| 498 __ jmp(&patch_receiver); | 490 __ jmp(&patch_receiver); |
| 499 | 491 |
| 500 // Use the global receiver object from the called function as the receiver. | 492 // Use the global receiver object from the called function as the |
| 493 // receiver. |
| 501 __ bind(&use_global_receiver); | 494 __ bind(&use_global_receiver); |
| 502 const int kGlobalIndex = | 495 const int kGlobalIndex = |
| 503 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 496 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 504 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); | 497 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
| 505 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); | 498 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); |
| 506 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); | 499 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); |
| 507 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 500 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 508 | 501 |
| 509 __ bind(&patch_receiver); | 502 __ bind(&patch_receiver); |
| 510 __ mov(Operand(esp, eax, times_4, 0), ebx); | 503 __ mov(Operand(esp, eax, times_4, 0), ebx); |
| 511 | 504 |
| 512 __ bind(&done); | 505 __ jmp(&shift_arguments); |
| 513 } | 506 } |
| 514 | 507 |
| 515 // 4. Check that the function really is a function. | 508 // 3b. Patch the first argument when calling a non-function. The |
| 516 { Label done; | 509 // CALL_NON_FUNCTION builtin expects the non-function callee as |
| 517 __ test(edi, Operand(edi)); | 510 // receiver, so overwrite the first argument which will ultimately |
| 518 __ j(not_zero, &done, taken); | 511 // become the receiver. |
| 519 __ xor_(ebx, Operand(ebx)); | 512 __ bind(&non_function); |
| 520 // CALL_NON_FUNCTION will expect to find the non-function callee on the | 513 __ mov(Operand(esp, eax, times_4, 0), edi); |
| 521 // expression stack of the caller. Transfer it from receiver to the | 514 // Clear edi to indicate a non-function being called. |
| 522 // caller's expression stack (and make the first argument the receiver | 515 __ 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 | 516 |
| 531 // 5. Shift arguments and return address one slot down on the stack | 517 // 4. Shift arguments and return address one slot down on the stack |
| 532 // (overwriting the receiver). | 518 // (overwriting the original receiver). Adjust argument count to make |
| 519 // the original first argument the new receiver. |
| 520 __ bind(&shift_arguments); |
| 533 { Label loop; | 521 { Label loop; |
| 534 __ mov(ecx, eax); | 522 __ mov(ecx, eax); |
| 535 __ bind(&loop); | 523 __ bind(&loop); |
| 536 __ mov(ebx, Operand(esp, ecx, times_4, 0)); | 524 __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
| 537 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); | 525 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
| 538 __ dec(ecx); | 526 __ dec(ecx); |
| 539 __ j(not_sign, &loop); | 527 __ j(not_sign, &loop); // While non-negative (to copy return address). |
| 540 __ pop(ebx); // Discard copy of return address. | 528 __ pop(ebx); // Discard copy of return address. |
| 541 __ dec(eax); // One fewer argument (first argument is new receiver). | 529 __ dec(eax); // One fewer argument (first argument is new receiver). |
| 542 } | 530 } |
| 543 | 531 |
| 544 // 6. Get the code to call from the function and check that the number of | 532 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. |
| 545 // expected arguments matches what we're providing. | 533 { Label function; |
| 546 { __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 534 __ test(edi, Operand(edi)); |
| 547 __ mov(ebx, | 535 __ j(not_zero, &function, taken); |
| 548 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); | 536 __ xor_(ebx, Operand(ebx)); |
| 549 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); | 537 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
| 550 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 538 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
| 551 __ cmp(eax, Operand(ebx)); | 539 RelocInfo::CODE_TARGET); |
| 552 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); | 540 __ bind(&function); |
| 553 } | 541 } |
| 554 | 542 |
| 555 // 7. Jump (tail-call) to the code in register edx without checking arguments. | 543 // 5b. Get the code to call from the function and check that the number of |
| 544 // expected arguments matches what we're providing. If so, jump |
| 545 // (tail-call) to the code in register edx without checking arguments. |
| 546 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 547 __ mov(ebx, |
| 548 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 549 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
| 550 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 551 __ cmp(eax, Operand(ebx)); |
| 552 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); |
| 553 |
| 556 ParameterCount expected(0); | 554 ParameterCount expected(0); |
| 557 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); | 555 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); |
| 558 } | 556 } |
| 559 | 557 |
| 560 | 558 |
| 561 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 559 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 562 __ EnterInternalFrame(); | 560 __ EnterInternalFrame(); |
| 563 | 561 |
| 564 __ push(Operand(ebp, 4 * kPointerSize)); // push this | 562 __ push(Operand(ebp, 4 * kPointerSize)); // push this |
| 565 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments | 563 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 | 638 |
| 641 // Push the receiver. | 639 // Push the receiver. |
| 642 __ bind(&push_receiver); | 640 __ bind(&push_receiver); |
| 643 __ push(ebx); | 641 __ push(ebx); |
| 644 | 642 |
| 645 // Copy all arguments from the array to the stack. | 643 // Copy all arguments from the array to the stack. |
| 646 Label entry, loop; | 644 Label entry, loop; |
| 647 __ mov(eax, Operand(ebp, kIndexOffset)); | 645 __ mov(eax, Operand(ebp, kIndexOffset)); |
| 648 __ jmp(&entry); | 646 __ jmp(&entry); |
| 649 __ bind(&loop); | 647 __ bind(&loop); |
| 650 __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments | 648 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments |
| 651 __ push(ecx); | |
| 652 __ push(eax); | |
| 653 | 649 |
| 654 // Use inline caching to speed up access to arguments. | 650 // Use inline caching to speed up access to arguments. |
| 655 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 651 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 656 __ call(ic, RelocInfo::CODE_TARGET); | 652 __ call(ic, RelocInfo::CODE_TARGET); |
| 657 // It is important that we do not have a test instruction after the | 653 // It is important that we do not have a test instruction after the |
| 658 // call. A test instruction after the call is used to indicate that | 654 // call. A test instruction after the call is used to indicate that |
| 659 // we have generated an inline version of the keyed load. In this | 655 // we have generated an inline version of the keyed load. In this |
| 660 // case, we know that we are not generating a test instruction next. | 656 // case, we know that we are not generating a test instruction next. |
| 661 | 657 |
| 662 // Remove IC arguments from the stack and push the nth argument. | 658 // Push the nth argument. |
| 663 __ add(Operand(esp), Immediate(2 * kPointerSize)); | |
| 664 __ push(eax); | 659 __ push(eax); |
| 665 | 660 |
| 666 // Update the index on the stack and in register eax. | 661 // Update the index on the stack and in register eax. |
| 667 __ mov(eax, Operand(ebp, kIndexOffset)); | 662 __ mov(eax, Operand(ebp, kIndexOffset)); |
| 668 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); | 663 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); |
| 669 __ mov(Operand(ebp, kIndexOffset), eax); | 664 __ mov(Operand(ebp, kIndexOffset), eax); |
| 670 | 665 |
| 671 __ bind(&entry); | 666 __ bind(&entry); |
| 672 __ cmp(eax, Operand(ebp, kLimitOffset)); | 667 __ cmp(eax, Operand(ebp, kLimitOffset)); |
| 673 __ j(not_equal, &loop); | 668 __ j(not_equal, &loop); |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 // Dont adapt arguments. | 1249 // Dont adapt arguments. |
| 1255 // ------------------------------------------- | 1250 // ------------------------------------------- |
| 1256 __ bind(&dont_adapt_arguments); | 1251 __ bind(&dont_adapt_arguments); |
| 1257 __ jmp(Operand(edx)); | 1252 __ jmp(Operand(edx)); |
| 1258 } | 1253 } |
| 1259 | 1254 |
| 1260 | 1255 |
| 1261 #undef __ | 1256 #undef __ |
| 1262 | 1257 |
| 1263 } } // namespace v8::internal | 1258 } } // namespace v8::internal |
| OLD | NEW |