1 | /* |
2 | * Copyright (C) 2016-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "AccessCaseSnippetParams.h" |
28 | |
29 | #include "LinkBuffer.h" |
30 | #include "PolymorphicAccess.h" |
31 | #include "StructureStubInfo.h" |
32 | |
33 | #if ENABLE(JIT) |
34 | |
35 | namespace JSC { |
36 | |
37 | template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments> |
38 | class SlowPathCallGeneratorWithArguments : public AccessCaseSnippetParams::SlowPathCallGenerator { |
39 | public: |
40 | SlowPathCallGeneratorWithArguments(JumpType from, CCallHelpers::Label to, FunctionType function, ResultType result, std::tuple<Arguments...> arguments) |
41 | : m_from(from) |
42 | , m_to(to) |
43 | , m_function(function) |
44 | , m_result(result) |
45 | , m_arguments(arguments) |
46 | { |
47 | } |
48 | |
49 | template<size_t... ArgumentsIndex> |
50 | CCallHelpers::JumpList generateImpl(AccessGenerationState& state, const RegisterSet& usedRegistersBySnippet, CCallHelpers& jit, std::index_sequence<ArgumentsIndex...>) |
51 | { |
52 | CCallHelpers::JumpList exceptions; |
53 | // We spill (1) the used registers by IC and (2) the used registers by Snippet. |
54 | AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall(usedRegistersBySnippet); |
55 | |
56 | jit.store32( |
57 | CCallHelpers::TrustedImm32(state.callSiteIndexForExceptionHandlingOrOriginal().bits()), |
58 | CCallHelpers::tagFor(static_cast<VirtualRegister>(CallFrameSlot::argumentCount))); |
59 | |
60 | jit.makeSpaceOnStackForCCall(); |
61 | |
62 | jit.setupArguments<FunctionType>(std::get<ArgumentsIndex>(m_arguments)...); |
63 | jit.prepareCallOperation(state.m_vm); |
64 | |
65 | CCallHelpers::Call operationCall = jit.call(OperationPtrTag); |
66 | auto function = m_function; |
67 | jit.addLinkTask([=] (LinkBuffer& linkBuffer) { |
68 | linkBuffer.link(operationCall, FunctionPtr<OperationPtrTag>(function)); |
69 | }); |
70 | |
71 | jit.setupResults(m_result); |
72 | jit.reclaimSpaceOnStackForCCall(); |
73 | |
74 | CCallHelpers::Jump noException = jit.emitExceptionCheck(state.m_vm, CCallHelpers::InvertedExceptionCheck); |
75 | |
76 | state.restoreLiveRegistersFromStackForCallWithThrownException(spillState); |
77 | exceptions.append(jit.jump()); |
78 | |
79 | noException.link(&jit); |
80 | RegisterSet dontRestore; |
81 | dontRestore.set(m_result); |
82 | state.restoreLiveRegistersFromStackForCall(spillState, dontRestore); |
83 | |
84 | return exceptions; |
85 | } |
86 | |
87 | CCallHelpers::JumpList generate(AccessGenerationState& state, const RegisterSet& usedRegistersBySnippet, CCallHelpers& jit) override |
88 | { |
89 | m_from.link(&jit); |
90 | CCallHelpers::JumpList exceptions = generateImpl(state, usedRegistersBySnippet, jit, std::make_index_sequence<std::tuple_size<std::tuple<Arguments...>>::value>()); |
91 | jit.jump().linkTo(m_to, &jit); |
92 | return exceptions; |
93 | } |
94 | |
95 | protected: |
96 | JumpType m_from; |
97 | CCallHelpers::Label m_to; |
98 | FunctionType m_function; |
99 | ResultType m_result; |
100 | std::tuple<Arguments...> m_arguments; |
101 | }; |
102 | |
103 | #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \ |
104 | void AccessCaseSnippetParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \ |
105 | { \ |
106 | CCallHelpers::Label to = jit.label(); \ |
107 | m_generators.append(makeUnique<SlowPathCallGeneratorWithArguments<CCallHelpers::JumpList, OperationType, ResultType, __VA_ARGS__>>(from, to, operation, result, args)); \ |
108 | } \ |
109 | |
110 | SNIPPET_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS) |
111 | #undef JSC_DEFINE_CALL_OPERATIONS |
112 | |
113 | CCallHelpers::JumpList AccessCaseSnippetParams::emitSlowPathCalls(AccessGenerationState& state, const RegisterSet& usedRegistersBySnippet, CCallHelpers& jit) |
114 | { |
115 | CCallHelpers::JumpList exceptions; |
116 | for (auto& generator : m_generators) |
117 | exceptions.append(generator->generate(state, usedRegistersBySnippet, jit)); |
118 | return exceptions; |
119 | } |
120 | |
121 | } |
122 | |
123 | #endif |
124 | |