From edb1ee9ec8e52a87189183b1e31310caaa404493 Mon Sep 17 00:00:00 2001 From: rhuanjl Date: Tue, 14 Feb 2023 17:30:28 +0000 Subject: [PATCH] Update Runtime to support Apple Silicon - Update entry point call for Apple arm64 function calling convention - New Assembler routines for function calls --- lib/Runtime/Debug/TTEventLog.cpp | 5 +- lib/Runtime/Language/Arguments.h | 4 + lib/Runtime/Language/CMakeLists.txt | 6 + .../Language/InterpreterStackFrame.cpp | 16 ++- .../Language/JavascriptStackWalker.cpp | 3 +- .../Language/arm64/arm64_CallEhFrame.S | 136 ++++++++++++++++++ lib/Runtime/Language/arm64/arm64_Thunks.S | 96 +++++++++++++ lib/Runtime/Library/CMakeLists.txt | 6 + .../Library/arm64/arm64_CallFunction.S | 56 ++++++++ .../arm64/arm64_DeferredDeserializeThunk.S | 41 ++++++ .../arm64/arm64_DeferredParsingThunk.S | 47 ++++++ .../Platform/Unix/AssemblyCommon.cpp | 3 +- 12 files changed, 412 insertions(+), 7 deletions(-) create mode 100644 lib/Runtime/Language/arm64/arm64_CallEhFrame.S create mode 100644 lib/Runtime/Language/arm64/arm64_Thunks.S create mode 100644 lib/Runtime/Library/arm64/arm64_CallFunction.S create mode 100644 lib/Runtime/Library/arm64/arm64_DeferredDeserializeThunk.S create mode 100644 lib/Runtime/Library/arm64/arm64_DeferredParsingThunk.S diff --git a/lib/Runtime/Debug/TTEventLog.cpp b/lib/Runtime/Debug/TTEventLog.cpp index e352817b30a..aabf558183d 100644 --- a/lib/Runtime/Debug/TTEventLog.cpp +++ b/lib/Runtime/Debug/TTEventLog.cpp @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. +// Copyright (c) ChakraCore Project Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #include "RuntimeDebugPch.h" @@ -2816,7 +2817,9 @@ namespace TTD TTDAssert(wcscmp(_u("x86"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!"); #elif defined(_M_X64) TTDAssert(wcscmp(_u("x64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!"); -#elif defined(_M_ARM) +#elif defined(_M_ARM) // #TODO investigate why this is checking for "arm64" instead of "arm" + TTDAssert(wcscmp(_u("arm64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!"); +#elif defined(_M_ARM64) TTDAssert(wcscmp(_u("arm64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!"); #else TTDAssert(false, "Unknown arch!!!"); diff --git a/lib/Runtime/Language/Arguments.h b/lib/Runtime/Language/Arguments.h index a71dc19cb0d..9b033ffedd8 100644 --- a/lib/Runtime/Language/Arguments.h +++ b/lib/Runtime/Language/Arguments.h @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. +// Copyright (c) ChakraCore Project Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once @@ -82,6 +83,9 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, const T5&, Js // xplat-todo: fix me ARM #define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \ entryPoint(function, callInfo, ##__VA_ARGS__) +#elif defined (_ARM64_) +#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \ + entryPoint(function, callInfo, function, callInfo, ##__VA_ARGS__) #else #error CALL_ENTRYPOINT_NOASSERT not yet implemented #endif diff --git a/lib/Runtime/Language/CMakeLists.txt b/lib/Runtime/Language/CMakeLists.txt index 20a2a254b74..20647547396 100644 --- a/lib/Runtime/Language/CMakeLists.txt +++ b/lib/Runtime/Language/CMakeLists.txt @@ -78,6 +78,12 @@ elseif(CC_TARGETS_X86) i386/AsmJsJitTemplate.cpp i386/StackFrame.cpp ) +elseif(CC_TARGETS_ARM64) + set (CRL_SOURCE_FILES ${CRL_SOURCE_FILES} + arm64/StackFrame.cpp + arm64/arm64_Thunks.S + arm64/arm64_CallEhFrame.S + ) elseif(CC_TARGETS_ARM) set (CRL_SOURCE_FILES ${CRL_SOURCE_FILES} arm/StackFrame.cpp diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp index bb0351e4e58..7b8535b5d1b 100644 --- a/lib/Runtime/Language/InterpreterStackFrame.cpp +++ b/lib/Runtime/Language/InterpreterStackFrame.cpp @@ -1,6 +1,6 @@ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft Corporation and contributors. All rights reserved. -// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved. +// Copyright (c) ChakraCore Project Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- @@ -1814,13 +1814,13 @@ namespace Js } #endif -#if !defined(_M_ARM64) +#if defined(_M_ARM64) && defined(_WIN32) + // Language\arm64\arm64_Thunks.asm +#else Var InterpreterStackFrame::StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...) { return InterpreterThunk((JavascriptCallStackLayout*)&function); } -#else - // Language\arm64\arm64_Thunks.asm #endif #pragma optimize("", on) @@ -6352,7 +6352,11 @@ namespace Js // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo // and do ISB only for 1st time this entry point is called (potential working set regression though). + #if defined(_InstructionSynchronizationBarrier) _InstructionSynchronizationBarrier(); + #else + asm("isb"); + #endif #endif uint newOffset = ::Math::PointerCastToIntegral( CALL_ENTRYPOINT_NOASSERT(address, function, CallInfo(CallFlags_InternalFrame, 1), this)); @@ -6386,7 +6390,11 @@ namespace Js // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo // and do ISB only for 1st time this entry point is called (potential working set regression though). + #if defined(_InstructionSynchronizationBarrier) _InstructionSynchronizationBarrier(); + #else + asm("isb"); + #endif #endif uint newOffset = ::Math::PointerCastToIntegral( CALL_ENTRYPOINT_NOASSERT(address, function, CallInfo(CallFlags_InternalFrame, 1), this)); diff --git a/lib/Runtime/Language/JavascriptStackWalker.cpp b/lib/Runtime/Language/JavascriptStackWalker.cpp index 5bf20cb3dcc..35c0ccee65f 100644 --- a/lib/Runtime/Language/JavascriptStackWalker.cpp +++ b/lib/Runtime/Language/JavascriptStackWalker.cpp @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. +// Copyright (c) ChakraCore Project Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #include "RuntimeLanguagePch.h" @@ -278,7 +279,7 @@ namespace Js } else #endif - if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine()) + if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine()) { JavascriptGenerator* gen = VarTo(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]); return gen->GetArguments().Values; diff --git a/lib/Runtime/Language/arm64/arm64_CallEhFrame.S b/lib/Runtime/Language/arm64/arm64_CallEhFrame.S new file mode 100644 index 00000000000..a145a48551c --- /dev/null +++ b/lib/Runtime/Language/arm64/arm64_CallEhFrame.S @@ -0,0 +1,136 @@ +;------------------------------------------------------------------------------------------------------- +; Copyright (C) Microsoft. All rights reserved. +; Copyright (c) ChakraCore Project Contributors. All rights reserved. +; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;------------------------------------------------------------------------------------------------------- + +; +; arm64_CallEhFrame() and arm64_CallCatch() both thunk into jitted code at the +; start of an EH region. The purpose is to restore the frame pointer (fp) +; and locals pointer (x28) to the appropriate values for executing the parent +; function and to create a local frame that can be unwound using the parent +; function's pdata. The parent's frame looks like this: +; +;------------------- +; {x0-x7} -- homed parameters +; lr -- address from which parent was called +; fp -- saved frame pointer, pointed to by current fp +; arg obj +; {x19-x28} -- non-volatile registers: all of them are saved +; {q8-q15} -- non-volatile double registers: all of them are saved +; locals area -- pointed to by x28 +; pointer to non-volatile register area above +; stack args +;------------------- +; +; The reason for the "pointer to non-volatile register area" is to allow the +; unwinder to deallocate the locals area regardless of its size. So this thunk can skip +; the allocation of the locals area altogether, and unwinding still works. +; The unwind pseudo-codes for the above prolog look like: +; +; 1. Deallocate stack args (sp now points to "pointer to non-volatile register area") +; 2. Restore rN (rN now points to first saved register) +; 3. Copy rN to sp (sp now points to first saved register) +; 4. Restore {q8-q15} (non-volatile double registers restored) +; 5. Restore {x19-x28} (non-volatile registers restored, sp points to saved r11) +; 6. Restore fp +; 7. Load lr into pc and deallocate remaining stack. +; +; The prologs for the assembly thunks allocate a frame that can be unwound by executing +; the above steps, although we don't allocate a locals area and don't know the size of the +; stack args. The caller doesn't return to this thunk; it executes its own epilog and +; returns to the caller of the thunk (one of the runtime try helpers). + + +#include "unixasmmacros.inc" + +.global C_FUNC(arm64_CallEhFrame) +.global C_FUNC(arm64_CallCatch) + +.macro STANDARD_PROLOG + + ; + ; Generate a prolog that will match the original function's, with all + ; parameters homed and all non-volatile registers saved: + ; + ; Size Offset + ; ---- ------ + ; 64 176 Homed parameters + ; 16 160 Saved FP/LR + ; 16 144 ArgOut / stack function list + ; 80 64 Saved x19-x28 + ; 64 0 Saved d8-d15 + ; = 240 total + ; + ; The try/catch/finally blocks will jump to the epilog code skipping + ; the instruction that deallocates the locals, in order to allow these + ; thunks to skip re-allocating locals space. + ; + + ; Params: + ; x0 -- thunk target + ; x1 -- frame pointer + ; x2 -- locals pointer + ; x3 -- size of stack args area + ; x4 -- exception object (for arm64_CallCatch only) + + PROLOG_SAVE_REG_PAIR d8, d9, -240 + PROLOG_SAVE_REG_PAIR d10, d11, 16 + PROLOG_SAVE_REG_PAIR d12, d13, 32 + PROLOG_SAVE_REG_PAIR d14, d15, 48 + PROLOG_SAVE_REG_PAIR x19, x20, 64 + PROLOG_SAVE_REG_PAIR x21, x22, 80 + PROLOG_SAVE_REG_PAIR x23, x24, 96 + PROLOG_SAVE_REG_PAIR x25, x26, 112 + PROLOG_SAVE_REG_PAIR x27, x28, 128 + PROLOG_SAVE_REG fp, 160 ; TODO: verify that this works the same as PROLOG_SAVE_REG_PAIR_NO_FP + PROLOG_SAVE_REG lr, 168 + + sub x15, x1, x2 ; x15 = frame pointer minus locals pointer + sub x15, x15, #160 ; x15 -= space we already allocated + add x15, x15, x3 ; x15 += argout area = same stack allocation as original function + lsr x15, x15, #4 ; x15 /= 16 + sub sp, sp, x15, lsl #4 ; allocate the stack + +.endm + + + +NESTED_ENTRY arm64_CallEhFrame, _TEXT, NoHandler + + STANDARD_PROLOG + + ; Set up the locals pointer and frame pointer + mov x28, x2 + mov fp, x1 + + ; Thunk to the jitted code (and don't return) + br x0 + +NESTED_END arm64_CallEhFrame + + + + ; arm64_CallCatch() is similar to arm64_CallEhFrame() except that we also pass the catch object to the jitted code + +NESTED_ENTRY arm64_CallCatch, _TEXT, NoHandler + + ; Params: + ; x0 -- thunk target + ; x1 -- frame pointer + ; x2 -- locals pointer + ; x3 -- size of stack args area + ; x4 -- exception object + + STANDARD_PROLOG + + ; Set up the locals pointer and frame pointer and catch object handler + mov x28, x2 + mov fp, x1 + mov x1, x4 + + ; Thunk to the jitted code (and don't return) + br x0 + +NESTED_END arm64_CallCatch + diff --git a/lib/Runtime/Language/arm64/arm64_Thunks.S b/lib/Runtime/Language/arm64/arm64_Thunks.S new file mode 100644 index 00000000000..de740b3f393 --- /dev/null +++ b/lib/Runtime/Language/arm64/arm64_Thunks.S @@ -0,0 +1,96 @@ +;------------------------------------------------------------------------------------------------------- +; Copyright (C) Microsoft. All rights reserved. +; Copyright (c) ChakraCore Project Contributors. All rights reserved. +; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;------------------------------------------------------------------------------------------------------- + +#include "unixasmmacros.inc" + +.global C_FUNC(_ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz) +.global C_FUNC(_ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz) + +#ifdef _ENABLE_DYNAMIC_THUNKS + +.global C_FUNC(_ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz) +.global C_FUNC(_ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz) + +;;============================================================================================================ +;; InterpreterStackFrame::DelayDynamicInterpreterThunk +;;============================================================================================================ + ;Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...) + +NESTED_ENTRY _ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers + stp x0, x1, [sp, #16] + + bl C_FUNC(_ZN2Js21InterpreterStackFrame29EnsureDynamicInterpreterThunkEPNS_14ScriptFunctionE) ; call InterpreterStackFrame::EnsureDynamicInterpreterThunk + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] ; restore parameters and volatile registers + + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; jump (tail call) to new entryPoint + +NESTED_END _ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT + +;;============================================================================================================ +;; DynamicProfileInfo::EnsureDynamicProfileInfoThunk +;;============================================================================================================ + ;Var DynamicProfileInfo::EnsureDynamicProfileInfoThunk(RecyclableObject* function, CallInfo callInfo, ...) +NESTED_ENTRY _ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers + stp x0, x1, [sp, #16] + + bl C_FUNC(_ZN2Js18DynamicProfileInfo24EnsureDynamicProfileInfoEPNS_14ScriptFunctionE) ; call DynamicProfileInfo::EnsureDynamicProfileInfo + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] ; restore parameters and volatile registers + + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; jump (tail call) to new entryPoint + +NESTED_END _ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT + +#endif + +;;============================================================================================================ +;; ScriptContext::ProfileModeDeferredParsingThunk +;;============================================================================================================ + ;; Var ScriptContext::ProfileModeDeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...) +NESTED_ENTRY _ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers + stp x0, x1, [sp, #16] + + mov x0, sp ; Pass the address of the function at the saved x0 in case it need to be boxed + add x0, x0, #16 ; 16 is subtracted from the stack pointer when the a function is called, add it back here. + bl C_FUNC(_ZN2Js13ScriptContext24ProfileModeDeferredParseEPPNS_14ScriptFunctionE) ; call ScriptContext::ProfileModeDeferredParse + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] ; restore parameters and volatile registers + + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; jump (tail call) to new entryPoint + +NESTED_END _ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT + +;;============================================================================================================ +;; ScriptContext::ProfileModeDeferredDeserializeThunk +;;============================================================================================================ + ;; Var ScriptContext::ProfileModeDeferredDeserializeThunk(RecyclableObject* function, CallInfo callInfo, ...) +NESTED_ENTRY _ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers + stp x0, x1, [sp, #16] + + bl C_FUNC(_ZN2Js13ScriptContext30ProfileModeDeferredDeserializeEPNS_14ScriptFunctionE) ; call ScriptContext::ProfileModeDeferredDeserialize + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] ; restore parameters and volatile registers + + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; jump (tail call) to new entryPoint + +NESTED_END _ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT diff --git a/lib/Runtime/Library/CMakeLists.txt b/lib/Runtime/Library/CMakeLists.txt index bbcc53254f2..4ed3d3bdde3 100644 --- a/lib/Runtime/Library/CMakeLists.txt +++ b/lib/Runtime/Library/CMakeLists.txt @@ -133,6 +133,12 @@ elseif(CC_TARGETS_ARM) set (CRLIB_SOURCE_CODES ${CRLIB_SOURCE_CODES} arm/arm_JavascriptFunctionA.S ) +elseif(CC_TARGETS_ARM64) + set (CRLIB_SOURCE_CODES ${CRLIB_SOURCE_CODES} + arm64/arm64_CallFunction.S + arm64/arm64_DeferredDeserializeThunk.S + arm64/arm64_DeferredParsingThunk.S + ) endif() add_library (Chakra.Runtime.Library OBJECT ${CRLIB_SOURCE_CODES}) diff --git a/lib/Runtime/Library/arm64/arm64_CallFunction.S b/lib/Runtime/Library/arm64/arm64_CallFunction.S new file mode 100644 index 00000000000..a98154ce725 --- /dev/null +++ b/lib/Runtime/Library/arm64/arm64_CallFunction.S @@ -0,0 +1,56 @@ +;------------------------------------------------------------------------------------------------------- +; Copyright (C) Microsoft. All rights reserved. +; Copyright (c) ChakraCore Project Contributors. All rights reserved. +; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;------------------------------------------------------------------------------------------------------- + +;Var arm64_CallFunction(JavascriptFunction* function, CallInfo info, uint argCount, Var* values, JavascriptMethod entryPoint) +; +; This method should be called as follows +; varResult = arm64_CallFunction((JavascriptFunction*)function, args.Info, argCount, args.Values, entryPoint); +; +; and makes the following call +; return entryPoint(function, info, function, info, values[0], values[1], ..., values[n-2], values[n-1]); +; where n = info.Count +; +; ARM64 on macOS puts upto 6 named parameters into x0-x5 and all other parameters (including ...) on the stack +; For the stack walker to work need function and info on stack as well as in x0 and x1 +; Below logic copies them and all other params to stack +; + +#include "unixasmmacros.inc" + +NESTED_ENTRY arm64_CallFunction, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16 ; save FP/LR registers, implicitly stores FP in SP + + add x5, x2, #3 ; add 3 to param count + lsr x5, x5, #1 ; divide by 2 + sub sp, sp, x5, lsl #4 ; then allocate the space + mov x6, sp ; use x6 = dest + str x0, [x6], 8 ; store function pointer + str x1, [x6], 8 ; store info pointer + + cmp x2, #0 ; check for 0 params + beq LOCAL_LABEL(CallEntryPoint) + + LOCAL_LABEL(CopyLoop): + subs x2, x2, #1 ; decrement param count by 1 + ldr x7, [x3], #8 ; read param from source + str x7, [x6], #8 ; store param to dest + bne LOCAL_LABEL(CopyLoop) ; loop until all copied + + LOCAL_LABEL(CallEntryPoint): + blr x4 ; call entry point + + mov sp, fp ; explicitly restore sp + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16 ; restore FP/LR + ret ; return + +NESTED_END arm64_CallFunction + +NESTED_ENTRY BreakSpeculation, _TEXT, NoHandler + cmp x0, x0 + csel x0, x0, x0, eq + ret +NESTED_END BreakSpeculation diff --git a/lib/Runtime/Library/arm64/arm64_DeferredDeserializeThunk.S b/lib/Runtime/Library/arm64/arm64_DeferredDeserializeThunk.S new file mode 100644 index 00000000000..1d03f1682cb --- /dev/null +++ b/lib/Runtime/Library/arm64/arm64_DeferredDeserializeThunk.S @@ -0,0 +1,41 @@ +;------------------------------------------------------------------------------------------------------- +; Copyright (C) Microsoft. All rights reserved. +; Copyright (c) ChakraCore Project Contributors. All rights reserved. +; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;------------------------------------------------------------------------------------------------------- + +;Var Js:JavascriptFunction::DeferredDeserializeThunk(function, info, values[0], values[1], ..., values[n-2], values[n-1]) +; +; This method should be called as follows +; varResult = JavascriptFunction::DeferredDeserializeThunk(function, info, values[0], values[1], ..., values[n-2], values[n-1]); +; +; and does the following: +; entryPoint = JavascriptFunction::DeferredDeserialize(function); +; return entryPoint(function, info, values[0], values[1], ..., values[n-2], values[n-1]); +; where n = info.Count +; +; ARM64 calling convention (on macOS) is: //TODO verify if same on Linux +; x0 parameter 1 = function +; x1 parameter 2 = info +; [sp+0] values[0] +; [sp+8] values[1] +; ... +; +; Save and restore x0 and x1 to ensure they are the same after JavascriptFunction::DeferredDeserialize +; Move the stack pointer on so values on the stack remain untouched - move it back after JavascriptFunction::DeferredDeserialize + +#include "unixasmmacros.inc" + +NESTED_ENTRY _ZN2Js18JavascriptFunction24DeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameter registers + stp x0, x1, [sp, #16] + + bl C_FUNC(_ZN2Js18JavascriptFunction19DeferredDeserializeEPNS_14ScriptFunctionE) ; retrieve entrypoint + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; tail call to new entryPoint + +NESTED_END _ZN2Js18JavascriptFunction24DeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz diff --git a/lib/Runtime/Library/arm64/arm64_DeferredParsingThunk.S b/lib/Runtime/Library/arm64/arm64_DeferredParsingThunk.S new file mode 100644 index 00000000000..1b447a16bc5 --- /dev/null +++ b/lib/Runtime/Library/arm64/arm64_DeferredParsingThunk.S @@ -0,0 +1,47 @@ +;------------------------------------------------------------------------------------------------------- +; Copyright (C) Microsoft. All rights reserved. +; Copyright (c) ChakraCore Project Contributors. All rights reserved. +; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;------------------------------------------------------------------------------------------------------- + +;Var Js:JavascriptFunction::DeferredParsingThunk(function, info, values[0], values[1], ..., values[n-2], values[n-1]) +; +; This method should be called as follows +; varResult = JavascriptFunction::DeferredParsingThunk(function, info, values[0], values[1], ..., values[n-2], values[n-1]); +; +; and does the following: +; entryPoint = JavascriptFunction::DeferredParse(&function); +; return entryPoint(function, info, values[0], values[1], ..., values[n-2], values[n-1]); +; where n = info.Count +; +; ARM64 calling convention (on macOS) is: //TODO verify if same on Linux +; x0 parameter 1 = function +; x1 parameter 2 = info +; [sp+0] values[0] +; [sp+8] values[1] +; ... +; +; Save and restore x0 and x1 to ensure they are the same after JavascriptFunction::DeferredParse +; Move the stack pointer on so values on the stack remain untouched - move it back after JavascriptFunction::DeferredParse +; Take the address of function to pass as parameter to JavascriptFunction::DeferredParse +; + +#include "unixasmmacros.inc" + +NESTED_ENTRY _ZN2Js18JavascriptFunction20DeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler + + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameter registers + stp x0, x1, [sp, #16] + + ; Pass the address of the function at the saved x0 + mov x0, sp + add x0, x0, #16 ; 16 is subtracted from the stack pointer when the a function is called, add it back here. + bl C_FUNC(_ZN2Js18JavascriptFunction13DeferredParseEPPNS_14ScriptFunctionE) ; retrieve entrypoint + mov x16, x0 ; back up entryPoint in x16 + + ldp x0, x1, [sp, #16] + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + br x16 ; tail call to new entryPoint + +NESTED_END _ZN2Js18JavascriptFunction20DeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz + diff --git a/lib/Runtime/PlatformAgnostic/Platform/Unix/AssemblyCommon.cpp b/lib/Runtime/PlatformAgnostic/Platform/Unix/AssemblyCommon.cpp index 52691b6b16d..96d2f653e85 100644 --- a/lib/Runtime/PlatformAgnostic/Platform/Unix/AssemblyCommon.cpp +++ b/lib/Runtime/PlatformAgnostic/Platform/Unix/AssemblyCommon.cpp @@ -1,12 +1,13 @@ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. +// Copyright (c) ChakraCore Project Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #include "Common.h" #include "PlatformAgnostic/AssemblyCommon.h" -#ifndef DISABLE_JIT +#if !defined(DISABLE_JIT) && defined(_AMD64_) extern void mac_fde_wrapper(const char *dataStart, mac_fde_reg_op reg_op) { const char *head = dataStart;