1/*
2 * Copyright (C) 2013-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 "JITInlineCacheGenerator.h"
28
29#if ENABLE(JIT)
30
31#include "CodeBlock.h"
32#include "InlineAccess.h"
33#include "JSCInlines.h"
34#include "LinkBuffer.h"
35#include "StructureStubInfo.h"
36
37namespace JSC {
38
39static StructureStubInfo* garbageStubInfo()
40{
41 static StructureStubInfo* stubInfo = new StructureStubInfo(AccessType::GetById);
42 return stubInfo;
43}
44
45JITInlineCacheGenerator::JITInlineCacheGenerator(
46 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType,
47 const RegisterSet& usedRegisters)
48 : m_codeBlock(codeBlock)
49{
50 m_stubInfo = m_codeBlock ? m_codeBlock->addStubInfo(accessType) : garbageStubInfo();
51 m_stubInfo->codeOrigin = codeOrigin;
52 m_stubInfo->callSiteIndex = callSite;
53
54 m_stubInfo->patch.usedRegisters = usedRegisters;
55}
56
57void JITInlineCacheGenerator::finalize(
58 LinkBuffer& fastPath, LinkBuffer& slowPath, CodeLocationLabel<JITStubRoutinePtrTag> start)
59{
60 m_stubInfo->patch.start = start;
61
62 m_stubInfo->patch.doneLocation = fastPath.locationOf<JSInternalPtrTag>(m_done);
63
64 m_stubInfo->patch.slowPathCallLocation = slowPath.locationOf<JSInternalPtrTag>(m_slowPathCall);
65 m_stubInfo->patch.slowPathStartLocation = slowPath.locationOf<JITStubRoutinePtrTag>(m_slowPathBegin);
66}
67
68JITByIdGenerator::JITByIdGenerator(
69 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType,
70 const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs value)
71 : JITInlineCacheGenerator(codeBlock, codeOrigin, callSite, accessType, usedRegisters)
72 , m_base(base)
73 , m_value(value)
74{
75 m_stubInfo->patch.baseGPR = base.payloadGPR();
76 m_stubInfo->patch.valueGPR = value.payloadGPR();
77 m_stubInfo->patch.u.thisGPR = InvalidGPRReg;
78#if USE(JSVALUE32_64)
79 m_stubInfo->patch.baseTagGPR = base.tagGPR();
80 m_stubInfo->patch.valueTagGPR = value.tagGPR();
81 m_stubInfo->patch.thisTagGPR = InvalidGPRReg;
82#endif
83}
84
85void JITByIdGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath)
86{
87 ASSERT(m_start.isSet());
88 JITInlineCacheGenerator::finalize(
89 fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start));
90}
91
92void JITByIdGenerator::generateFastCommon(MacroAssembler& jit, size_t inlineICSize)
93{
94 m_start = jit.label();
95 size_t startSize = jit.m_assembler.buffer().codeSize();
96 m_slowPathJump = jit.jump();
97 size_t jumpSize = jit.m_assembler.buffer().codeSize() - startSize;
98 size_t nopsToEmitInBytes = inlineICSize - jumpSize;
99 jit.emitNops(nopsToEmitInBytes);
100 ASSERT(jit.m_assembler.buffer().codeSize() - startSize == inlineICSize);
101 m_done = jit.label();
102}
103
104JITGetByIdGenerator::JITGetByIdGenerator(
105 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
106 UniquedStringImpl* propertyName, JSValueRegs base, JSValueRegs value, AccessType accessType)
107 : JITByIdGenerator(codeBlock, codeOrigin, callSite, accessType, usedRegisters, base, value)
108 , m_isLengthAccess(propertyName == codeBlock->vm().propertyNames->length.impl())
109{
110 RELEASE_ASSERT(base.payloadGPR() != value.tagGPR());
111}
112
113void JITGetByIdGenerator::generateFastPath(MacroAssembler& jit)
114{
115 generateFastCommon(jit, m_isLengthAccess ? InlineAccess::sizeForLengthAccess() : InlineAccess::sizeForPropertyAccess());
116}
117
118JITGetByIdWithThisGenerator::JITGetByIdWithThisGenerator(
119 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
120 UniquedStringImpl*, JSValueRegs value, JSValueRegs base, JSValueRegs thisRegs)
121 : JITByIdGenerator(codeBlock, codeOrigin, callSite, AccessType::GetByIdWithThis, usedRegisters, base, value)
122{
123 RELEASE_ASSERT(thisRegs.payloadGPR() != thisRegs.tagGPR());
124
125 m_stubInfo->patch.u.thisGPR = thisRegs.payloadGPR();
126#if USE(JSVALUE32_64)
127 m_stubInfo->patch.thisTagGPR = thisRegs.tagGPR();
128#endif
129}
130
131void JITGetByIdWithThisGenerator::generateFastPath(MacroAssembler& jit)
132{
133 generateFastCommon(jit, InlineAccess::sizeForPropertyAccess());
134}
135
136JITPutByIdGenerator::JITPutByIdGenerator(
137 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
138 JSValueRegs base, JSValueRegs value, GPRReg scratch,
139 ECMAMode ecmaMode, PutKind putKind)
140 : JITByIdGenerator(
141 codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value)
142 , m_ecmaMode(ecmaMode)
143 , m_putKind(putKind)
144{
145 m_stubInfo->patch.usedRegisters.clear(scratch);
146}
147
148void JITPutByIdGenerator::generateFastPath(MacroAssembler& jit)
149{
150 generateFastCommon(jit, InlineAccess::sizeForPropertyReplace());
151}
152
153V_JITOperation_GSsiJJI JITPutByIdGenerator::slowPathFunction()
154{
155 if (m_ecmaMode == StrictMode) {
156 if (m_putKind == Direct)
157 return operationPutByIdDirectStrictOptimize;
158 return operationPutByIdStrictOptimize;
159 }
160 if (m_putKind == Direct)
161 return operationPutByIdDirectNonStrictOptimize;
162 return operationPutByIdNonStrictOptimize;
163}
164
165JITInByIdGenerator::JITInByIdGenerator(
166 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
167 UniquedStringImpl* propertyName, JSValueRegs base, JSValueRegs value)
168 : JITByIdGenerator(codeBlock, codeOrigin, callSite, AccessType::In, usedRegisters, base, value)
169{
170 // FIXME: We are not supporting fast path for "length" property.
171 UNUSED_PARAM(propertyName);
172 RELEASE_ASSERT(base.payloadGPR() != value.tagGPR());
173}
174
175void JITInByIdGenerator::generateFastPath(MacroAssembler& jit)
176{
177 generateFastCommon(jit, InlineAccess::sizeForPropertyAccess());
178}
179
180JITInstanceOfGenerator::JITInstanceOfGenerator(
181 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex,
182 const RegisterSet& usedRegisters, GPRReg result, GPRReg value, GPRReg prototype,
183 GPRReg scratch1, GPRReg scratch2, bool prototypeIsKnownObject)
184 : JITInlineCacheGenerator(
185 codeBlock, codeOrigin, callSiteIndex, AccessType::InstanceOf, usedRegisters)
186{
187 m_stubInfo->patch.baseGPR = value;
188 m_stubInfo->patch.valueGPR = result;
189 m_stubInfo->patch.u.prototypeGPR = prototype;
190#if USE(JSVALUE32_64)
191 m_stubInfo->patch.baseTagGPR = InvalidGPRReg;
192 m_stubInfo->patch.valueTagGPR = InvalidGPRReg;
193 m_stubInfo->patch.thisTagGPR = InvalidGPRReg;
194#endif
195
196 m_stubInfo->patch.usedRegisters.clear(result);
197 if (scratch1 != InvalidGPRReg)
198 m_stubInfo->patch.usedRegisters.clear(scratch1);
199 if (scratch2 != InvalidGPRReg)
200 m_stubInfo->patch.usedRegisters.clear(scratch2);
201
202 m_stubInfo->prototypeIsKnownObject = prototypeIsKnownObject;
203
204 m_stubInfo->hasConstantIdentifier = false;
205}
206
207void JITInstanceOfGenerator::generateFastPath(MacroAssembler& jit)
208{
209 m_jump = jit.patchableJump();
210 m_done = jit.label();
211}
212
213void JITInstanceOfGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath)
214{
215 JITInlineCacheGenerator::finalize(
216 fastPath, slowPath,
217 fastPath.locationOf<JITStubRoutinePtrTag>(m_jump));
218
219 fastPath.link(m_jump.m_jump, slowPath.locationOf<NoPtrTag>(m_slowPathBegin));
220}
221
222JITGetByValGenerator::JITGetByValGenerator(CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs property, JSValueRegs result)
223 : Base(codeBlock, codeOrigin, callSiteIndex, AccessType::GetByVal, usedRegisters)
224 , m_base(base)
225 , m_result(result)
226{
227 m_stubInfo->hasConstantIdentifier = false;
228
229 m_stubInfo->patch.baseGPR = base.payloadGPR();
230 m_stubInfo->patch.u.propertyGPR = property.payloadGPR();
231 m_stubInfo->patch.valueGPR = result.payloadGPR();
232}
233
234void JITGetByValGenerator::generateFastPath(MacroAssembler& jit)
235{
236 m_start = jit.label();
237 m_slowPathJump = jit.patchableJump();
238 m_done = jit.label();
239}
240
241void JITGetByValGenerator::finalize(
242 LinkBuffer& fastPath, LinkBuffer& slowPath)
243{
244 ASSERT(m_start.isSet());
245 Base::finalize(
246 fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start));
247}
248
249} // namespace JSC
250
251#endif // ENABLE(JIT)
252
253