898a6905e3be23b812bd89fe6d29cfc41b888d20
[WebKit-https.git] / Source / JavaScriptCore / jit / JITInlineCacheGenerator.cpp
1 /*
2  * Copyright (C) 2013, 2015 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 "LinkBuffer.h"
33 #include "JSCInlines.h"
34
35 namespace JSC {
36
37 static StructureStubInfo* garbageStubInfo()
38 {
39     static StructureStubInfo* stubInfo = new StructureStubInfo(AccessType::Get);
40     return stubInfo;
41 }
42
43 JITInlineCacheGenerator::JITInlineCacheGenerator(
44     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType)
45     : m_codeBlock(codeBlock)
46 {
47     m_stubInfo = m_codeBlock ? m_codeBlock->addStubInfo(accessType) : garbageStubInfo();
48     m_stubInfo->codeOrigin = codeOrigin;
49     m_stubInfo->callSiteIndex = callSite;
50 }
51
52 JITByIdGenerator::JITByIdGenerator(
53     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType,
54     const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs value,
55     SpillRegistersMode spillMode)
56     : JITInlineCacheGenerator(codeBlock, codeOrigin, callSite, accessType)
57     , m_base(base)
58     , m_value(value)
59 {
60     m_stubInfo->patch.spillMode = spillMode;
61     m_stubInfo->patch.usedRegisters = usedRegisters;
62     
63     // This is a convenience - in cases where the only registers you're using are base/value,
64     // it allows you to pass RegisterSet() as the usedRegisters argument.
65     m_stubInfo->patch.usedRegisters.set(base);
66     m_stubInfo->patch.usedRegisters.set(value);
67     
68     m_stubInfo->patch.baseGPR = static_cast<int8_t>(base.payloadGPR());
69     m_stubInfo->patch.valueGPR = static_cast<int8_t>(value.payloadGPR());
70 #if USE(JSVALUE32_64)
71     m_stubInfo->patch.valueTagGPR = static_cast<int8_t>(value.tagGPR());
72 #endif
73 }
74
75 void JITByIdGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath)
76 {
77     CodeLocationCall callReturnLocation = slowPath.locationOf(m_call);
78     m_stubInfo->callReturnLocation = callReturnLocation;
79     m_stubInfo->patch.deltaCheckImmToCall = MacroAssembler::differenceBetweenCodePtr(
80         fastPath.locationOf(m_structureImm), callReturnLocation);
81     m_stubInfo->patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
82         callReturnLocation, fastPath.locationOf(m_structureCheck));
83 #if USE(JSVALUE64)
84     m_stubInfo->patch.deltaCallToLoadOrStore = MacroAssembler::differenceBetweenCodePtr(
85         callReturnLocation, fastPath.locationOf(m_loadOrStore));
86 #else
87     m_stubInfo->patch.deltaCallToTagLoadOrStore = MacroAssembler::differenceBetweenCodePtr(
88         callReturnLocation, fastPath.locationOf(m_tagLoadOrStore));
89     m_stubInfo->patch.deltaCallToPayloadLoadOrStore = MacroAssembler::differenceBetweenCodePtr(
90         callReturnLocation, fastPath.locationOf(m_loadOrStore));
91 #endif
92     m_stubInfo->patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
93         callReturnLocation, slowPath.locationOf(m_slowPathBegin));
94     m_stubInfo->patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
95         callReturnLocation, fastPath.locationOf(m_done));
96 }
97
98 void JITByIdGenerator::finalize(LinkBuffer& linkBuffer)
99 {
100     finalize(linkBuffer, linkBuffer);
101 }
102
103 void JITByIdGenerator::generateFastPathChecks(MacroAssembler& jit)
104 {
105     m_structureCheck = jit.patchableBranch32WithPatch(
106         MacroAssembler::NotEqual,
107         MacroAssembler::Address(m_base.payloadGPR(), JSCell::structureIDOffset()),
108         m_structureImm, MacroAssembler::TrustedImm32(0));
109 }
110
111 JITGetByIdGenerator::JITGetByIdGenerator(
112     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
113     JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode)
114     : JITByIdGenerator(
115         codeBlock, codeOrigin, callSite, AccessType::Get, usedRegisters, base, value, spillMode)
116 {
117     RELEASE_ASSERT(base.payloadGPR() != value.tagGPR());
118 }
119
120 void JITGetByIdGenerator::generateFastPath(MacroAssembler& jit)
121 {
122     generateFastPathChecks(jit);
123     
124 #if USE(JSVALUE64)
125     m_loadOrStore = jit.load64WithCompactAddressOffsetPatch(
126         MacroAssembler::Address(m_base.payloadGPR(), 0), m_value.payloadGPR()).label();
127 #else
128     m_tagLoadOrStore = jit.load32WithCompactAddressOffsetPatch(
129         MacroAssembler::Address(m_base.payloadGPR(), 0), m_value.tagGPR()).label();
130     m_loadOrStore = jit.load32WithCompactAddressOffsetPatch(
131         MacroAssembler::Address(m_base.payloadGPR(), 0), m_value.payloadGPR()).label();
132 #endif
133     
134     m_done = jit.label();
135 }
136
137 JITPutByIdGenerator::JITPutByIdGenerator(
138     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
139     JSValueRegs base, JSValueRegs value, GPRReg scratch, SpillRegistersMode spillMode,
140     ECMAMode ecmaMode, PutKind putKind)
141     : JITByIdGenerator(
142         codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value, spillMode)
143     , m_ecmaMode(ecmaMode)
144     , m_putKind(putKind)
145 {
146     m_stubInfo->patch.usedRegisters.clear(scratch);
147 }
148
149 void JITPutByIdGenerator::generateFastPath(MacroAssembler& jit)
150 {
151     generateFastPathChecks(jit);
152     
153 #if USE(JSVALUE64)
154     m_loadOrStore = jit.store64WithAddressOffsetPatch(
155         m_value.payloadGPR(), MacroAssembler::Address(m_base.payloadGPR(), 0)).label();
156 #else
157     m_tagLoadOrStore = jit.store32WithAddressOffsetPatch(
158         m_value.tagGPR(), MacroAssembler::Address(m_base.payloadGPR(), 0)).label();
159     m_loadOrStore = jit.store32WithAddressOffsetPatch(
160         m_value.payloadGPR(), MacroAssembler::Address(m_base.payloadGPR(), 0)).label();
161 #endif
162     
163     m_done = jit.label();
164 }
165
166 V_JITOperation_ESsiJJI JITPutByIdGenerator::slowPathFunction()
167 {
168     if (m_ecmaMode == StrictMode) {
169         if (m_putKind == Direct)
170             return operationPutByIdDirectStrictOptimize;
171         return operationPutByIdStrictOptimize;
172     }
173     if (m_putKind == Direct)
174         return operationPutByIdDirectNonStrictOptimize;
175     return operationPutByIdNonStrictOptimize;
176 }
177
178 } // namespace JSC
179
180 #endif // ENABLE(JIT)
181