1/*
2 * Copyright (C) 2011-2019 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 "DFGThunks.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "CCallHelpers.h"
32#include "DFGJITCode.h"
33#include "DFGOSRExit.h"
34#include "FPRInfo.h"
35#include "GPRInfo.h"
36#include "LinkBuffer.h"
37#include "MacroAssembler.h"
38#include "JSCInlines.h"
39#include "DFGOSRExitCompilerCommon.h"
40
41namespace JSC { namespace DFG {
42
43MacroAssemblerCodeRef<JITThunkPtrTag> osrExitThunkGenerator(VM& vm)
44{
45 CCallHelpers jit(nullptr);
46 jit.probe(OSRExit::executeOSRExit, &vm);
47 LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
48 return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "DFG OSR exit thunk");
49}
50
51MacroAssemblerCodeRef<JITThunkPtrTag> osrExitGenerationThunkGenerator(VM& vm)
52{
53 CCallHelpers jit(nullptr);
54
55 // This needs to happen before we use the scratch buffer because this function also uses the scratch buffer.
56 adjustFrameAndStackInOSRExitCompilerThunk<DFG::JITCode>(jit, vm, JITType::DFGJIT);
57
58 size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
59 ScratchBuffer* scratchBuffer = vm.scratchBufferForSize(scratchSize);
60 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
61
62 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
63#if USE(JSVALUE64)
64 jit.store64(GPRInfo::toRegister(i), buffer + i);
65#else
66 jit.store32(GPRInfo::toRegister(i), buffer + i);
67#endif
68 }
69 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
70 jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
71 jit.storeDouble(FPRInfo::toRegister(i), MacroAssembler::Address(GPRInfo::regT0));
72 }
73
74 // Tell GC mark phase how much of the scratch buffer is active during call.
75 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->addressOfActiveLength()), GPRInfo::regT0);
76 jit.storePtr(MacroAssembler::TrustedImmPtr(scratchSize), MacroAssembler::Address(GPRInfo::regT0));
77
78 // Set up one argument.
79 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
80 jit.prepareCallOperation(vm);
81
82 MacroAssembler::Call functionCall = jit.call(OperationPtrTag);
83
84 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->addressOfActiveLength()), GPRInfo::regT0);
85 jit.storePtr(MacroAssembler::TrustedImmPtr(nullptr), MacroAssembler::Address(GPRInfo::regT0));
86
87 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
88 jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
89 jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::toRegister(i));
90 }
91 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
92#if USE(JSVALUE64)
93 jit.load64(buffer + i, GPRInfo::toRegister(i));
94#else
95 jit.load32(buffer + i, GPRInfo::toRegister(i));
96#endif
97 }
98
99 jit.farJump(MacroAssembler::AbsoluteAddress(&vm.osrExitJumpDestination), OSRExitPtrTag);
100
101 LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
102
103 patchBuffer.link(functionCall, FunctionPtr<OperationPtrTag>(operationCompileOSRExit));
104
105 return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "DFG OSR exit generation thunk");
106}
107
108MacroAssemblerCodeRef<JITThunkPtrTag> osrEntryThunkGenerator(VM& vm)
109{
110 AssemblyHelpers jit(nullptr);
111
112 // We get passed the address of a scratch buffer in GPRInfo::returnValueGPR2.
113 // The first 8-byte slot of the buffer is the frame size. The second 8-byte slot
114 // is the pointer to where we are supposed to jump. The remaining bytes are
115 // the new call frame header followed by the locals.
116
117 ptrdiff_t offsetOfFrameSize = 0; // This is the DFG frame count.
118 ptrdiff_t offsetOfTargetPC = offsetOfFrameSize + sizeof(EncodedJSValue);
119 ptrdiff_t offsetOfPayload = offsetOfTargetPC + sizeof(EncodedJSValue);
120 ptrdiff_t offsetOfLocals = offsetOfPayload + sizeof(Register) * CallFrame::headerSizeInRegisters;
121
122 jit.move(GPRInfo::returnValueGPR2, GPRInfo::regT0);
123 jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfFrameSize), GPRInfo::regT1); // Load the frame size.
124 jit.negPtr(GPRInfo::regT1, GPRInfo::regT2);
125 jit.getEffectiveAddress(MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT2, MacroAssembler::TimesEight), MacroAssembler::stackPointerRegister);
126
127 MacroAssembler::Label loop = jit.label();
128 jit.subPtr(MacroAssembler::TrustedImm32(1), GPRInfo::regT1);
129 jit.negPtr(GPRInfo::regT1, GPRInfo::regT4);
130 jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals), GPRInfo::regT2);
131 jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals + sizeof(int32_t)), GPRInfo::regT3);
132 jit.store32(GPRInfo::regT2, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register))));
133 jit.store32(GPRInfo::regT3, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register)) + static_cast<intptr_t>(sizeof(int32_t))));
134 jit.branchPtr(MacroAssembler::NotEqual, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(-static_cast<intptr_t>(CallFrame::headerSizeInRegisters)))).linkTo(loop, &jit);
135
136 jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::regT1);
137 MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
138 jit.abortWithReason(DFGUnreasonableOSREntryJumpDestination);
139
140 ok.link(&jit);
141 jit.restoreCalleeSavesFromEntryFrameCalleeSavesBuffer(vm.topEntryFrame);
142 jit.emitMaterializeTagCheckRegisters();
143
144 jit.farJump(GPRInfo::regT1, GPRInfo::callFrameRegister);
145
146 LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
147 return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "DFG OSR entry thunk");
148}
149
150} } // namespace JSC::DFG
151
152#endif // ENABLE(DFG_JIT)
153