OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 2390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2401 | 2401 |
2402 | 2402 |
2403 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 2403 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
2404 CEntryStub stub(1, kDontSaveFPRegs); | 2404 CEntryStub stub(1, kDontSaveFPRegs); |
2405 stub.GetCode(isolate); | 2405 stub.GetCode(isolate); |
2406 CEntryStub save_doubles(1, kSaveFPRegs); | 2406 CEntryStub save_doubles(1, kSaveFPRegs); |
2407 save_doubles.GetCode(isolate); | 2407 save_doubles.GetCode(isolate); |
2408 } | 2408 } |
2409 | 2409 |
2410 | 2410 |
2411 void CEntryStub::GenerateCore(MacroAssembler* masm, | 2411 void CEntryStub::Generate(MacroAssembler* masm) { |
2412 Label* throw_normal_exception, | 2412 // rax: number of arguments including receiver |
2413 Label* throw_termination_exception, | 2413 // rbx: pointer to C function (C callee-saved) |
2414 bool do_gc, | 2414 // rbp: frame pointer of calling JS frame (restored after C call) |
2415 bool always_allocate_scope) { | 2415 // rsp: stack pointer (restored after C call) |
2416 // rax: result parameter for PerformGC, if any. | 2416 // rsi: current context (restored) |
2417 // rbx: pointer to C function (C callee-saved). | 2417 |
2418 // rbp: frame pointer (restored after C call). | 2418 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
2419 // rsp: stack pointer (restored after C call). | 2419 |
2420 // Enter the exit frame that transitions from JavaScript to C++. | |
2421 #ifdef _WIN64 | |
2422 int arg_stack_space = (result_size_ < 2 ? 2 : 4); | |
2423 #else | |
2424 int arg_stack_space = 0; | |
2425 #endif | |
2426 __ EnterExitFrame(arg_stack_space, save_doubles_); | |
2427 | |
2428 // rax: Holds the context at this point, but should not be used. | |
2429 // On entry to code generated by GenerateCore, it must hold | |
Jakob Kummerow
2014/04/22 12:22:23
"GenerateCore" doesn't exist any more.
| |
2430 // a failure result if the collect_garbage argument to GenerateCore | |
2431 // is true. This failure result can be the result of code | |
2432 // generated by a previous call to GenerateCore. The value | |
2433 // of rax is then passed to Runtime::PerformGC. | |
2434 // rbx: pointer to builtin function (C callee-saved). | |
2435 // rbp: frame pointer of exit frame (restored after C call). | |
2436 // rsp: stack pointer (restored after C call). | |
2420 // r14: number of arguments including receiver (C callee-saved). | 2437 // r14: number of arguments including receiver (C callee-saved). |
2421 // r15: pointer to the first argument (C callee-saved). | 2438 // r15: argv pointer (C callee-saved). |
2422 // This pointer is reused in LeaveExitFrame(), so it is stored in a | |
2423 // callee-saved register. | |
2424 | 2439 |
2425 // Simple results returned in rax (both AMD64 and Win64 calling conventions). | 2440 // Simple results returned in rax (both AMD64 and Win64 calling conventions). |
2426 // Complex results must be written to address passed as first argument. | 2441 // Complex results must be written to address passed as first argument. |
2427 // AMD64 calling convention: a struct of two pointers in rax+rdx | 2442 // AMD64 calling convention: a struct of two pointers in rax+rdx |
2428 | 2443 |
2429 // Check stack alignment. | 2444 // Check stack alignment. |
2430 if (FLAG_debug_code) { | 2445 if (FLAG_debug_code) { |
2431 __ CheckStackAlignment(); | 2446 __ CheckStackAlignment(); |
2432 } | 2447 } |
2433 | 2448 |
2434 if (do_gc) { | |
2435 // Pass failure code returned from last attempt as first argument to | |
2436 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the | |
2437 // stack is known to be aligned. This function takes one argument which is | |
2438 // passed in register. | |
2439 __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate())); | |
2440 __ movp(arg_reg_1, rax); | |
2441 __ Move(kScratchRegister, | |
2442 ExternalReference::perform_gc_function(masm->isolate())); | |
2443 __ call(kScratchRegister); | |
2444 } | |
2445 | |
2446 ExternalReference scope_depth = | |
2447 ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); | |
2448 if (always_allocate_scope) { | |
2449 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); | |
2450 __ incl(scope_depth_operand); | |
2451 } | |
2452 | |
2453 // Call C function. | 2449 // Call C function. |
2454 #ifdef _WIN64 | 2450 #ifdef _WIN64 |
2455 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. | 2451 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. |
2456 // Pass argv and argc as two parameters. The arguments object will | 2452 // Pass argv and argc as two parameters. The arguments object will |
2457 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). | 2453 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). |
2458 if (result_size_ < 2) { | 2454 if (result_size_ < 2) { |
2459 // Pass a pointer to the Arguments object as the first argument. | 2455 // Pass a pointer to the Arguments object as the first argument. |
2460 // Return result in single register (rax). | 2456 // Return result in single register (rax). |
2461 __ movp(rcx, r14); // argc. | 2457 __ movp(rcx, r14); // argc. |
2462 __ movp(rdx, r15); // argv. | 2458 __ movp(rdx, r15); // argv. |
(...skipping 10 matching lines...) Expand all Loading... | |
2473 | 2469 |
2474 #else // _WIN64 | 2470 #else // _WIN64 |
2475 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. | 2471 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. |
2476 __ movp(rdi, r14); // argc. | 2472 __ movp(rdi, r14); // argc. |
2477 __ movp(rsi, r15); // argv. | 2473 __ movp(rsi, r15); // argv. |
2478 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); | 2474 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); |
2479 #endif | 2475 #endif |
2480 __ call(rbx); | 2476 __ call(rbx); |
2481 // Result is in rax - do not destroy this register! | 2477 // Result is in rax - do not destroy this register! |
2482 | 2478 |
2483 if (always_allocate_scope) { | |
2484 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); | |
2485 __ decl(scope_depth_operand); | |
2486 } | |
2487 | |
2488 // Check for failure result. | |
2489 Label failure_returned; | |
2490 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | |
2491 #ifdef _WIN64 | 2479 #ifdef _WIN64 |
2492 // If return value is on the stack, pop it to registers. | 2480 // If return value is on the stack, pop it to registers. |
2493 if (result_size_ > 1) { | 2481 if (result_size_ > 1) { |
2494 ASSERT_EQ(2, result_size_); | 2482 ASSERT_EQ(2, result_size_); |
2495 // Read result values stored on stack. Result is stored | 2483 // Read result values stored on stack. Result is stored |
2496 // above the four argument mirror slots and the two | 2484 // above the four argument mirror slots and the two |
2497 // Arguments object slots. | 2485 // Arguments object slots. |
2498 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); | 2486 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); |
2499 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); | 2487 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); |
2500 } | 2488 } |
2501 #endif | 2489 #endif |
2502 __ leap(rcx, Operand(rax, 1)); | 2490 |
2503 // Lower 2 bits of rcx are 0 iff rax has failure tag. | 2491 // Runtime functions should not return 'the hole'. Allowing it to escape may |
2504 __ testl(rcx, Immediate(kFailureTagMask)); | 2492 // lead to crashes in the IC code later. |
2505 __ j(zero, &failure_returned); | 2493 if (FLAG_debug_code) { |
2494 Label okay; | |
2495 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | |
2496 __ j(not_equal, &okay, Label::kNear); | |
2497 __ int3(); | |
2498 __ bind(&okay); | |
2499 } | |
2500 | |
2501 // Check for failure result. | |
2502 Label failure_returned; | |
2503 __ CompareRoot(rax, Heap::kExceptionRootIndex); | |
2504 __ j(equal, &failure_returned); | |
2505 | |
2506 ExternalReference pending_exception_address( | |
2507 Isolate::kPendingExceptionAddress, masm->isolate()); | |
2508 | |
2509 // Check that there is no pending exception, otherwise we | |
2510 // should have returned the exception sentinel. | |
2511 if (FLAG_debug_code) { | |
2512 Label okay; | |
2513 __ LoadRoot(r14, Heap::kTheHoleValueRootIndex); | |
2514 Operand pending_exception_operand = | |
2515 masm->ExternalOperand(pending_exception_address); | |
2516 __ cmpq(r14, pending_exception_operand); | |
Jakob Kummerow
2014/04/22 12:22:23
I think the x32 port requires a "cmpp" here ("p" a
| |
2517 __ j(equal, &okay, Label::kNear); | |
2518 __ int3(); | |
2519 __ bind(&okay); | |
2520 } | |
2506 | 2521 |
2507 // Exit the JavaScript to C++ exit frame. | 2522 // Exit the JavaScript to C++ exit frame. |
2508 __ LeaveExitFrame(save_doubles_); | 2523 __ LeaveExitFrame(save_doubles_); |
2509 __ ret(0); | 2524 __ ret(0); |
2510 | 2525 |
2511 // Handling of failure. | 2526 // Handling of failure. |
2512 __ bind(&failure_returned); | 2527 __ bind(&failure_returned); |
2513 | 2528 |
2514 Label retry; | |
2515 // If the returned exception is RETRY_AFTER_GC continue at retry label | |
2516 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | |
2517 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | |
2518 __ j(zero, &retry, Label::kNear); | |
2519 | |
2520 // Retrieve the pending exception. | 2529 // Retrieve the pending exception. |
2521 ExternalReference pending_exception_address( | |
2522 Isolate::kPendingExceptionAddress, masm->isolate()); | |
2523 Operand pending_exception_operand = | 2530 Operand pending_exception_operand = |
2524 masm->ExternalOperand(pending_exception_address); | 2531 masm->ExternalOperand(pending_exception_address); |
2525 __ movp(rax, pending_exception_operand); | 2532 __ movp(rax, pending_exception_operand); |
2526 | 2533 |
2527 // Clear the pending exception. | 2534 // Clear the pending exception. |
2528 pending_exception_operand = | |
2529 masm->ExternalOperand(pending_exception_address); | |
2530 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 2535 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
2531 __ movp(pending_exception_operand, rdx); | 2536 __ movp(pending_exception_operand, rdx); |
2532 | 2537 |
2533 // Special handling of termination exceptions which are uncatchable | 2538 // Special handling of termination exceptions which are uncatchable |
2534 // by javascript code. | 2539 // by javascript code. |
2540 Label throw_termination_exception; | |
2535 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 2541 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
2536 __ j(equal, throw_termination_exception); | 2542 __ j(equal, &throw_termination_exception); |
2537 | 2543 |
2538 // Handle normal exception. | 2544 // Handle normal exception. |
2539 __ jmp(throw_normal_exception); | 2545 __ Throw(rax); |
2540 | 2546 |
2541 // Retry. | 2547 __ bind(&throw_termination_exception); |
2542 __ bind(&retry); | 2548 __ ThrowUncatchable(rax); |
2543 } | 2549 } |
2544 | 2550 |
2545 | 2551 |
2546 void CEntryStub::Generate(MacroAssembler* masm) { | |
2547 // rax: number of arguments including receiver | |
2548 // rbx: pointer to C function (C callee-saved) | |
2549 // rbp: frame pointer of calling JS frame (restored after C call) | |
2550 // rsp: stack pointer (restored after C call) | |
2551 // rsi: current context (restored) | |
2552 | |
2553 // NOTE: Invocations of builtins may return failure objects | |
2554 // instead of a proper result. The builtin entry handles | |
2555 // this by performing a garbage collection and retrying the | |
2556 // builtin once. | |
2557 | |
2558 ProfileEntryHookStub::MaybeCallEntryHook(masm); | |
2559 | |
2560 // Enter the exit frame that transitions from JavaScript to C++. | |
2561 #ifdef _WIN64 | |
2562 int arg_stack_space = (result_size_ < 2 ? 2 : 4); | |
2563 #else | |
2564 int arg_stack_space = 0; | |
2565 #endif | |
2566 __ EnterExitFrame(arg_stack_space, save_doubles_); | |
2567 | |
2568 // rax: Holds the context at this point, but should not be used. | |
2569 // On entry to code generated by GenerateCore, it must hold | |
2570 // a failure result if the collect_garbage argument to GenerateCore | |
2571 // is true. This failure result can be the result of code | |
2572 // generated by a previous call to GenerateCore. The value | |
2573 // of rax is then passed to Runtime::PerformGC. | |
2574 // rbx: pointer to builtin function (C callee-saved). | |
2575 // rbp: frame pointer of exit frame (restored after C call). | |
2576 // rsp: stack pointer (restored after C call). | |
2577 // r14: number of arguments including receiver (C callee-saved). | |
2578 // r15: argv pointer (C callee-saved). | |
2579 | |
2580 Label throw_normal_exception; | |
2581 Label throw_termination_exception; | |
2582 | |
2583 // Call into the runtime system. | |
2584 GenerateCore(masm, | |
2585 &throw_normal_exception, | |
2586 &throw_termination_exception, | |
2587 false, | |
2588 false); | |
2589 | |
2590 // Do space-specific GC and retry runtime call. | |
2591 GenerateCore(masm, | |
2592 &throw_normal_exception, | |
2593 &throw_termination_exception, | |
2594 true, | |
2595 false); | |
2596 | |
2597 // Do full GC and retry runtime call one final time. | |
2598 Failure* failure = Failure::InternalError(); | |
2599 __ Move(rax, failure, Assembler::RelocInfoNone()); | |
2600 GenerateCore(masm, | |
2601 &throw_normal_exception, | |
2602 &throw_termination_exception, | |
2603 true, | |
2604 true); | |
2605 | |
2606 { FrameScope scope(masm, StackFrame::MANUAL); | |
2607 __ PrepareCallCFunction(0); | |
2608 __ CallCFunction( | |
2609 ExternalReference::out_of_memory_function(masm->isolate()), 0); | |
2610 } | |
2611 | |
2612 __ bind(&throw_termination_exception); | |
2613 __ ThrowUncatchable(rax); | |
2614 | |
2615 __ bind(&throw_normal_exception); | |
2616 __ Throw(rax); | |
2617 } | |
2618 | |
2619 | |
2620 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 2552 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
2621 Label invoke, handler_entry, exit; | 2553 Label invoke, handler_entry, exit; |
2622 Label not_outermost_js, not_outermost_js_2; | 2554 Label not_outermost_js, not_outermost_js_2; |
2623 | 2555 |
2624 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 2556 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
2625 | 2557 |
2626 { // NOLINT. Scope block confuses linter. | 2558 { // NOLINT. Scope block confuses linter. |
2627 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); | 2559 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); |
2628 // Set up frame. | 2560 // Set up frame. |
2629 __ pushq(rbp); | 2561 __ pushq(rbp); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2695 // Jump to a faked try block that does the invoke, with a faked catch | 2627 // Jump to a faked try block that does the invoke, with a faked catch |
2696 // block that sets the pending exception. | 2628 // block that sets the pending exception. |
2697 __ jmp(&invoke); | 2629 __ jmp(&invoke); |
2698 __ bind(&handler_entry); | 2630 __ bind(&handler_entry); |
2699 handler_offset_ = handler_entry.pos(); | 2631 handler_offset_ = handler_entry.pos(); |
2700 // Caught exception: Store result (exception) in the pending exception | 2632 // Caught exception: Store result (exception) in the pending exception |
2701 // field in the JSEnv and return a failure sentinel. | 2633 // field in the JSEnv and return a failure sentinel. |
2702 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | 2634 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, |
2703 isolate); | 2635 isolate); |
2704 __ Store(pending_exception, rax); | 2636 __ Store(pending_exception, rax); |
2705 __ Move(rax, Failure::Exception(), Assembler::RelocInfoNone()); | 2637 __ LoadRoot(rax, Heap::kExceptionRootIndex); |
2706 __ jmp(&exit); | 2638 __ jmp(&exit); |
2707 | 2639 |
2708 // Invoke: Link this frame into the handler chain. There's only one | 2640 // Invoke: Link this frame into the handler chain. There's only one |
2709 // handler block in this code object, so its index is 0. | 2641 // handler block in this code object, so its index is 0. |
2710 __ bind(&invoke); | 2642 __ bind(&invoke); |
2711 __ PushTryHandler(StackHandler::JS_ENTRY, 0); | 2643 __ PushTryHandler(StackHandler::JS_ENTRY, 0); |
2712 | 2644 |
2713 // Clear any pending exceptions. | 2645 // Clear any pending exceptions. |
2714 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | 2646 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); |
2715 __ Store(pending_exception, rax); | 2647 __ Store(pending_exception, rax); |
(...skipping 2312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5028 return_value_operand, | 4960 return_value_operand, |
5029 NULL); | 4961 NULL); |
5030 } | 4962 } |
5031 | 4963 |
5032 | 4964 |
5033 #undef __ | 4965 #undef __ |
5034 | 4966 |
5035 } } // namespace v8::internal | 4967 } } // namespace v8::internal |
5036 | 4968 |
5037 #endif // V8_TARGET_ARCH_X64 | 4969 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |