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