Make JITType an enum class
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGThunks.cpp
1 /*
2  * Copyright (C) 2011-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 "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
41 namespace JSC { namespace DFG {
42
43 MacroAssemblerCodeRef<JITThunkPtrTag> osrExitThunkGenerator(VM* vm)
44 {
45     MacroAssembler jit;
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
51 MacroAssemblerCodeRef<JITThunkPtrTag> osrExitGenerationThunkGenerator(VM* vm)
52 {
53     MacroAssembler jit;
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 #if CPU(X86)
80     jit.poke(GPRInfo::callFrameRegister, 0);
81 #else
82     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
83 #endif
84
85     MacroAssembler::Call functionCall = jit.call(OperationPtrTag);
86
87     jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->addressOfActiveLength()), GPRInfo::regT0);
88     jit.storePtr(MacroAssembler::TrustedImmPtr(nullptr), MacroAssembler::Address(GPRInfo::regT0));
89
90     for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
91         jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
92         jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::toRegister(i));
93     }
94     for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
95 #if USE(JSVALUE64)
96         jit.load64(buffer + i, GPRInfo::toRegister(i));
97 #else
98         jit.load32(buffer + i, GPRInfo::toRegister(i));
99 #endif
100     }
101
102     jit.jump(MacroAssembler::AbsoluteAddress(&vm->osrExitJumpDestination), OSRExitPtrTag);
103
104     LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
105     
106     patchBuffer.link(functionCall, FunctionPtr<OperationPtrTag>(OSRExit::compileOSRExit));
107
108     return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "DFG OSR exit generation thunk");
109 }
110
111 MacroAssemblerCodeRef<JITThunkPtrTag> osrEntryThunkGenerator(VM* vm)
112 {
113     AssemblyHelpers jit(nullptr);
114
115     // We get passed the address of a scratch buffer in GPRInfo::returnValueGPR2.
116     // The first 8-byte slot of the buffer is the frame size. The second 8-byte slot
117     // is the pointer to where we are supposed to jump. The remaining bytes are
118     // the new call frame header followed by the locals.
119     
120     ptrdiff_t offsetOfFrameSize = 0; // This is the DFG frame count.
121     ptrdiff_t offsetOfTargetPC = offsetOfFrameSize + sizeof(EncodedJSValue);
122     ptrdiff_t offsetOfPayload = offsetOfTargetPC + sizeof(EncodedJSValue);
123     ptrdiff_t offsetOfLocals = offsetOfPayload + sizeof(Register) * CallFrame::headerSizeInRegisters;
124     
125     jit.move(GPRInfo::returnValueGPR2, GPRInfo::regT0);
126     jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfFrameSize), GPRInfo::regT1); // Load the frame size.
127     jit.negPtr(GPRInfo::regT1, GPRInfo::regT2);
128     jit.getEffectiveAddress(MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT2, MacroAssembler::TimesEight), MacroAssembler::stackPointerRegister);
129     
130     MacroAssembler::Label loop = jit.label();
131     jit.subPtr(MacroAssembler::TrustedImm32(1), GPRInfo::regT1);
132     jit.negPtr(GPRInfo::regT1, GPRInfo::regT4);
133     jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals), GPRInfo::regT2);
134     jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals + sizeof(int32_t)), GPRInfo::regT3);
135     jit.store32(GPRInfo::regT2, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register))));
136     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))));
137     jit.branchPtr(MacroAssembler::NotEqual, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(-static_cast<intptr_t>(CallFrame::headerSizeInRegisters)))).linkTo(loop, &jit);
138     
139     jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::regT1);
140     MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
141     jit.abortWithReason(DFGUnreasonableOSREntryJumpDestination);
142
143     ok.link(&jit);
144     jit.restoreCalleeSavesFromEntryFrameCalleeSavesBuffer(vm->topEntryFrame);
145     jit.emitMaterializeTagCheckRegisters();
146
147     jit.jump(GPRInfo::regT1, GPRInfo::callFrameRegister);
148
149     LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
150     return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, "DFG OSR entry thunk");
151 }
152
153 } } // namespace JSC::DFG
154
155 #endif // ENABLE(DFG_JIT)