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 // rbx: pointer to builtin function (C callee-saved). |
| 2429 // rbp: frame pointer of exit frame (restored after C call). |
| 2430 // rsp: stack pointer (restored after C call). |
2420 // r14: number of arguments including receiver (C callee-saved). | 2431 // r14: number of arguments including receiver (C callee-saved). |
2421 // r15: pointer to the first argument (C callee-saved). | 2432 // r15: argv pointer (C callee-saved). |
2422 // This pointer is reused in LeaveExitFrame(), so it is stored in a | |
2423 // callee-saved register. | |
2424 | 2433 |
2425 // Simple results returned in rax (both AMD64 and Win64 calling conventions). | 2434 // Simple results returned in rax (both AMD64 and Win64 calling conventions). |
2426 // Complex results must be written to address passed as first argument. | 2435 // Complex results must be written to address passed as first argument. |
2427 // AMD64 calling convention: a struct of two pointers in rax+rdx | 2436 // AMD64 calling convention: a struct of two pointers in rax+rdx |
2428 | 2437 |
2429 // Check stack alignment. | 2438 // Check stack alignment. |
2430 if (FLAG_debug_code) { | 2439 if (FLAG_debug_code) { |
2431 __ CheckStackAlignment(); | 2440 __ CheckStackAlignment(); |
2432 } | 2441 } |
2433 | 2442 |
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. | 2443 // Call C function. |
2454 #ifdef _WIN64 | 2444 #ifdef _WIN64 |
2455 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. | 2445 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. |
2456 // Pass argv and argc as two parameters. The arguments object will | 2446 // Pass argv and argc as two parameters. The arguments object will |
2457 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). | 2447 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). |
2458 if (result_size_ < 2) { | 2448 if (result_size_ < 2) { |
2459 // Pass a pointer to the Arguments object as the first argument. | 2449 // Pass a pointer to the Arguments object as the first argument. |
2460 // Return result in single register (rax). | 2450 // Return result in single register (rax). |
2461 __ movp(rcx, r14); // argc. | 2451 __ movp(rcx, r14); // argc. |
2462 __ movp(rdx, r15); // argv. | 2452 __ movp(rdx, r15); // argv. |
(...skipping 10 matching lines...) Expand all Loading... |
2473 | 2463 |
2474 #else // _WIN64 | 2464 #else // _WIN64 |
2475 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. | 2465 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. |
2476 __ movp(rdi, r14); // argc. | 2466 __ movp(rdi, r14); // argc. |
2477 __ movp(rsi, r15); // argv. | 2467 __ movp(rsi, r15); // argv. |
2478 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); | 2468 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); |
2479 #endif | 2469 #endif |
2480 __ call(rbx); | 2470 __ call(rbx); |
2481 // Result is in rax - do not destroy this register! | 2471 // Result is in rax - do not destroy this register! |
2482 | 2472 |
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 | 2473 #ifdef _WIN64 |
2492 // If return value is on the stack, pop it to registers. | 2474 // If return value is on the stack, pop it to registers. |
2493 if (result_size_ > 1) { | 2475 if (result_size_ > 1) { |
2494 ASSERT_EQ(2, result_size_); | 2476 ASSERT_EQ(2, result_size_); |
2495 // Read result values stored on stack. Result is stored | 2477 // Read result values stored on stack. Result is stored |
2496 // above the four argument mirror slots and the two | 2478 // above the four argument mirror slots and the two |
2497 // Arguments object slots. | 2479 // Arguments object slots. |
2498 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); | 2480 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); |
2499 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); | 2481 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); |
2500 } | 2482 } |
2501 #endif | 2483 #endif |
2502 __ leap(rcx, Operand(rax, 1)); | 2484 |
2503 // Lower 2 bits of rcx are 0 iff rax has failure tag. | 2485 // Runtime functions should not return 'the hole'. Allowing it to escape may |
2504 __ testl(rcx, Immediate(kFailureTagMask)); | 2486 // lead to crashes in the IC code later. |
2505 __ j(zero, &failure_returned); | 2487 if (FLAG_debug_code) { |
| 2488 Label okay; |
| 2489 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 2490 __ j(not_equal, &okay, Label::kNear); |
| 2491 __ int3(); |
| 2492 __ bind(&okay); |
| 2493 } |
| 2494 |
| 2495 // Check result for exception sentinel. |
| 2496 Label exception_returned; |
| 2497 __ CompareRoot(rax, Heap::kExceptionRootIndex); |
| 2498 __ j(equal, &exception_returned); |
| 2499 |
| 2500 ExternalReference pending_exception_address( |
| 2501 Isolate::kPendingExceptionAddress, masm->isolate()); |
| 2502 |
| 2503 // Check that there is no pending exception, otherwise we |
| 2504 // should have returned the exception sentinel. |
| 2505 if (FLAG_debug_code) { |
| 2506 Label okay; |
| 2507 __ LoadRoot(r14, Heap::kTheHoleValueRootIndex); |
| 2508 Operand pending_exception_operand = |
| 2509 masm->ExternalOperand(pending_exception_address); |
| 2510 __ cmpp(r14, pending_exception_operand); |
| 2511 __ j(equal, &okay, Label::kNear); |
| 2512 __ int3(); |
| 2513 __ bind(&okay); |
| 2514 } |
2506 | 2515 |
2507 // Exit the JavaScript to C++ exit frame. | 2516 // Exit the JavaScript to C++ exit frame. |
2508 __ LeaveExitFrame(save_doubles_); | 2517 __ LeaveExitFrame(save_doubles_); |
2509 __ ret(0); | 2518 __ ret(0); |
2510 | 2519 |
2511 // Handling of failure. | 2520 // Handling of exception. |
2512 __ bind(&failure_returned); | 2521 __ bind(&exception_returned); |
2513 | |
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 | 2522 |
2520 // Retrieve the pending exception. | 2523 // Retrieve the pending exception. |
2521 ExternalReference pending_exception_address( | |
2522 Isolate::kPendingExceptionAddress, masm->isolate()); | |
2523 Operand pending_exception_operand = | 2524 Operand pending_exception_operand = |
2524 masm->ExternalOperand(pending_exception_address); | 2525 masm->ExternalOperand(pending_exception_address); |
2525 __ movp(rax, pending_exception_operand); | 2526 __ movp(rax, pending_exception_operand); |
2526 | 2527 |
2527 // Clear the pending exception. | 2528 // Clear the pending exception. |
2528 pending_exception_operand = | |
2529 masm->ExternalOperand(pending_exception_address); | |
2530 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 2529 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
2531 __ movp(pending_exception_operand, rdx); | 2530 __ movp(pending_exception_operand, rdx); |
2532 | 2531 |
2533 // Special handling of termination exceptions which are uncatchable | 2532 // Special handling of termination exceptions which are uncatchable |
2534 // by javascript code. | 2533 // by javascript code. |
| 2534 Label throw_termination_exception; |
2535 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 2535 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
2536 __ j(equal, throw_termination_exception); | 2536 __ j(equal, &throw_termination_exception); |
2537 | 2537 |
2538 // Handle normal exception. | 2538 // Handle normal exception. |
2539 __ jmp(throw_normal_exception); | 2539 __ Throw(rax); |
2540 | 2540 |
2541 // Retry. | 2541 __ bind(&throw_termination_exception); |
2542 __ bind(&retry); | 2542 __ ThrowUncatchable(rax); |
2543 } | 2543 } |
2544 | 2544 |
2545 | 2545 |
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) { | 2546 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
2621 Label invoke, handler_entry, exit; | 2547 Label invoke, handler_entry, exit; |
2622 Label not_outermost_js, not_outermost_js_2; | 2548 Label not_outermost_js, not_outermost_js_2; |
2623 | 2549 |
2624 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 2550 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
2625 | 2551 |
2626 { // NOLINT. Scope block confuses linter. | 2552 { // NOLINT. Scope block confuses linter. |
2627 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); | 2553 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); |
2628 // Set up frame. | 2554 // Set up frame. |
2629 __ pushq(rbp); | 2555 __ 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 | 2621 // Jump to a faked try block that does the invoke, with a faked catch |
2696 // block that sets the pending exception. | 2622 // block that sets the pending exception. |
2697 __ jmp(&invoke); | 2623 __ jmp(&invoke); |
2698 __ bind(&handler_entry); | 2624 __ bind(&handler_entry); |
2699 handler_offset_ = handler_entry.pos(); | 2625 handler_offset_ = handler_entry.pos(); |
2700 // Caught exception: Store result (exception) in the pending exception | 2626 // Caught exception: Store result (exception) in the pending exception |
2701 // field in the JSEnv and return a failure sentinel. | 2627 // field in the JSEnv and return a failure sentinel. |
2702 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | 2628 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, |
2703 isolate); | 2629 isolate); |
2704 __ Store(pending_exception, rax); | 2630 __ Store(pending_exception, rax); |
2705 __ Move(rax, Failure::Exception(), Assembler::RelocInfoNone()); | 2631 __ LoadRoot(rax, Heap::kExceptionRootIndex); |
2706 __ jmp(&exit); | 2632 __ jmp(&exit); |
2707 | 2633 |
2708 // Invoke: Link this frame into the handler chain. There's only one | 2634 // Invoke: Link this frame into the handler chain. There's only one |
2709 // handler block in this code object, so its index is 0. | 2635 // handler block in this code object, so its index is 0. |
2710 __ bind(&invoke); | 2636 __ bind(&invoke); |
2711 __ PushTryHandler(StackHandler::JS_ENTRY, 0); | 2637 __ PushTryHandler(StackHandler::JS_ENTRY, 0); |
2712 | 2638 |
2713 // Clear any pending exceptions. | 2639 // Clear any pending exceptions. |
2714 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | 2640 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); |
2715 __ Store(pending_exception, rax); | 2641 __ Store(pending_exception, rax); |
(...skipping 2312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5028 return_value_operand, | 4954 return_value_operand, |
5029 NULL); | 4955 NULL); |
5030 } | 4956 } |
5031 | 4957 |
5032 | 4958 |
5033 #undef __ | 4959 #undef __ |
5034 | 4960 |
5035 } } // namespace v8::internal | 4961 } } // namespace v8::internal |
5036 | 4962 |
5037 #endif // V8_TARGET_ARCH_X64 | 4963 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |