| 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 | |
| 64 | CCallHelpers::Call operationCall = jit.call(OperationPtrTag); |
| 65 | auto function = m_function; |
| 66 | jit.addLinkTask([=] (LinkBuffer& linkBuffer) { |
| 67 | linkBuffer.link(operationCall, FunctionPtr<OperationPtrTag>(function)); |
| 68 | }); |
| 69 | |
| 70 | jit.setupResults(m_result); |
| 71 | jit.reclaimSpaceOnStackForCCall(); |
| 72 | |
| 73 | CCallHelpers::Jump noException = jit.emitExceptionCheck(state.m_vm, CCallHelpers::InvertedExceptionCheck); |
| 74 | |
| 75 | state.restoreLiveRegistersFromStackForCallWithThrownException(spillState); |
| 76 | exceptions.append(jit.jump()); |
| 77 | |
| 78 | noException.link(&jit); |
| 79 | RegisterSet dontRestore; |
| 80 | dontRestore.set(m_result); |
| 81 | state.restoreLiveRegistersFromStackForCall(spillState, dontRestore); |
| 82 | |
| 83 | return exceptions; |
| 84 | } |
| 85 | |
| 86 | CCallHelpers::JumpList generate(AccessGenerationState& state, const RegisterSet& usedRegistersBySnippet, CCallHelpers& jit) override |
| 87 | { |
| 88 | m_from.link(&jit); |
| 89 | CCallHelpers::JumpList exceptions = generateImpl(state, usedRegistersBySnippet, jit, std::make_index_sequence<std::tuple_size<std::tuple<Arguments...>>::value>()); |
| 90 | jit.jump().linkTo(m_to, &jit); |
| 91 | return exceptions; |
| 92 | } |
| 93 | |
| 94 | protected: |
| 95 | JumpType m_from; |
| 96 | CCallHelpers::Label m_to; |
| 97 | FunctionType m_function; |
| 98 | ResultType m_result; |
| 99 | std::tuple<Arguments...> m_arguments; |
| 100 | }; |
| 101 | |
| 102 | #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \ |
| 103 | void AccessCaseSnippetParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \ |
| 104 | { \ |
| 105 | CCallHelpers::Label to = jit.label(); \ |
| 106 | m_generators.append(std::make_unique<SlowPathCallGeneratorWithArguments<CCallHelpers::JumpList, OperationType, ResultType, __VA_ARGS__>>(from, to, operation, result, args)); \ |
| 107 | } \ |
| 108 | |
| 109 | SNIPPET_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS) |
| 110 | #undef JSC_DEFINE_CALL_OPERATIONS |
| 111 | |
| 112 | CCallHelpers::JumpList AccessCaseSnippetParams::emitSlowPathCalls(AccessGenerationState& state, const RegisterSet& usedRegistersBySnippet, CCallHelpers& jit) |
| 113 | { |
| 114 | CCallHelpers::JumpList exceptions; |
| 115 | for (auto& generator : m_generators) |
| 116 | exceptions.append(generator->generate(state, usedRegistersBySnippet, jit)); |
| 117 | return exceptions; |
| 118 | } |
| 119 | |
| 120 | } |
| 121 | |
| 122 | #endif |
| 123 | |