MathICs should be able to take and dump stats about code size
[WebKit-https.git] / Source / JavaScriptCore / jit / JITMathIC.h
1 /*
2  * Copyright (C) 2016 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 #pragma once
27
28 #if ENABLE(JIT)
29
30 #include "CCallHelpers.h"
31 #include "JITAddGenerator.h"
32 #include "JITMathICInlineResult.h"
33 #include "JITMulGenerator.h"
34 #include "LinkBuffer.h"
35 #include "Repatch.h"
36 #include "SnippetOperand.h"
37
38 namespace JSC {
39
40 class LinkBuffer;
41
42 struct MathICGenerationState {
43     MacroAssembler::Label fastPathStart;
44     MacroAssembler::Label fastPathEnd;
45     MacroAssembler::Label slowPathStart;
46     MacroAssembler::Call slowPathCall;
47     MacroAssembler::JumpList slowPathJumps;
48     bool shouldSlowPathRepatch;
49 };
50
51 #define ENABLE_MATH_IC_STATS 0
52
53 template <typename GeneratorType>
54 class JITMathIC {
55 public:
56     CodeLocationLabel doneLocation() { return m_inlineStart.labelAtOffset(m_inlineSize); }
57     CodeLocationLabel slowPathStartLocation() { return m_inlineStart.labelAtOffset(m_deltaFromStartToSlowPathStart); }
58     CodeLocationCall slowPathCallLocation() { return m_inlineStart.callAtOffset(m_deltaFromStartToSlowPathCallLocation); }
59
60     bool isLeftOperandValidConstant() const { return m_generator.isLeftOperandValidConstant(); }
61     bool isRightOperandValidConstant() const { return m_generator.isRightOperandValidConstant(); }
62
63     bool generateInline(CCallHelpers& jit, MathICGenerationState& state, bool shouldEmitProfiling = true)
64     {
65         state.fastPathStart = jit.label();
66         size_t startSize = jit.m_assembler.buffer().codeSize();
67         JITMathICInlineResult result = m_generator.generateInline(jit, state);
68
69         switch (result) {
70         case JITMathICInlineResult::GeneratedFastPath: {
71             size_t inlineSize = jit.m_assembler.buffer().codeSize() - startSize;
72             if (static_cast<ptrdiff_t>(inlineSize) < MacroAssembler::maxJumpReplacementSize()) {
73                 size_t nopsToEmitInBytes = MacroAssembler::maxJumpReplacementSize() - inlineSize;
74                 jit.emitNops(nopsToEmitInBytes);
75             }
76             state.shouldSlowPathRepatch = true;
77             state.fastPathEnd = jit.label();
78             return true;
79         }
80         case JITMathICInlineResult::GenerateFullSnippet: {
81             MacroAssembler::JumpList endJumpList;
82             bool result = m_generator.generateFastPath(jit, endJumpList, state.slowPathJumps, shouldEmitProfiling);
83             if (result) {
84                 state.fastPathEnd = jit.label();
85                 state.shouldSlowPathRepatch = false;
86                 endJumpList.link(&jit);
87                 return true;
88             }
89             return false;
90         }
91         case JITMathICInlineResult::DontGenerate: {
92             return false;
93         }
94         default:
95             ASSERT_NOT_REACHED();
96         }
97
98         return false;
99     }
100
101     void generateOutOfLine(VM& vm, CodeBlock* codeBlock, FunctionPtr callReplacement)
102     {
103         // We rewire to the alternate regardless of whether or not we can allocate the out of line path
104         // because if we fail allocating the out of line path, we don't want to waste time trying to
105         // allocate it in the future.
106         ftlThunkAwareRepatchCall(codeBlock, slowPathCallLocation(), callReplacement);
107
108         {
109             CCallHelpers jit(&vm, codeBlock);
110
111             MacroAssembler::JumpList endJumpList; 
112             MacroAssembler::JumpList slowPathJumpList; 
113
114             bool shouldEmitProfiling = !JITCode::isOptimizingJIT(codeBlock->jitType());
115             bool emittedFastPath = m_generator.generateFastPath(jit, endJumpList, slowPathJumpList, shouldEmitProfiling);
116             if (!emittedFastPath)
117                 return;
118             endJumpList.append(jit.jump());
119
120             LinkBuffer linkBuffer(vm, jit, codeBlock, JITCompilationCanFail);
121             if (linkBuffer.didFailToAllocate())
122                 return;
123
124             linkBuffer.link(endJumpList, doneLocation());
125             linkBuffer.link(slowPathJumpList, slowPathStartLocation());
126
127             m_code = FINALIZE_CODE_FOR(
128                 codeBlock, linkBuffer, ("JITMathIC: generating out of line IC snippet"));
129         }
130
131         {
132             CCallHelpers jit(&vm, codeBlock);
133             auto jump = jit.jump();
134             // We don't need a nop sled here because nobody should be jumping into the middle of an IC.
135             bool needsBranchCompaction = false;
136             RELEASE_ASSERT(jit.m_assembler.buffer().codeSize() <= static_cast<size_t>(m_inlineSize));
137             LinkBuffer linkBuffer(jit, m_inlineStart.dataLocation(), jit.m_assembler.buffer().codeSize(), JITCompilationMustSucceed, needsBranchCompaction);
138             RELEASE_ASSERT(linkBuffer.isValid());
139             linkBuffer.link(jump, CodeLocationLabel(m_code.code()));
140             FINALIZE_CODE(linkBuffer, ("JITMathIC: linking constant jump to out of line stub"));
141         }
142     }
143
144     void finalizeInlineCode(const MathICGenerationState& state, LinkBuffer& linkBuffer)
145     {
146         CodeLocationLabel start = linkBuffer.locationOf(state.fastPathStart);
147         m_inlineStart = start;
148
149         m_inlineSize = MacroAssembler::differenceBetweenCodePtr(
150             start, linkBuffer.locationOf(state.fastPathEnd));
151         ASSERT(m_inlineSize > 0);
152
153         m_deltaFromStartToSlowPathCallLocation = MacroAssembler::differenceBetweenCodePtr(
154             start, linkBuffer.locationOf(state.slowPathCall));
155         m_deltaFromStartToSlowPathStart = MacroAssembler::differenceBetweenCodePtr(
156             start, linkBuffer.locationOf(state.slowPathStart));
157     }
158
159 #if ENABLE(MATH_IC_STATS)
160     size_t m_generatedCodeSize { 0 };
161     size_t codeSize() const
162     {
163         size_t result = m_generatedCodeSize;
164         if (m_code)
165             result += m_code.size();
166         return result;
167     }
168 #endif
169
170     MacroAssemblerCodeRef m_code;
171     CodeLocationLabel m_inlineStart;
172     int32_t m_inlineSize;
173     int32_t m_deltaFromStartToSlowPathCallLocation;
174     int32_t m_deltaFromStartToSlowPathStart;
175     GeneratorType m_generator;
176 };
177
178 typedef JITMathIC<JITAddGenerator> JITAddIC;
179 typedef JITMathIC<JITMulGenerator> JITMulIC;
180
181 } // namespace JSC
182
183 #endif // ENABLE(JIT)