OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 2403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2414 __ RecordWriteArray(ebx, edi, edx, kDontSaveFPRegs, | 2414 __ RecordWriteArray(ebx, edi, edx, kDontSaveFPRegs, |
2415 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 2415 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
2416 __ pop(edx); | 2416 __ pop(edx); |
2417 __ pop(ebx); | 2417 __ pop(ebx); |
2418 __ pop(edi); | 2418 __ pop(edi); |
2419 | 2419 |
2420 __ bind(&done); | 2420 __ bind(&done); |
2421 } | 2421 } |
2422 | 2422 |
2423 | 2423 |
2424 void CallICStub::GenerateCall(MacroAssembler* masm, bool monomorphic, | |
Toon Verwaest
2014/03/10 13:50:44
one arg per line
mvstanton
2014/03/20 15:51:53
Done.
| |
2425 bool args_match, bool strict_or_native) { | |
2426 Isolate* isolate = masm->isolate(); | |
2427 Label slow, non_function, cont, wrap; | |
2428 ParameterCount actual(arg_count()); | |
2429 | |
2430 if (!monomorphic) { | |
2431 // Check that the function really is a JavaScript function. | |
2432 __ JumpIfSmi(edi, &non_function); | |
2433 | |
2434 // Goto slow case if we do not have a function. | |
2435 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
2436 __ j(not_equal, &slow); | |
2437 } | |
2438 | |
2439 if (call_as_method()) { | |
2440 if (!monomorphic) { | |
2441 // Do not transform the receiver for strict mode functions. | |
2442 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
2443 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), | |
2444 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | |
2445 __ j(not_equal, &cont); | |
2446 | |
2447 // Do not transform the receiver for natives (shared already in ecx). | |
2448 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), | |
2449 1 << SharedFunctionInfo::kNativeBitWithinByte); | |
2450 __ j(not_equal, &cont); | |
2451 } | |
2452 | |
2453 if (!strict_or_native) { | |
2454 // Load the receiver from the stack. | |
2455 __ mov(eax, Operand(esp, (arg_count() + 1) * kPointerSize)); | |
2456 | |
2457 __ JumpIfSmi(eax, &wrap); | |
2458 | |
2459 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | |
2460 __ j(below, &wrap); | |
2461 } | |
2462 | |
2463 __ bind(&cont); | |
2464 } | |
2465 | |
2466 if (args_match) { | |
2467 __ InvokeFunction(edi, actual, actual, JUMP_FUNCTION, NullCallWrapper()); | |
2468 } else { | |
2469 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
2470 } | |
2471 | |
2472 if (!monomorphic) { | |
2473 // Slow-case: Non-function called. | |
2474 __ bind(&slow); | |
2475 // Check for function proxy. | |
2476 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); | |
2477 __ j(not_equal, &non_function); | |
2478 __ pop(ecx); | |
2479 __ push(edi); // put proxy as additional argument under return address | |
2480 __ push(ecx); | |
2481 __ Set(eax, Immediate(arg_count() + 1)); | |
2482 __ Set(ebx, Immediate(0)); | |
2483 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | |
2484 { | |
2485 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); | |
2486 __ jmp(adaptor, RelocInfo::CODE_TARGET); | |
2487 } | |
2488 | |
2489 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | |
2490 // of the original receiver from the call site). | |
2491 __ bind(&non_function); | |
2492 __ mov(Operand(esp, (arg_count() + 1) * kPointerSize), edi); | |
2493 __ Set(eax, Immediate(arg_count())); | |
2494 __ Set(ebx, Immediate(0)); | |
2495 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | |
2496 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); | |
2497 __ jmp(adaptor, RelocInfo::CODE_TARGET); | |
2498 } | |
2499 | |
2500 if (call_as_method() && !strict_or_native) { | |
2501 __ bind(&wrap); | |
2502 // Wrap the receiver and patch it back onto the stack. | |
2503 { FrameScope frame_scope(masm, StackFrame::INTERNAL); | |
2504 __ push(edi); | |
2505 __ push(eax); | |
2506 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | |
2507 __ pop(edi); | |
2508 } | |
2509 __ mov(Operand(esp, (arg_count() + 1) * kPointerSize), eax); | |
2510 __ jmp(&cont); | |
2511 } | |
2512 } | |
2513 | |
2514 | |
2515 void CallICStub::Generate(MacroAssembler* masm) { | |
2516 // edi - function | |
2517 // ebx - vector | |
2518 // edx - slot id | |
2519 Label mono, slow; | |
2520 | |
2521 Isolate* isolate = masm->isolate(); | |
2522 if (!monomorphic()) { | |
2523 Label miss_uninit; | |
2524 | |
2525 // The checks. First, does edi match the cell? | |
2526 __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, | |
2527 FixedArray::kHeaderSize)); | |
2528 __ cmp(ecx, edi); | |
Toon Verwaest
2014/03/10 13:50:44
Wouldn't it be faster to flip over the conditions,
mvstanton
2014/03/20 15:51:53
Excellent idea, it reads cleaner too.
| |
2529 __ j(equal, &mono); | |
2530 __ cmp(ecx, Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate))); | |
2531 __ j(equal, &slow); | |
2532 __ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate))); | |
2533 __ j(equal, &miss_uninit); | |
2534 // If we got here we went megamorphic. Don't bother missing, just update. | |
Toon Verwaest
2014/03/10 13:50:44
we went -> If we get here, go from monomorphic to
mvstanton
2014/03/20 15:51:53
Done.
| |
2535 __ mov(FieldOperand(ebx, edx, times_half_pointer_size, | |
2536 FixedArray::kHeaderSize), | |
2537 Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate))); | |
2538 __ jmp(&slow); | |
2539 | |
2540 __ bind(&miss_uninit); | |
2541 GenerateMiss(masm); | |
2542 __ jmp(&slow); | |
2543 } else { | |
2544 // Verify still monomorphic, miss otherwise | |
Toon Verwaest
2014/03/10 13:50:44
Verify whether the input function matches the reco
mvstanton
2014/03/20 15:51:53
After rearranging the function, I kept your ideal
| |
2545 __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, | |
2546 FixedArray::kHeaderSize)); | |
2547 __ cmp(ecx, edi); | |
2548 __ j(equal, &mono); | |
Toon Verwaest
2014/03/10 13:50:44
Same here as above. This path should be inlined he
mvstanton
2014/03/20 15:51:53
Done.
| |
2549 // Uh-oh, we missed, have to fall back to slow stub, go ahead and patch but | |
2550 // we still have to handle the slow case. | |
2551 GenerateMiss(masm); | |
2552 __ jmp(&slow); | |
2553 } | |
2554 | |
2555 __ bind(&mono); | |
2556 if (!monomorphic()) { | |
2557 GenerateCall(masm, true, true, false); | |
2558 } else { | |
2559 GenerateCall(masm, true, args_match(), strict_native()); | |
2560 } | |
2561 | |
2562 // the slow case | |
2563 __ bind(&slow); | |
2564 GenerateCall(masm, false, false, false); | |
2565 } | |
2566 | |
2567 | |
2568 void CallICStub::GenerateMiss(MacroAssembler* masm) { | |
2569 // Get the receiver of the function from the stack; 1 ~ return address. | |
2570 __ mov(ecx, Operand(esp, (arg_count() + 1) * kPointerSize)); | |
2571 | |
2572 { | |
2573 FrameScope scope(masm, StackFrame::INTERNAL); | |
2574 | |
2575 // Push the receiver and the function and feedback info. | |
2576 __ push(ecx); | |
2577 __ push(edi); | |
2578 __ push(ebx); | |
2579 __ push(edx); | |
2580 | |
2581 // Call the entry. | |
2582 CEntryStub stub(1); | |
2583 __ mov(eax, Immediate(4)); | |
2584 __ mov(ebx, Immediate(ExternalReference(IC_Utility(IC::kCallIC_Miss), | |
2585 masm->isolate()))); | |
2586 __ CallStub(&stub); | |
2587 | |
2588 // Move result to edi and exit the internal frame. | |
2589 __ mov(edi, eax); | |
2590 } | |
2591 } | |
2592 | |
2593 | |
2424 void CallFunctionStub::Generate(MacroAssembler* masm) { | 2594 void CallFunctionStub::Generate(MacroAssembler* masm) { |
2425 // ebx : feedback vector | 2595 // ebx : feedback vector |
2426 // edx : (only if ebx is not the megamorphic symbol) slot in feedback | 2596 // edx : (only if ebx is not the megamorphic symbol) slot in feedback |
2427 // vector (Smi) | 2597 // vector (Smi) |
2428 // edi : the function to call | 2598 // edi : the function to call |
2429 Isolate* isolate = masm->isolate(); | 2599 Isolate* isolate = masm->isolate(); |
2430 Label slow, non_function, wrap, cont; | 2600 Label slow, non_function, wrap, cont; |
2431 | 2601 |
2432 if (NeedsChecks()) { | 2602 if (NeedsChecks()) { |
2433 // Check that the function really is a JavaScript function. | 2603 // Check that the function really is a JavaScript function. |
2434 __ JumpIfSmi(edi, &non_function); | 2604 __ JumpIfSmi(edi, &non_function); |
2435 | 2605 |
2436 // Goto slow case if we do not have a function. | 2606 // Goto slow case if we do not have a function. |
2437 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 2607 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
2438 __ j(not_equal, &slow); | 2608 __ j(not_equal, &slow); |
2439 | |
2440 if (RecordCallTarget()) { | |
2441 GenerateRecordCallTarget(masm); | |
2442 } | |
2443 } | 2609 } |
2444 | 2610 |
2445 // Fast-case: Just invoke the function. | 2611 // Fast-case: Just invoke the function. |
2446 ParameterCount actual(argc_); | 2612 ParameterCount actual(argc_); |
2447 | 2613 |
2448 if (CallAsMethod()) { | 2614 if (CallAsMethod()) { |
2449 if (NeedsChecks()) { | 2615 if (NeedsChecks()) { |
2450 // Do not transform the receiver for strict mode functions. | 2616 // Do not transform the receiver for strict mode functions. |
2451 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 2617 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
2452 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), | 2618 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), |
(...skipping 19 matching lines...) Expand all Loading... | |
2472 } | 2638 } |
2473 | 2639 |
2474 __ bind(&cont); | 2640 __ bind(&cont); |
2475 } | 2641 } |
2476 | 2642 |
2477 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | 2643 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); |
2478 | 2644 |
2479 if (NeedsChecks()) { | 2645 if (NeedsChecks()) { |
2480 // Slow-case: Non-function called. | 2646 // Slow-case: Non-function called. |
2481 __ bind(&slow); | 2647 __ bind(&slow); |
2482 if (RecordCallTarget()) { | |
2483 // If there is a call target cache, mark it megamorphic in the | |
2484 // non-function case. MegamorphicSentinel is an immortal immovable | |
2485 // object (megamorphic symbol) so no write barrier is needed. | |
2486 __ mov(FieldOperand(ebx, edx, times_half_pointer_size, | |
2487 FixedArray::kHeaderSize), | |
2488 Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate))); | |
2489 } | |
2490 // Check for function proxy. | 2648 // Check for function proxy. |
2491 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); | 2649 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); |
2492 __ j(not_equal, &non_function); | 2650 __ j(not_equal, &non_function); |
2493 __ pop(ecx); | 2651 __ pop(ecx); |
2494 __ push(edi); // put proxy as additional argument under return address | 2652 __ push(edi); // put proxy as additional argument under return address |
2495 __ push(ecx); | 2653 __ push(ecx); |
2496 __ Set(eax, Immediate(argc_ + 1)); | 2654 __ Set(eax, Immediate(argc_ + 1)); |
2497 __ Set(ebx, Immediate(0)); | 2655 __ Set(ebx, Immediate(0)); |
2498 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | 2656 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); |
2499 { | 2657 { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2579 } | 2737 } |
2580 | 2738 |
2581 | 2739 |
2582 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 2740 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
2583 CEntryStub::GenerateAheadOfTime(isolate); | 2741 CEntryStub::GenerateAheadOfTime(isolate); |
2584 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2742 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
2585 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 2743 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
2586 // It is important that the store buffer overflow stubs are generated first. | 2744 // It is important that the store buffer overflow stubs are generated first. |
2587 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 2745 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
2588 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 2746 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
2747 // CallICStub::GenerateAheadOfTime(isolate); | |
2589 if (Serializer::enabled()) { | 2748 if (Serializer::enabled()) { |
2590 PlatformFeatureScope sse2(SSE2); | 2749 PlatformFeatureScope sse2(SSE2); |
2591 BinaryOpICStub::GenerateAheadOfTime(isolate); | 2750 BinaryOpICStub::GenerateAheadOfTime(isolate); |
2592 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); | 2751 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); |
2593 } else { | 2752 } else { |
2594 BinaryOpICStub::GenerateAheadOfTime(isolate); | 2753 BinaryOpICStub::GenerateAheadOfTime(isolate); |
2595 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); | 2754 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); |
2596 } | 2755 } |
2597 } | 2756 } |
2598 | 2757 |
(...skipping 2852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5451 Operand(ebp, 7 * kPointerSize), | 5610 Operand(ebp, 7 * kPointerSize), |
5452 NULL); | 5611 NULL); |
5453 } | 5612 } |
5454 | 5613 |
5455 | 5614 |
5456 #undef __ | 5615 #undef __ |
5457 | 5616 |
5458 } } // namespace v8::internal | 5617 } } // namespace v8::internal |
5459 | 5618 |
5460 #endif // V8_TARGET_ARCH_IA32 | 5619 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |