Enhance the MacroAssembler and LinkBuffer to support pointer profiling.
[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 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, NoPtrTag, "DFG OSR exit thunk");
49 }
50
51 MacroAssemblerCodeRef 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, JITCode::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(NoPtrTag);
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), NoPtrTag);
103
104     LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
105     
106     patchBuffer.link(functionCall, OSRExit::compileOSRExit, NoPtrTag);
107     
108     return FINALIZE_CODE(patchBuffer, NoPtrTag, "DFG OSR exit generation thunk");
109 }
110
111 MacroAssemblerCodeRef osrEntryThunkGenerator(VM* vm)
112 {
113     AssemblyHelpers jit(nullptr);
114
115     // We get passed the address of a scratch buffer. The first 8-byte slot of the buffer
116     // is the frame size. The second 8-byte slot is the pointer to where we are supposed to
117     // jump. The remaining bytes are the new call frame header followed by the locals.
118     
119     ptrdiff_t offsetOfFrameSize = 0; // This is the DFG frame count.
120     ptrdiff_t offsetOfTargetPC = offsetOfFrameSize + sizeof(EncodedJSValue);
121     ptrdiff_t offsetOfPayload = offsetOfTargetPC + sizeof(EncodedJSValue);
122     ptrdiff_t offsetOfLocals = offsetOfPayload + sizeof(Register) * CallFrame::headerSizeInRegisters;
123     
124     jit.move(GPRInfo::returnValueGPR2, GPRInfo::regT0);
125     jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfFrameSize), GPRInfo::regT1); // Load the frame size.
126     jit.negPtr(GPRInfo::regT1, GPRInfo::regT2);
127     jit.getEffectiveAddress(MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT2, MacroAssembler::TimesEight), MacroAssembler::stackPointerRegister);
128     
129     MacroAssembler::Label loop = jit.label();
130     jit.subPtr(MacroAssembler::TrustedImm32(1), GPRInfo::regT1);
131     jit.negPtr(GPRInfo::regT1, GPRInfo::regT4);
132     jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals), GPRInfo::regT2);
133     jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals + sizeof(int32_t)), GPRInfo::regT3);
134     jit.store32(GPRInfo::regT2, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register))));
135     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))));
136     jit.branchPtr(MacroAssembler::NotEqual, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(-static_cast<intptr_t>(CallFrame::headerSizeInRegisters)))).linkTo(loop, &jit);
137     
138     jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::regT1);
139     MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
140     jit.abortWithReason(DFGUnreasonableOSREntryJumpDestination);
141
142     ok.link(&jit);
143     jit.restoreCalleeSavesFromEntryFrameCalleeSavesBuffer(vm->topEntryFrame);
144     jit.emitMaterializeTagCheckRegisters();
145
146     jit.jump(GPRInfo::regT1, NoPtrTag);
147     
148     LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
149     return FINALIZE_CODE(patchBuffer, NoPtrTag, "DFG OSR entry thunk");
150 }
151
152 } } // namespace JSC::DFG
153
154 #endif // ENABLE(DFG_JIT)