| 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 |