Skip to content

Commit edb1ee9

Browse files
committed
Update Runtime to support Apple Silicon
- Update entry point call for Apple arm64 function calling convention - New Assembler routines for function calls
1 parent 015b05d commit edb1ee9

File tree

12 files changed

+412
-7
lines changed

12 files changed

+412
-7
lines changed

lib/Runtime/Debug/TTEventLog.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "RuntimeDebugPch.h"
@@ -2816,7 +2817,9 @@ namespace TTD
28162817
TTDAssert(wcscmp(_u("x86"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
28172818
#elif defined(_M_X64)
28182819
TTDAssert(wcscmp(_u("x64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
2819-
#elif defined(_M_ARM)
2820+
#elif defined(_M_ARM) // #TODO investigate why this is checking for "arm64" instead of "arm"
2821+
TTDAssert(wcscmp(_u("arm64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
2822+
#elif defined(_M_ARM64)
28202823
TTDAssert(wcscmp(_u("arm64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
28212824
#else
28222825
TTDAssert(false, "Unknown arch!!!");

lib/Runtime/Language/Arguments.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#pragma once
@@ -82,6 +83,9 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, const T5&, Js
8283
// xplat-todo: fix me ARM
8384
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
8485
entryPoint(function, callInfo, ##__VA_ARGS__)
86+
#elif defined (_ARM64_)
87+
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
88+
entryPoint(function, callInfo, function, callInfo, ##__VA_ARGS__)
8589
#else
8690
#error CALL_ENTRYPOINT_NOASSERT not yet implemented
8791
#endif

lib/Runtime/Language/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ elseif(CC_TARGETS_X86)
7878
i386/AsmJsJitTemplate.cpp
7979
i386/StackFrame.cpp
8080
)
81+
elseif(CC_TARGETS_ARM64)
82+
set (CRL_SOURCE_FILES ${CRL_SOURCE_FILES}
83+
arm64/StackFrame.cpp
84+
arm64/arm64_Thunks.S
85+
arm64/arm64_CallEhFrame.S
86+
)
8187
elseif(CC_TARGETS_ARM)
8288
set (CRL_SOURCE_FILES ${CRL_SOURCE_FILES}
8389
arm/StackFrame.cpp

lib/Runtime/Language/InterpreterStackFrame.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3-
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
44
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
55
//-------------------------------------------------------------------------------------------------------
66

@@ -1814,13 +1814,13 @@ namespace Js
18141814
}
18151815
#endif
18161816

1817-
#if !defined(_M_ARM64)
1817+
#if defined(_M_ARM64) && defined(_WIN32)
1818+
// Language\arm64\arm64_Thunks.asm
1819+
#else
18181820
Var InterpreterStackFrame::StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
18191821
{
18201822
return InterpreterThunk((JavascriptCallStackLayout*)&function);
18211823
}
1822-
#else
1823-
// Language\arm64\arm64_Thunks.asm
18241824
#endif
18251825
#pragma optimize("", on)
18261826

@@ -6352,7 +6352,11 @@ namespace Js
63526352
// For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
63536353
// Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
63546354
// and do ISB only for 1st time this entry point is called (potential working set regression though).
6355+
#if defined(_InstructionSynchronizationBarrier)
63556356
_InstructionSynchronizationBarrier();
6357+
#else
6358+
asm("isb");
6359+
#endif
63566360
#endif
63576361
uint newOffset = ::Math::PointerCastToIntegral<uint>(
63586362
CALL_ENTRYPOINT_NOASSERT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
@@ -6386,7 +6390,11 @@ namespace Js
63866390
// For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
63876391
// Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
63886392
// and do ISB only for 1st time this entry point is called (potential working set regression though).
6393+
#if defined(_InstructionSynchronizationBarrier)
63896394
_InstructionSynchronizationBarrier();
6395+
#else
6396+
asm("isb");
6397+
#endif
63906398
#endif
63916399
uint newOffset = ::Math::PointerCastToIntegral<uint>(
63926400
CALL_ENTRYPOINT_NOASSERT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));

lib/Runtime/Language/JavascriptStackWalker.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "RuntimeLanguagePch.h"
@@ -278,7 +279,7 @@ namespace Js
278279
}
279280
else
280281
#endif
281-
if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
282+
if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
282283
{
283284
JavascriptGenerator* gen = VarTo<JavascriptGenerator>(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
284285
return gen->GetArguments().Values;
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
;-------------------------------------------------------------------------------------------------------
2+
; Copyright (C) Microsoft. All rights reserved.
3+
; Copyright (c) ChakraCore Project Contributors. All rights reserved.
4+
; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
5+
;-------------------------------------------------------------------------------------------------------
6+
7+
;
8+
; arm64_CallEhFrame() and arm64_CallCatch() both thunk into jitted code at the
9+
; start of an EH region. The purpose is to restore the frame pointer (fp)
10+
; and locals pointer (x28) to the appropriate values for executing the parent
11+
; function and to create a local frame that can be unwound using the parent
12+
; function's pdata. The parent's frame looks like this:
13+
;
14+
;-------------------
15+
; {x0-x7} -- homed parameters
16+
; lr -- address from which parent was called
17+
; fp -- saved frame pointer, pointed to by current fp
18+
; arg obj
19+
; {x19-x28} -- non-volatile registers: all of them are saved
20+
; {q8-q15} -- non-volatile double registers: all of them are saved
21+
; locals area -- pointed to by x28
22+
; pointer to non-volatile register area above
23+
; stack args
24+
;-------------------
25+
;
26+
; The reason for the "pointer to non-volatile register area" is to allow the
27+
; unwinder to deallocate the locals area regardless of its size. So this thunk can skip
28+
; the allocation of the locals area altogether, and unwinding still works.
29+
; The unwind pseudo-codes for the above prolog look like:
30+
;
31+
; 1. Deallocate stack args (sp now points to "pointer to non-volatile register area")
32+
; 2. Restore rN (rN now points to first saved register)
33+
; 3. Copy rN to sp (sp now points to first saved register)
34+
; 4. Restore {q8-q15} (non-volatile double registers restored)
35+
; 5. Restore {x19-x28} (non-volatile registers restored, sp points to saved r11)
36+
; 6. Restore fp
37+
; 7. Load lr into pc and deallocate remaining stack.
38+
;
39+
; The prologs for the assembly thunks allocate a frame that can be unwound by executing
40+
; the above steps, although we don't allocate a locals area and don't know the size of the
41+
; stack args. The caller doesn't return to this thunk; it executes its own epilog and
42+
; returns to the caller of the thunk (one of the runtime try helpers).
43+
44+
45+
#include "unixasmmacros.inc"
46+
47+
.global C_FUNC(arm64_CallEhFrame)
48+
.global C_FUNC(arm64_CallCatch)
49+
50+
.macro STANDARD_PROLOG
51+
52+
;
53+
; Generate a prolog that will match the original function's, with all
54+
; parameters homed and all non-volatile registers saved:
55+
;
56+
; Size Offset
57+
; ---- ------
58+
; 64 176 Homed parameters
59+
; 16 160 Saved FP/LR
60+
; 16 144 ArgOut / stack function list
61+
; 80 64 Saved x19-x28
62+
; 64 0 Saved d8-d15
63+
; = 240 total
64+
;
65+
; The try/catch/finally blocks will jump to the epilog code skipping
66+
; the instruction that deallocates the locals, in order to allow these
67+
; thunks to skip re-allocating locals space.
68+
;
69+
70+
; Params:
71+
; x0 -- thunk target
72+
; x1 -- frame pointer
73+
; x2 -- locals pointer
74+
; x3 -- size of stack args area
75+
; x4 -- exception object (for arm64_CallCatch only)
76+
77+
PROLOG_SAVE_REG_PAIR d8, d9, -240
78+
PROLOG_SAVE_REG_PAIR d10, d11, 16
79+
PROLOG_SAVE_REG_PAIR d12, d13, 32
80+
PROLOG_SAVE_REG_PAIR d14, d15, 48
81+
PROLOG_SAVE_REG_PAIR x19, x20, 64
82+
PROLOG_SAVE_REG_PAIR x21, x22, 80
83+
PROLOG_SAVE_REG_PAIR x23, x24, 96
84+
PROLOG_SAVE_REG_PAIR x25, x26, 112
85+
PROLOG_SAVE_REG_PAIR x27, x28, 128
86+
PROLOG_SAVE_REG fp, 160 ; TODO: verify that this works the same as PROLOG_SAVE_REG_PAIR_NO_FP
87+
PROLOG_SAVE_REG lr, 168
88+
89+
sub x15, x1, x2 ; x15 = frame pointer minus locals pointer
90+
sub x15, x15, #160 ; x15 -= space we already allocated
91+
add x15, x15, x3 ; x15 += argout area = same stack allocation as original function
92+
lsr x15, x15, #4 ; x15 /= 16
93+
sub sp, sp, x15, lsl #4 ; allocate the stack
94+
95+
.endm
96+
97+
98+
99+
NESTED_ENTRY arm64_CallEhFrame, _TEXT, NoHandler
100+
101+
STANDARD_PROLOG
102+
103+
; Set up the locals pointer and frame pointer
104+
mov x28, x2
105+
mov fp, x1
106+
107+
; Thunk to the jitted code (and don't return)
108+
br x0
109+
110+
NESTED_END arm64_CallEhFrame
111+
112+
113+
114+
; arm64_CallCatch() is similar to arm64_CallEhFrame() except that we also pass the catch object to the jitted code
115+
116+
NESTED_ENTRY arm64_CallCatch, _TEXT, NoHandler
117+
118+
; Params:
119+
; x0 -- thunk target
120+
; x1 -- frame pointer
121+
; x2 -- locals pointer
122+
; x3 -- size of stack args area
123+
; x4 -- exception object
124+
125+
STANDARD_PROLOG
126+
127+
; Set up the locals pointer and frame pointer and catch object handler
128+
mov x28, x2
129+
mov fp, x1
130+
mov x1, x4
131+
132+
; Thunk to the jitted code (and don't return)
133+
br x0
134+
135+
NESTED_END arm64_CallCatch
136+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
;-------------------------------------------------------------------------------------------------------
2+
; Copyright (C) Microsoft. All rights reserved.
3+
; Copyright (c) ChakraCore Project Contributors. All rights reserved.
4+
; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
5+
;-------------------------------------------------------------------------------------------------------
6+
7+
#include "unixasmmacros.inc"
8+
9+
.global C_FUNC(_ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz)
10+
.global C_FUNC(_ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz)
11+
12+
#ifdef _ENABLE_DYNAMIC_THUNKS
13+
14+
.global C_FUNC(_ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz)
15+
.global C_FUNC(_ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz)
16+
17+
;;============================================================================================================
18+
;; InterpreterStackFrame::DelayDynamicInterpreterThunk
19+
;;============================================================================================================
20+
;Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
21+
22+
NESTED_ENTRY _ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
23+
24+
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers
25+
stp x0, x1, [sp, #16]
26+
27+
bl C_FUNC(_ZN2Js21InterpreterStackFrame29EnsureDynamicInterpreterThunkEPNS_14ScriptFunctionE) ; call InterpreterStackFrame::EnsureDynamicInterpreterThunk
28+
mov x16, x0 ; back up entryPoint in x16
29+
30+
ldp x0, x1, [sp, #16] ; restore parameters and volatile registers
31+
32+
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
33+
br x16 ; jump (tail call) to new entryPoint
34+
35+
NESTED_END _ZN2Js21InterpreterStackFrame28DelayDynamicInterpreterThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
36+
37+
;;============================================================================================================
38+
;; DynamicProfileInfo::EnsureDynamicProfileInfoThunk
39+
;;============================================================================================================
40+
;Var DynamicProfileInfo::EnsureDynamicProfileInfoThunk(RecyclableObject* function, CallInfo callInfo, ...)
41+
NESTED_ENTRY _ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
42+
43+
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers
44+
stp x0, x1, [sp, #16]
45+
46+
bl C_FUNC(_ZN2Js18DynamicProfileInfo24EnsureDynamicProfileInfoEPNS_14ScriptFunctionE) ; call DynamicProfileInfo::EnsureDynamicProfileInfo
47+
mov x16, x0 ; back up entryPoint in x16
48+
49+
ldp x0, x1, [sp, #16] ; restore parameters and volatile registers
50+
51+
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
52+
br x16 ; jump (tail call) to new entryPoint
53+
54+
NESTED_END _ZN2Js18DynamicProfileInfo29EnsureDynamicProfileInfoThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
55+
56+
#endif
57+
58+
;;============================================================================================================
59+
;; ScriptContext::ProfileModeDeferredParsingThunk
60+
;;============================================================================================================
61+
;; Var ScriptContext::ProfileModeDeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...)
62+
NESTED_ENTRY _ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
63+
64+
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers
65+
stp x0, x1, [sp, #16]
66+
67+
mov x0, sp ; Pass the address of the function at the saved x0 in case it need to be boxed
68+
add x0, x0, #16 ; 16 is subtracted from the stack pointer when the a function is called, add it back here.
69+
bl C_FUNC(_ZN2Js13ScriptContext24ProfileModeDeferredParseEPPNS_14ScriptFunctionE) ; call ScriptContext::ProfileModeDeferredParse
70+
mov x16, x0 ; back up entryPoint in x16
71+
72+
ldp x0, x1, [sp, #16] ; restore parameters and volatile registers
73+
74+
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
75+
br x16 ; jump (tail call) to new entryPoint
76+
77+
NESTED_END _ZN2Js13ScriptContext31ProfileModeDeferredParsingThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
78+
79+
;;============================================================================================================
80+
;; ScriptContext::ProfileModeDeferredDeserializeThunk
81+
;;============================================================================================================
82+
;; Var ScriptContext::ProfileModeDeferredDeserializeThunk(RecyclableObject* function, CallInfo callInfo, ...)
83+
NESTED_ENTRY _ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
84+
85+
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 ; save parameters and volatile registers
86+
stp x0, x1, [sp, #16]
87+
88+
bl C_FUNC(_ZN2Js13ScriptContext30ProfileModeDeferredDeserializeEPNS_14ScriptFunctionE) ; call ScriptContext::ProfileModeDeferredDeserialize
89+
mov x16, x0 ; back up entryPoint in x16
90+
91+
ldp x0, x1, [sp, #16] ; restore parameters and volatile registers
92+
93+
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
94+
br x16 ; jump (tail call) to new entryPoint
95+
96+
NESTED_END _ZN2Js13ScriptContext35ProfileModeDeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT

lib/Runtime/Library/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ elseif(CC_TARGETS_ARM)
133133
set (CRLIB_SOURCE_CODES ${CRLIB_SOURCE_CODES}
134134
arm/arm_JavascriptFunctionA.S
135135
)
136+
elseif(CC_TARGETS_ARM64)
137+
set (CRLIB_SOURCE_CODES ${CRLIB_SOURCE_CODES}
138+
arm64/arm64_CallFunction.S
139+
arm64/arm64_DeferredDeserializeThunk.S
140+
arm64/arm64_DeferredParsingThunk.S
141+
)
136142
endif()
137143

138144
add_library (Chakra.Runtime.Library OBJECT ${CRLIB_SOURCE_CODES})

0 commit comments

Comments
 (0)