]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
93a37866 | 2 | * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. |
9dae56ea A |
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 | #ifndef JIT_h | |
27 | #define JIT_h | |
28 | ||
9dae56ea A |
29 | #if ENABLE(JIT) |
30 | ||
6fe7ccc8 A |
31 | // Verbose logging of code generation |
32 | #define ENABLE_JIT_VERBOSE 0 | |
33 | // Verbose logging for OSR-related code. | |
34 | #define ENABLE_JIT_VERBOSE_OSR 0 | |
35 | ||
ba379fdc A |
36 | // We've run into some problems where changing the size of the class JIT leads to |
37 | // performance fluctuations. Try forcing alignment in an attempt to stabalize this. | |
38 | #if COMPILER(GCC) | |
39 | #define JIT_CLASS_ALIGNMENT __attribute__ ((aligned (32))) | |
40 | #else | |
41 | #define JIT_CLASS_ALIGNMENT | |
42 | #endif | |
9dae56ea | 43 | |
14957cd0 | 44 | #define ASSERT_JIT_OFFSET(actual, expected) ASSERT_WITH_MESSAGE(actual == expected, "JIT Offset \"%s\" should be %d, not %d.\n", #expected, static_cast<int>(expected), static_cast<int>(actual)); |
f9bf01c6 | 45 | |
ba379fdc | 46 | #include "CodeBlock.h" |
6fe7ccc8 | 47 | #include "CompactJITCodeMap.h" |
9dae56ea | 48 | #include "Interpreter.h" |
93a37866 | 49 | #include "JITDisassembler.h" |
4e4e5a6f | 50 | #include "JSInterfaceJIT.h" |
93a37866 | 51 | #include "LegacyProfiler.h" |
9dae56ea | 52 | #include "Opcode.h" |
93a37866 A |
53 | #include "ResultType.h" |
54 | #include "UnusedPointer.h" | |
ba379fdc | 55 | #include <bytecode/SamplingTool.h> |
9dae56ea | 56 | |
9dae56ea A |
57 | namespace JSC { |
58 | ||
59 | class CodeBlock; | |
6fe7ccc8 | 60 | class FunctionExecutable; |
ba379fdc | 61 | class JIT; |
9dae56ea A |
62 | class JSPropertyNameIterator; |
63 | class Interpreter; | |
93a37866 A |
64 | class JSScope; |
65 | class JSStack; | |
66 | class MarkedAllocator; | |
9dae56ea | 67 | class Register; |
9dae56ea A |
68 | class StructureChain; |
69 | ||
70 | struct CallLinkInfo; | |
71 | struct Instruction; | |
72 | struct OperandTypes; | |
73 | struct PolymorphicAccessStructureList; | |
f9bf01c6 A |
74 | struct SimpleJumpTable; |
75 | struct StringJumpTable; | |
9dae56ea A |
76 | struct StructureStubInfo; |
77 | ||
9dae56ea | 78 | struct CallRecord { |
ba379fdc | 79 | MacroAssembler::Call from; |
14957cd0 | 80 | unsigned bytecodeOffset; |
9dae56ea A |
81 | void* to; |
82 | ||
83 | CallRecord() | |
84 | { | |
85 | } | |
86 | ||
14957cd0 | 87 | CallRecord(MacroAssembler::Call from, unsigned bytecodeOffset, void* to = 0) |
9dae56ea | 88 | : from(from) |
14957cd0 | 89 | , bytecodeOffset(bytecodeOffset) |
9dae56ea A |
90 | , to(to) |
91 | { | |
92 | } | |
93 | }; | |
94 | ||
95 | struct JumpTable { | |
96 | MacroAssembler::Jump from; | |
14957cd0 | 97 | unsigned toBytecodeOffset; |
9dae56ea A |
98 | |
99 | JumpTable(MacroAssembler::Jump f, unsigned t) | |
100 | : from(f) | |
14957cd0 | 101 | , toBytecodeOffset(t) |
9dae56ea A |
102 | { |
103 | } | |
104 | }; | |
105 | ||
106 | struct SlowCaseEntry { | |
107 | MacroAssembler::Jump from; | |
108 | unsigned to; | |
109 | unsigned hint; | |
110 | ||
111 | SlowCaseEntry(MacroAssembler::Jump f, unsigned t, unsigned h = 0) | |
112 | : from(f) | |
113 | , to(t) | |
114 | , hint(h) | |
115 | { | |
116 | } | |
117 | }; | |
118 | ||
119 | struct SwitchRecord { | |
120 | enum Type { | |
121 | Immediate, | |
122 | Character, | |
123 | String | |
124 | }; | |
125 | ||
126 | Type type; | |
127 | ||
128 | union { | |
129 | SimpleJumpTable* simpleJumpTable; | |
130 | StringJumpTable* stringJumpTable; | |
131 | } jumpTable; | |
132 | ||
14957cd0 | 133 | unsigned bytecodeOffset; |
9dae56ea A |
134 | unsigned defaultOffset; |
135 | ||
14957cd0 | 136 | SwitchRecord(SimpleJumpTable* jumpTable, unsigned bytecodeOffset, unsigned defaultOffset, Type type) |
9dae56ea | 137 | : type(type) |
14957cd0 | 138 | , bytecodeOffset(bytecodeOffset) |
9dae56ea A |
139 | , defaultOffset(defaultOffset) |
140 | { | |
141 | this->jumpTable.simpleJumpTable = jumpTable; | |
142 | } | |
143 | ||
14957cd0 | 144 | SwitchRecord(StringJumpTable* jumpTable, unsigned bytecodeOffset, unsigned defaultOffset) |
9dae56ea | 145 | : type(String) |
14957cd0 | 146 | , bytecodeOffset(bytecodeOffset) |
9dae56ea A |
147 | , defaultOffset(defaultOffset) |
148 | { | |
149 | this->jumpTable.stringJumpTable = jumpTable; | |
150 | } | |
151 | }; | |
152 | ||
6fe7ccc8 A |
153 | enum PropertyStubGetById_T { PropertyStubGetById }; |
154 | enum PropertyStubPutById_T { PropertyStubPutById }; | |
155 | ||
9dae56ea | 156 | struct PropertyStubCompilationInfo { |
93a37866 | 157 | enum Type { GetById, PutById } m_type; |
6fe7ccc8 A |
158 | |
159 | unsigned bytecodeIndex; | |
ba379fdc | 160 | MacroAssembler::Call callReturnLocation; |
9dae56ea | 161 | MacroAssembler::Label hotPathBegin; |
6fe7ccc8 A |
162 | MacroAssembler::DataLabelPtr getStructureToCompare; |
163 | MacroAssembler::PatchableJump getStructureCheck; | |
93a37866 | 164 | MacroAssembler::ConvertibleLoadLabel propertyStorageLoad; |
6fe7ccc8 A |
165 | #if USE(JSVALUE64) |
166 | MacroAssembler::DataLabelCompact getDisplacementLabel; | |
167 | #else | |
168 | MacroAssembler::DataLabelCompact getDisplacementLabel1; | |
169 | MacroAssembler::DataLabelCompact getDisplacementLabel2; | |
170 | #endif | |
171 | MacroAssembler::Label getPutResult; | |
172 | MacroAssembler::Label getColdPathBegin; | |
173 | MacroAssembler::DataLabelPtr putStructureToCompare; | |
174 | #if USE(JSVALUE64) | |
175 | MacroAssembler::DataLabel32 putDisplacementLabel; | |
176 | #else | |
177 | MacroAssembler::DataLabel32 putDisplacementLabel1; | |
178 | MacroAssembler::DataLabel32 putDisplacementLabel2; | |
179 | #endif | |
6fe7ccc8 A |
180 | |
181 | #if !ASSERT_DISABLED | |
182 | PropertyStubCompilationInfo() | |
183 | : bytecodeIndex(std::numeric_limits<unsigned>::max()) | |
184 | { | |
185 | } | |
186 | #endif | |
187 | ||
188 | ||
93a37866 A |
189 | PropertyStubCompilationInfo( |
190 | PropertyStubGetById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin, | |
191 | MacroAssembler::DataLabelPtr structureToCompare, | |
192 | MacroAssembler::PatchableJump structureCheck, | |
193 | MacroAssembler::ConvertibleLoadLabel propertyStorageLoad, | |
6fe7ccc8 | 194 | #if USE(JSVALUE64) |
93a37866 | 195 | MacroAssembler::DataLabelCompact displacementLabel, |
6fe7ccc8 | 196 | #else |
93a37866 A |
197 | MacroAssembler::DataLabelCompact displacementLabel1, |
198 | MacroAssembler::DataLabelCompact displacementLabel2, | |
6fe7ccc8 | 199 | #endif |
93a37866 | 200 | MacroAssembler::Label putResult) |
6fe7ccc8 A |
201 | : m_type(GetById) |
202 | , bytecodeIndex(bytecodeIndex) | |
203 | , hotPathBegin(hotPathBegin) | |
204 | , getStructureToCompare(structureToCompare) | |
205 | , getStructureCheck(structureCheck) | |
93a37866 | 206 | , propertyStorageLoad(propertyStorageLoad) |
6fe7ccc8 A |
207 | #if USE(JSVALUE64) |
208 | , getDisplacementLabel(displacementLabel) | |
209 | #else | |
210 | , getDisplacementLabel1(displacementLabel1) | |
211 | , getDisplacementLabel2(displacementLabel2) | |
212 | #endif | |
213 | , getPutResult(putResult) | |
214 | { | |
215 | } | |
216 | ||
93a37866 A |
217 | PropertyStubCompilationInfo( |
218 | PropertyStubPutById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin, | |
219 | MacroAssembler::DataLabelPtr structureToCompare, | |
220 | MacroAssembler::ConvertibleLoadLabel propertyStorageLoad, | |
6fe7ccc8 | 221 | #if USE(JSVALUE64) |
93a37866 | 222 | MacroAssembler::DataLabel32 displacementLabel |
6fe7ccc8 | 223 | #else |
93a37866 A |
224 | MacroAssembler::DataLabel32 displacementLabel1, |
225 | MacroAssembler::DataLabel32 displacementLabel2 | |
6fe7ccc8 | 226 | #endif |
93a37866 | 227 | ) |
6fe7ccc8 A |
228 | : m_type(PutById) |
229 | , bytecodeIndex(bytecodeIndex) | |
230 | , hotPathBegin(hotPathBegin) | |
93a37866 | 231 | , propertyStorageLoad(propertyStorageLoad) |
6fe7ccc8 A |
232 | , putStructureToCompare(structureToCompare) |
233 | #if USE(JSVALUE64) | |
234 | , putDisplacementLabel(displacementLabel) | |
235 | #else | |
236 | , putDisplacementLabel1(displacementLabel1) | |
237 | , putDisplacementLabel2(displacementLabel2) | |
238 | #endif | |
239 | { | |
240 | } | |
241 | ||
242 | void slowCaseInfo(PropertyStubGetById_T, MacroAssembler::Label coldPathBegin, MacroAssembler::Call call) | |
243 | { | |
93a37866 | 244 | ASSERT(m_type == GetById); |
6fe7ccc8 A |
245 | callReturnLocation = call; |
246 | getColdPathBegin = coldPathBegin; | |
247 | } | |
248 | ||
249 | void slowCaseInfo(PropertyStubPutById_T, MacroAssembler::Call call) | |
250 | { | |
251 | ASSERT(m_type == PutById); | |
252 | callReturnLocation = call; | |
253 | } | |
254 | ||
93a37866 A |
255 | void copyToStubInfo(StructureStubInfo& info, LinkBuffer &patchBuffer); |
256 | }; | |
257 | ||
258 | struct ByValCompilationInfo { | |
259 | ByValCompilationInfo() { } | |
260 | ||
261 | ByValCompilationInfo(unsigned bytecodeIndex, MacroAssembler::PatchableJump badTypeJump, JITArrayMode arrayMode, MacroAssembler::Label doneTarget) | |
262 | : bytecodeIndex(bytecodeIndex) | |
263 | , badTypeJump(badTypeJump) | |
264 | , arrayMode(arrayMode) | |
265 | , doneTarget(doneTarget) | |
6fe7ccc8 | 266 | { |
6fe7ccc8 | 267 | } |
93a37866 A |
268 | |
269 | unsigned bytecodeIndex; | |
270 | MacroAssembler::PatchableJump badTypeJump; | |
271 | JITArrayMode arrayMode; | |
272 | MacroAssembler::Label doneTarget; | |
273 | MacroAssembler::Label slowPathTarget; | |
274 | MacroAssembler::Call returnAddress; | |
9dae56ea A |
275 | }; |
276 | ||
277 | struct StructureStubCompilationInfo { | |
278 | MacroAssembler::DataLabelPtr hotPathBegin; | |
ba379fdc A |
279 | MacroAssembler::Call hotPathOther; |
280 | MacroAssembler::Call callReturnLocation; | |
6fe7ccc8 A |
281 | CallLinkInfo::CallType callType; |
282 | unsigned bytecodeIndex; | |
9dae56ea A |
283 | }; |
284 | ||
ba379fdc A |
285 | // Near calls can only be patched to other JIT code, regular calls can be patched to JIT code or relinked to stub functions. |
286 | void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction); | |
287 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction); | |
288 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction); | |
9dae56ea | 289 | |
4e4e5a6f | 290 | class JIT : private JSInterfaceJIT { |
ba379fdc | 291 | friend class JITStubCall; |
6fe7ccc8 | 292 | friend struct PropertyStubCompilationInfo; |
ba379fdc | 293 | |
9dae56ea A |
294 | using MacroAssembler::Jump; |
295 | using MacroAssembler::JumpList; | |
296 | using MacroAssembler::Label; | |
297 | ||
93a37866 | 298 | static const uintptr_t patchGetByIdDefaultStructure = unusedPointer; |
14957cd0 | 299 | static const int patchGetByIdDefaultOffset = 0; |
9dae56ea A |
300 | // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler |
301 | // will compress the displacement, and we may not be able to fit a patched offset. | |
14957cd0 | 302 | static const int patchPutByIdDefaultOffset = 256; |
9dae56ea | 303 | |
9dae56ea | 304 | public: |
93a37866 A |
305 | static JITCode compile(VM* vm, CodeBlock* codeBlock, JITCompilationEffort effort, CodePtr* functionEntryArityCheck = 0) |
306 | { | |
307 | return JIT(vm, codeBlock).privateCompile(functionEntryArityCheck, effort); | |
308 | } | |
309 | ||
310 | static void compileClosureCall(VM* vm, CallLinkInfo* callLinkInfo, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr) | |
9dae56ea | 311 | { |
93a37866 A |
312 | JIT jit(vm, callerCodeBlock); |
313 | jit.m_bytecodeOffset = callLinkInfo->codeOrigin.bytecodeIndex; | |
314 | jit.privateCompileClosureCall(callLinkInfo, calleeCodeBlock, expectedStructure, expectedExecutable, codePtr); | |
9dae56ea A |
315 | } |
316 | ||
93a37866 | 317 | static void compileGetByIdProto(VM* vm, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress) |
9dae56ea | 318 | { |
93a37866 | 319 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 320 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 321 | jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame); |
9dae56ea A |
322 | } |
323 | ||
93a37866 | 324 | static void compileGetByIdSelfList(VM* vm, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset) |
9dae56ea | 325 | { |
93a37866 | 326 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 327 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 328 | jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, ident, slot, cachedOffset); |
9dae56ea | 329 | } |
93a37866 | 330 | static void compileGetByIdProtoList(VM* vm, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset) |
9dae56ea | 331 | { |
93a37866 | 332 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 333 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 334 | jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, ident, slot, cachedOffset, callFrame); |
9dae56ea | 335 | } |
93a37866 | 336 | static void compileGetByIdChainList(VM* vm, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset) |
9dae56ea | 337 | { |
93a37866 | 338 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 339 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 340 | jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, ident, slot, cachedOffset, callFrame); |
9dae56ea | 341 | } |
9dae56ea | 342 | |
93a37866 | 343 | static void compileGetByIdChain(VM* vm, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress) |
9dae56ea | 344 | { |
93a37866 | 345 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 346 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 347 | jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame); |
9dae56ea | 348 | } |
9dae56ea | 349 | |
93a37866 | 350 | static void compilePutByIdTransition(VM* vm, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) |
9dae56ea | 351 | { |
93a37866 | 352 | JIT jit(vm, codeBlock); |
6fe7ccc8 | 353 | jit.m_bytecodeOffset = stubInfo->bytecodeIndex; |
4e4e5a6f | 354 | jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress, direct); |
9dae56ea | 355 | } |
93a37866 A |
356 | |
357 | static void compileGetByVal(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode) | |
358 | { | |
359 | JIT jit(vm, codeBlock); | |
360 | jit.m_bytecodeOffset = byValInfo->bytecodeIndex; | |
361 | jit.privateCompileGetByVal(byValInfo, returnAddress, arrayMode); | |
362 | } | |
9dae56ea | 363 | |
93a37866 | 364 | static void compilePutByVal(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode) |
9dae56ea | 365 | { |
93a37866 A |
366 | JIT jit(vm, codeBlock); |
367 | jit.m_bytecodeOffset = byValInfo->bytecodeIndex; | |
368 | jit.privateCompilePutByVal(byValInfo, returnAddress, arrayMode); | |
9dae56ea A |
369 | } |
370 | ||
93a37866 | 371 | static CodeRef compileCTINativeCall(VM* vm, NativeFunction func) |
14957cd0 | 372 | { |
93a37866 | 373 | if (!vm->canUseJIT()) { |
6fe7ccc8 A |
374 | #if ENABLE(LLINT) |
375 | return CodeRef::createLLIntCodeRef(llint_native_call_trampoline); | |
376 | #else | |
377 | return CodeRef(); | |
378 | #endif | |
379 | } | |
93a37866 A |
380 | JIT jit(vm, 0); |
381 | return jit.privateCompileCTINativeCall(vm, func); | |
14957cd0 A |
382 | } |
383 | ||
6fe7ccc8 A |
384 | static void resetPatchGetById(RepatchBuffer&, StructureStubInfo*); |
385 | static void resetPatchPutById(RepatchBuffer&, StructureStubInfo*); | |
93a37866 A |
386 | static void patchGetByIdSelf(CodeBlock*, StructureStubInfo*, Structure*, PropertyOffset cachedOffset, ReturnAddressPtr); |
387 | static void patchPutByIdReplace(CodeBlock*, StructureStubInfo*, Structure*, PropertyOffset cachedOffset, ReturnAddressPtr, bool direct); | |
9dae56ea | 388 | |
93a37866 | 389 | static void compilePatchGetArrayLength(VM* vm, CodeBlock* codeBlock, ReturnAddressPtr returnAddress) |
9dae56ea | 390 | { |
93a37866 A |
391 | JIT jit(vm, codeBlock); |
392 | #if ENABLE(DFG_JIT) | |
393 | // Force profiling to be enabled during stub generation. | |
394 | jit.m_canBeOptimized = true; | |
395 | jit.m_canBeOptimizedOrInlined = true; | |
396 | jit.m_shouldEmitProfiling = true; | |
397 | #endif // ENABLE(DFG_JIT) | |
9dae56ea A |
398 | return jit.privateCompilePatchGetArrayLength(returnAddress); |
399 | } | |
400 | ||
93a37866 A |
401 | static void linkFor(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, VM*, CodeSpecializationKind); |
402 | static void linkSlowCall(CodeBlock* callerCodeBlock, CallLinkInfo*); | |
9dae56ea | 403 | |
9dae56ea | 404 | private: |
93a37866 | 405 | JIT(VM*, CodeBlock* = 0); |
9dae56ea A |
406 | |
407 | void privateCompileMainPass(); | |
408 | void privateCompileLinkPass(); | |
409 | void privateCompileSlowCases(); | |
6fe7ccc8 | 410 | JITCode privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffort); |
93a37866 A |
411 | |
412 | void privateCompileClosureCall(CallLinkInfo*, CodeBlock* calleeCodeBlock, Structure*, ExecutableBase*, MacroAssemblerCodePtr); | |
413 | ||
414 | void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, ReturnAddressPtr, CallFrame*); | |
415 | void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset); | |
416 | void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, CallFrame*); | |
417 | void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, CallFrame*); | |
418 | void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, ReturnAddressPtr, CallFrame*); | |
419 | void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, PropertyOffset cachedOffset, StructureChain*, ReturnAddressPtr, bool direct); | |
420 | ||
421 | void privateCompileGetByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode); | |
422 | void privateCompilePutByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode); | |
423 | ||
424 | Label privateCompileCTINativeCall(VM*, bool isConstruct = false); | |
425 | CodeRef privateCompileCTINativeCall(VM*, NativeFunction); | |
ba379fdc | 426 | void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress); |
9dae56ea | 427 | |
6fe7ccc8 A |
428 | static bool isDirectPutById(StructureStubInfo*); |
429 | ||
9dae56ea | 430 | void addSlowCase(Jump); |
ba379fdc | 431 | void addSlowCase(JumpList); |
6fe7ccc8 | 432 | void addSlowCase(); |
9dae56ea A |
433 | void addJump(Jump, int); |
434 | void emitJumpSlowToHot(Jump, int); | |
435 | ||
6fe7ccc8 A |
436 | void compileOpCall(OpcodeID, Instruction*, unsigned callLinkInfoIndex); |
437 | void compileOpCallSlowCase(OpcodeID, Instruction*, Vector<SlowCaseEntry>::iterator&, unsigned callLinkInfoIndex); | |
438 | void compileLoadVarargs(Instruction*); | |
439 | void compileCallEval(); | |
440 | void compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator&); | |
ba379fdc | 441 | |
9dae56ea A |
442 | enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq }; |
443 | void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type); | |
f9bf01c6 A |
444 | bool isOperandConstantImmediateDouble(unsigned src); |
445 | ||
6fe7ccc8 A |
446 | void emitLoadDouble(int index, FPRegisterID value); |
447 | void emitLoadInt32ToDouble(int index, FPRegisterID value); | |
448 | Jump emitJumpIfNotObject(RegisterID structureReg); | |
f9bf01c6 | 449 | |
93a37866 A |
450 | Jump addStructureTransitionCheck(JSCell*, Structure*, StructureStubInfo*, RegisterID scratch); |
451 | void addStructureTransitionCheck(JSCell*, Structure*, StructureStubInfo*, JumpList& failureCases, RegisterID scratch); | |
452 | void testPrototype(JSValue, JumpList& failureCases, StructureStubInfo*); | |
9dae56ea | 453 | |
6fe7ccc8 A |
454 | enum WriteBarrierMode { UnconditionalWriteBarrier, ShouldFilterImmediates }; |
455 | // value register in write barrier is used before any scratch registers | |
456 | // so may safely be the same as either of the scratch registers. | |
457 | void emitWriteBarrier(RegisterID owner, RegisterID valueTag, RegisterID scratch, RegisterID scratch2, WriteBarrierMode, WriteBarrierUseKind); | |
458 | void emitWriteBarrier(JSCell* owner, RegisterID value, RegisterID scratch, WriteBarrierMode, WriteBarrierUseKind); | |
459 | ||
93a37866 A |
460 | template<typename StructureType> // StructureType can be RegisterID or ImmPtr. |
461 | void emitAllocateJSObject(RegisterID allocator, StructureType, RegisterID result, RegisterID scratch); | |
6fe7ccc8 A |
462 | |
463 | #if ENABLE(VALUE_PROFILER) | |
464 | // This assumes that the value to profile is in regT0 and that regT3 is available for | |
465 | // scratch. | |
466 | void emitValueProfilingSite(ValueProfile*); | |
467 | void emitValueProfilingSite(unsigned bytecodeOffset); | |
468 | void emitValueProfilingSite(); | |
469 | #else | |
470 | void emitValueProfilingSite(unsigned) { } | |
471 | void emitValueProfilingSite() { } | |
472 | #endif | |
93a37866 A |
473 | void emitArrayProfilingSite(RegisterID structureAndIndexingType, RegisterID scratch, ArrayProfile*); |
474 | void emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndIndexingType, RegisterID scratch, unsigned bytecodeIndex); | |
475 | void emitArrayProfileStoreToHoleSpecialCase(ArrayProfile*); | |
476 | void emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile*); | |
477 | ||
478 | JITArrayMode chooseArrayMode(ArrayProfile*); | |
479 | ||
480 | // Property is in regT1, base is in regT0. regT2 contains indexing type. | |
481 | // Property is int-checked and zero extended. Base is cell checked. | |
482 | // Structure is already profiled. Returns the slow cases. Fall-through | |
483 | // case contains result in regT0, and it is not yet profiled. | |
484 | JumpList emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); } | |
485 | JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType); | |
486 | JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape); | |
487 | JumpList emitArrayStorageGetByVal(Instruction*, PatchableJump& badType); | |
488 | JumpList emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness); | |
489 | JumpList emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize); | |
490 | ||
491 | // Property is in regT0, base is in regT0. regT2 contains indecing type. | |
492 | // The value to store is not yet loaded. Property is int-checked and | |
493 | // zero-extended. Base is cell checked. Structure is already profiled. | |
494 | // returns the slow cases. | |
495 | JumpList emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType) | |
496 | { | |
497 | return emitGenericContiguousPutByVal(currentInstruction, badType, Int32Shape); | |
498 | } | |
499 | JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType) | |
500 | { | |
501 | return emitGenericContiguousPutByVal(currentInstruction, badType, DoubleShape); | |
502 | } | |
503 | JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) | |
504 | { | |
505 | return emitGenericContiguousPutByVal(currentInstruction, badType); | |
506 | } | |
507 | JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType, IndexingType indexingShape = ContiguousShape); | |
508 | JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType); | |
509 | JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness, TypedArrayRounding); | |
510 | JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize); | |
511 | ||
512 | enum FinalObjectMode { MayBeFinal, KnownNotFinal }; | |
6fe7ccc8 | 513 | |
ba379fdc | 514 | #if USE(JSVALUE32_64) |
ba379fdc | 515 | bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant); |
ba379fdc | 516 | |
6fe7ccc8 A |
517 | void emitLoadTag(int index, RegisterID tag); |
518 | void emitLoadPayload(int index, RegisterID payload); | |
ba379fdc A |
519 | |
520 | void emitLoad(const JSValue& v, RegisterID tag, RegisterID payload); | |
6fe7ccc8 A |
521 | void emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); |
522 | void emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2); | |
523 | ||
524 | void emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); | |
525 | void emitStore(int index, const JSValue constant, RegisterID base = callFrameRegister); | |
526 | void emitStoreInt32(int index, RegisterID payload, bool indexIsInt32 = false); | |
527 | void emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32 = false); | |
528 | void emitStoreAndMapInt32(int index, RegisterID tag, RegisterID payload, bool indexIsInt32, size_t opcodeLength); | |
529 | void emitStoreCell(int index, RegisterID payload, bool indexIsCell = false); | |
530 | void emitStoreBool(int index, RegisterID payload, bool indexIsBool = false); | |
531 | void emitStoreDouble(int index, FPRegisterID value); | |
ba379fdc | 532 | |
14957cd0 | 533 | bool isLabeled(unsigned bytecodeOffset); |
6fe7ccc8 | 534 | void map(unsigned bytecodeOffset, int virtualRegisterIndex, RegisterID tag, RegisterID payload); |
ba379fdc A |
535 | void unmap(RegisterID); |
536 | void unmap(); | |
6fe7ccc8 A |
537 | bool isMapped(int virtualRegisterIndex); |
538 | bool getMappedPayload(int virtualRegisterIndex, RegisterID& payload); | |
539 | bool getMappedTag(int virtualRegisterIndex, RegisterID& tag); | |
93a37866 | 540 | |
6fe7ccc8 A |
541 | void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex); |
542 | void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag); | |
ba379fdc | 543 | |
93a37866 A |
544 | void compileGetByIdHotPath(Identifier*); |
545 | void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier*, Vector<SlowCaseEntry>::iterator&); | |
546 | void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset); | |
547 | void compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset); | |
548 | void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset, FinalObjectMode = MayBeFinal); | |
549 | void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, PropertyOffset cachedOffset); | |
9dae56ea | 550 | |
ba379fdc A |
551 | // Arithmetic opcode helpers |
552 | void emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType); | |
553 | void emitSub32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType); | |
554 | void emitBinaryDoubleOp(OpcodeID, unsigned dst, unsigned op1, unsigned op2, OperandTypes, JumpList& notInt32Op1, JumpList& notInt32Op2, bool op1IsInRegisters = true, bool op2IsInRegisters = true); | |
9dae56ea | 555 | |
6fe7ccc8 | 556 | #if CPU(ARM_TRADITIONAL) |
f9bf01c6 A |
557 | // sequenceOpCall |
558 | static const int sequenceOpCallInstructionSpace = 12; | |
559 | static const int sequenceOpCallConstantSpace = 2; | |
f9bf01c6 A |
560 | // sequenceGetByIdHotPath |
561 | static const int sequenceGetByIdHotPathInstructionSpace = 36; | |
562 | static const int sequenceGetByIdHotPathConstantSpace = 4; | |
563 | // sequenceGetByIdSlowCase | |
93a37866 | 564 | static const int sequenceGetByIdSlowCaseInstructionSpace = 80; |
6fe7ccc8 | 565 | static const int sequenceGetByIdSlowCaseConstantSpace = 4; |
f9bf01c6 A |
566 | // sequencePutById |
567 | static const int sequencePutByIdInstructionSpace = 36; | |
568 | static const int sequencePutByIdConstantSpace = 4; | |
14957cd0 | 569 | #elif CPU(SH4) |
14957cd0 A |
570 | // sequenceOpCall |
571 | static const int sequenceOpCallInstructionSpace = 12; | |
572 | static const int sequenceOpCallConstantSpace = 2; | |
14957cd0 A |
573 | // sequenceGetByIdHotPath |
574 | static const int sequenceGetByIdHotPathInstructionSpace = 36; | |
575 | static const int sequenceGetByIdHotPathConstantSpace = 5; | |
576 | // sequenceGetByIdSlowCase | |
6fe7ccc8 A |
577 | static const int sequenceGetByIdSlowCaseInstructionSpace = 38; |
578 | static const int sequenceGetByIdSlowCaseConstantSpace = 4; | |
14957cd0 A |
579 | // sequencePutById |
580 | static const int sequencePutByIdInstructionSpace = 36; | |
581 | static const int sequencePutByIdConstantSpace = 5; | |
ba379fdc | 582 | #endif |
9dae56ea | 583 | |
ba379fdc | 584 | #else // USE(JSVALUE32_64) |
93a37866 A |
585 | /* This function is deprecated. */ |
586 | void emitGetJITStubArg(unsigned argumentNumber, RegisterID dst); | |
587 | ||
ba379fdc A |
588 | void emitGetVirtualRegister(int src, RegisterID dst); |
589 | void emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2); | |
590 | void emitPutVirtualRegister(unsigned dst, RegisterID from = regT0); | |
6fe7ccc8 A |
591 | void emitStoreCell(unsigned dst, RegisterID payload, bool /* only used in JSValue32_64 */ = false) |
592 | { | |
593 | emitPutVirtualRegister(dst, payload); | |
594 | } | |
9dae56ea | 595 | |
9dae56ea | 596 | int32_t getConstantOperandImmediateInt(unsigned src); |
ba379fdc | 597 | |
ba379fdc | 598 | void killLastResultRegister(); |
9dae56ea A |
599 | |
600 | Jump emitJumpIfJSCell(RegisterID); | |
601 | Jump emitJumpIfBothJSCells(RegisterID, RegisterID, RegisterID); | |
602 | void emitJumpSlowCaseIfJSCell(RegisterID); | |
9dae56ea A |
603 | void emitJumpSlowCaseIfNotJSCell(RegisterID); |
604 | void emitJumpSlowCaseIfNotJSCell(RegisterID, int VReg); | |
6fe7ccc8 A |
605 | Jump emitJumpIfImmediateInteger(RegisterID); |
606 | Jump emitJumpIfNotImmediateInteger(RegisterID); | |
607 | Jump emitJumpIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); | |
9dae56ea | 608 | void emitJumpSlowCaseIfNotImmediateInteger(RegisterID); |
f9bf01c6 | 609 | void emitJumpSlowCaseIfNotImmediateNumber(RegisterID); |
9dae56ea A |
610 | void emitJumpSlowCaseIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); |
611 | ||
9dae56ea | 612 | void emitFastArithReTagImmediate(RegisterID src, RegisterID dest); |
9dae56ea A |
613 | |
614 | void emitTagAsBoolImmediate(RegisterID reg); | |
ba379fdc | 615 | void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi); |
f9bf01c6 | 616 | void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned dst, unsigned src1, unsigned src2, OperandTypes, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase); |
ba379fdc | 617 | |
6fe7ccc8 | 618 | void compileGetByIdHotPath(int baseVReg, Identifier*); |
93a37866 A |
619 | void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier*, Vector<SlowCaseEntry>::iterator&); |
620 | void compileGetDirectOffset(RegisterID base, RegisterID result, PropertyOffset cachedOffset); | |
621 | void compileGetDirectOffset(JSObject* base, RegisterID result, PropertyOffset cachedOffset); | |
622 | void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch, FinalObjectMode = MayBeFinal); | |
623 | void compilePutDirectOffset(RegisterID base, RegisterID value, PropertyOffset cachedOffset); | |
f9bf01c6 | 624 | |
ba379fdc A |
625 | #endif // USE(JSVALUE32_64) |
626 | ||
b80e6193 | 627 | #if (defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL) |
14957cd0 A |
628 | #define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false) |
629 | #define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace, dst); } while (false) | |
630 | #define END_UNINTERRUPTED_SEQUENCE(name) END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, 0) | |
f9bf01c6 A |
631 | |
632 | void beginUninterruptedSequence(int, int); | |
14957cd0 | 633 | void endUninterruptedSequence(int, int, int); |
f9bf01c6 A |
634 | |
635 | #else | |
6fe7ccc8 A |
636 | #define BEGIN_UNINTERRUPTED_SEQUENCE(name) |
637 | #define END_UNINTERRUPTED_SEQUENCE(name) | |
638 | #define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) | |
f9bf01c6 A |
639 | #endif |
640 | ||
6fe7ccc8 A |
641 | void emit_compareAndJump(OpcodeID, unsigned op1, unsigned op2, unsigned target, RelationalCondition); |
642 | void emit_compareAndJumpSlow(unsigned op1, unsigned op2, unsigned target, DoubleCondition, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION), bool invert, Vector<SlowCaseEntry>::iterator&); | |
643 | ||
ba379fdc A |
644 | void emit_op_add(Instruction*); |
645 | void emit_op_bitand(Instruction*); | |
ba379fdc A |
646 | void emit_op_bitor(Instruction*); |
647 | void emit_op_bitxor(Instruction*); | |
648 | void emit_op_call(Instruction*); | |
649 | void emit_op_call_eval(Instruction*); | |
650 | void emit_op_call_varargs(Instruction*); | |
14957cd0 | 651 | void emit_op_call_put_result(Instruction*); |
ba379fdc A |
652 | void emit_op_catch(Instruction*); |
653 | void emit_op_construct(Instruction*); | |
14957cd0 A |
654 | void emit_op_get_callee(Instruction*); |
655 | void emit_op_create_this(Instruction*); | |
ba379fdc A |
656 | void emit_op_convert_this(Instruction*); |
657 | void emit_op_create_arguments(Instruction*); | |
658 | void emit_op_debug(Instruction*); | |
659 | void emit_op_del_by_id(Instruction*); | |
660 | void emit_op_div(Instruction*); | |
661 | void emit_op_end(Instruction*); | |
662 | void emit_op_enter(Instruction*); | |
14957cd0 | 663 | void emit_op_create_activation(Instruction*); |
ba379fdc A |
664 | void emit_op_eq(Instruction*); |
665 | void emit_op_eq_null(Instruction*); | |
666 | void emit_op_get_by_id(Instruction*); | |
14957cd0 | 667 | void emit_op_get_arguments_length(Instruction*); |
ba379fdc | 668 | void emit_op_get_by_val(Instruction*); |
14957cd0 | 669 | void emit_op_get_argument_by_val(Instruction*); |
f9bf01c6 | 670 | void emit_op_get_by_pname(Instruction*); |
14957cd0 A |
671 | void emit_op_init_lazy_reg(Instruction*); |
672 | void emit_op_check_has_instance(Instruction*); | |
ba379fdc | 673 | void emit_op_instanceof(Instruction*); |
6fe7ccc8 A |
674 | void emit_op_is_undefined(Instruction*); |
675 | void emit_op_is_boolean(Instruction*); | |
676 | void emit_op_is_number(Instruction*); | |
677 | void emit_op_is_string(Instruction*); | |
ba379fdc A |
678 | void emit_op_jeq_null(Instruction*); |
679 | void emit_op_jfalse(Instruction*); | |
680 | void emit_op_jmp(Instruction*); | |
ba379fdc A |
681 | void emit_op_jneq_null(Instruction*); |
682 | void emit_op_jneq_ptr(Instruction*); | |
f9bf01c6 | 683 | void emit_op_jless(Instruction*); |
6fe7ccc8 A |
684 | void emit_op_jlesseq(Instruction*); |
685 | void emit_op_jgreater(Instruction*); | |
686 | void emit_op_jgreatereq(Instruction*); | |
687 | void emit_op_jnless(Instruction*); | |
ba379fdc | 688 | void emit_op_jnlesseq(Instruction*); |
6fe7ccc8 A |
689 | void emit_op_jngreater(Instruction*); |
690 | void emit_op_jngreatereq(Instruction*); | |
ba379fdc | 691 | void emit_op_jtrue(Instruction*); |
6fe7ccc8 | 692 | void emit_op_loop_hint(Instruction*); |
ba379fdc | 693 | void emit_op_lshift(Instruction*); |
ba379fdc A |
694 | void emit_op_mod(Instruction*); |
695 | void emit_op_mov(Instruction*); | |
696 | void emit_op_mul(Instruction*); | |
697 | void emit_op_negate(Instruction*); | |
698 | void emit_op_neq(Instruction*); | |
699 | void emit_op_neq_null(Instruction*); | |
700 | void emit_op_new_array(Instruction*); | |
93a37866 | 701 | void emit_op_new_array_with_size(Instruction*); |
14957cd0 | 702 | void emit_op_new_array_buffer(Instruction*); |
ba379fdc A |
703 | void emit_op_new_func(Instruction*); |
704 | void emit_op_new_func_exp(Instruction*); | |
705 | void emit_op_new_object(Instruction*); | |
706 | void emit_op_new_regexp(Instruction*); | |
f9bf01c6 | 707 | void emit_op_get_pnames(Instruction*); |
ba379fdc A |
708 | void emit_op_next_pname(Instruction*); |
709 | void emit_op_not(Instruction*); | |
710 | void emit_op_nstricteq(Instruction*); | |
711 | void emit_op_pop_scope(Instruction*); | |
93a37866 A |
712 | void emit_op_dec(Instruction*); |
713 | void emit_op_inc(Instruction*); | |
ba379fdc A |
714 | void emit_op_profile_did_call(Instruction*); |
715 | void emit_op_profile_will_call(Instruction*); | |
93a37866 A |
716 | void emit_op_push_name_scope(Instruction*); |
717 | void emit_op_push_with_scope(Instruction*); | |
ba379fdc A |
718 | void emit_op_put_by_id(Instruction*); |
719 | void emit_op_put_by_index(Instruction*); | |
720 | void emit_op_put_by_val(Instruction*); | |
6fe7ccc8 | 721 | void emit_op_put_getter_setter(Instruction*); |
93a37866 A |
722 | void emit_op_init_global_const(Instruction*); |
723 | void emit_op_init_global_const_check(Instruction*); | |
724 | void emit_resolve_operations(ResolveOperations*, const int* base, const int* value); | |
725 | void emitSlow_link_resolve_operations(ResolveOperations*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc A |
726 | void emit_op_resolve(Instruction*); |
727 | void emit_op_resolve_base(Instruction*); | |
ba379fdc | 728 | void emit_op_resolve_with_base(Instruction*); |
6fe7ccc8 | 729 | void emit_op_resolve_with_this(Instruction*); |
93a37866 | 730 | void emit_op_put_to_base(Instruction*); |
ba379fdc | 731 | void emit_op_ret(Instruction*); |
14957cd0 | 732 | void emit_op_ret_object_or_this(Instruction*); |
ba379fdc | 733 | void emit_op_rshift(Instruction*); |
ba379fdc A |
734 | void emit_op_strcat(Instruction*); |
735 | void emit_op_stricteq(Instruction*); | |
736 | void emit_op_sub(Instruction*); | |
737 | void emit_op_switch_char(Instruction*); | |
738 | void emit_op_switch_imm(Instruction*); | |
739 | void emit_op_switch_string(Instruction*); | |
740 | void emit_op_tear_off_activation(Instruction*); | |
741 | void emit_op_tear_off_arguments(Instruction*); | |
742 | void emit_op_throw(Instruction*); | |
93a37866 A |
743 | void emit_op_throw_static_error(Instruction*); |
744 | void emit_op_to_number(Instruction*); | |
ba379fdc A |
745 | void emit_op_to_primitive(Instruction*); |
746 | void emit_op_unexpected_load(Instruction*); | |
4e4e5a6f | 747 | void emit_op_urshift(Instruction*); |
93a37866 A |
748 | void emit_op_get_scoped_var(Instruction*); |
749 | void emit_op_put_scoped_var(Instruction*); | |
ba379fdc A |
750 | |
751 | void emitSlow_op_add(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
752 | void emitSlow_op_bitand(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc A |
753 | void emitSlow_op_bitor(Instruction*, Vector<SlowCaseEntry>::iterator&); |
754 | void emitSlow_op_bitxor(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
755 | void emitSlow_op_call(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
756 | void emitSlow_op_call_eval(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
757 | void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
758 | void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc | 759 | void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&); |
6fe7ccc8 | 760 | void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc A |
761 | void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&); |
762 | void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
763 | void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
14957cd0 | 764 | void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc | 765 | void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); |
14957cd0 | 766 | void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); |
f9bf01c6 | 767 | void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&); |
14957cd0 | 768 | void emitSlow_op_check_has_instance(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc A |
769 | void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&); |
770 | void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
f9bf01c6 | 771 | void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&); |
6fe7ccc8 A |
772 | void emitSlow_op_jlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); |
773 | void emitSlow_op_jgreater(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
774 | void emitSlow_op_jgreatereq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
775 | void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc | 776 | void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); |
6fe7ccc8 A |
777 | void emitSlow_op_jngreater(Instruction*, Vector<SlowCaseEntry>::iterator&); |
778 | void emitSlow_op_jngreatereq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc | 779 | void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&); |
93a37866 | 780 | void emitSlow_op_loop_hint(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc | 781 | void emitSlow_op_lshift(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc A |
782 | void emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&); |
783 | void emitSlow_op_mul(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
784 | void emitSlow_op_negate(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
785 | void emitSlow_op_neq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
6fe7ccc8 | 786 | void emitSlow_op_new_object(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc A |
787 | void emitSlow_op_not(Instruction*, Vector<SlowCaseEntry>::iterator&); |
788 | void emitSlow_op_nstricteq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
93a37866 A |
789 | void emitSlow_op_dec(Instruction*, Vector<SlowCaseEntry>::iterator&); |
790 | void emitSlow_op_inc(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
ba379fdc A |
791 | void emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); |
792 | void emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
93a37866 | 793 | void emitSlow_op_init_global_const_check(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc A |
794 | void emitSlow_op_rshift(Instruction*, Vector<SlowCaseEntry>::iterator&); |
795 | void emitSlow_op_stricteq(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
796 | void emitSlow_op_sub(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
93a37866 | 797 | void emitSlow_op_to_number(Instruction*, Vector<SlowCaseEntry>::iterator&); |
ba379fdc | 798 | void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&); |
4e4e5a6f | 799 | void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&); |
93a37866 A |
800 | |
801 | void emitSlow_op_resolve(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
802 | void emitSlow_op_resolve_base(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
803 | void emitSlow_op_resolve_with_base(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
804 | void emitSlow_op_resolve_with_this(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
805 | void emitSlow_op_put_to_base(Instruction*, Vector<SlowCaseEntry>::iterator&); | |
806 | ||
4e4e5a6f A |
807 | void emitRightShift(Instruction*, bool isUnsigned); |
808 | void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned); | |
ba379fdc | 809 | |
ba379fdc A |
810 | void emitInitRegister(unsigned dst); |
811 | ||
93a37866 A |
812 | void emitPutIntToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry); |
813 | void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry, RegisterID to, RegisterID from = callFrameRegister); | |
814 | void emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry, RegisterID to, RegisterID from = callFrameRegister); | |
815 | #if USE(JSVALUE64) | |
816 | void emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry, RegisterID to, RegisterID from = callFrameRegister); | |
817 | #endif | |
ba379fdc A |
818 | |
819 | JSValue getConstantOperand(unsigned src); | |
820 | bool isOperandConstantImmediateInt(unsigned src); | |
4e4e5a6f | 821 | bool isOperandConstantImmediateChar(unsigned src); |
ba379fdc | 822 | |
14957cd0 A |
823 | bool atJumpTarget(); |
824 | ||
ba379fdc A |
825 | Jump getSlowCase(Vector<SlowCaseEntry>::iterator& iter) |
826 | { | |
827 | return iter++->from; | |
828 | } | |
829 | void linkSlowCase(Vector<SlowCaseEntry>::iterator& iter) | |
830 | { | |
831 | iter->from.link(this); | |
832 | ++iter; | |
833 | } | |
6fe7ccc8 A |
834 | void linkDummySlowCase(Vector<SlowCaseEntry>::iterator& iter) |
835 | { | |
836 | ASSERT(!iter->from.isSet()); | |
837 | ++iter; | |
838 | } | |
839 | void linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator&, int virtualRegisterIndex); | |
ba379fdc A |
840 | |
841 | Jump checkStructure(RegisterID reg, Structure* structure); | |
9dae56ea | 842 | |
9dae56ea | 843 | void restoreArgumentReferenceForTrampoline(); |
6fe7ccc8 | 844 | void updateTopCallFrame(); |
9dae56ea | 845 | |
ba379fdc | 846 | Call emitNakedCall(CodePtr function = CodePtr()); |
9dae56ea | 847 | |
4e4e5a6f A |
848 | // Loads the character value of a single character string into dst. |
849 | void emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures); | |
850 | ||
6fe7ccc8 | 851 | #if ENABLE(DFG_JIT) |
93a37866 | 852 | void emitEnterOptimizationCheck(); |
6fe7ccc8 | 853 | #else |
93a37866 | 854 | void emitEnterOptimizationCheck() { } |
6fe7ccc8 | 855 | #endif |
93a37866 | 856 | |
9dae56ea A |
857 | #ifndef NDEBUG |
858 | void printBytecodeOperandTypes(unsigned src1, unsigned src2); | |
859 | #endif | |
860 | ||
ba379fdc A |
861 | #if ENABLE(SAMPLING_FLAGS) |
862 | void setSamplingFlag(int32_t); | |
863 | void clearSamplingFlag(int32_t); | |
9dae56ea | 864 | #endif |
ba379fdc A |
865 | |
866 | #if ENABLE(SAMPLING_COUNTERS) | |
6fe7ccc8 | 867 | void emitCount(AbstractSamplingCounter&, int32_t = 1); |
9dae56ea A |
868 | #endif |
869 | ||
870 | #if ENABLE(OPCODE_SAMPLING) | |
ba379fdc | 871 | void sampleInstruction(Instruction*, bool = false); |
9dae56ea | 872 | #endif |
ba379fdc A |
873 | |
874 | #if ENABLE(CODEBLOCK_SAMPLING) | |
875 | void sampleCodeBlock(CodeBlock*); | |
9dae56ea | 876 | #else |
ba379fdc | 877 | void sampleCodeBlock(CodeBlock*) {} |
9dae56ea A |
878 | #endif |
879 | ||
6fe7ccc8 A |
880 | #if ENABLE(DFG_JIT) |
881 | bool canBeOptimized() { return m_canBeOptimized; } | |
93a37866 A |
882 | bool canBeOptimizedOrInlined() { return m_canBeOptimizedOrInlined; } |
883 | bool shouldEmitProfiling() { return m_shouldEmitProfiling; } | |
6fe7ccc8 A |
884 | #else |
885 | bool canBeOptimized() { return false; } | |
93a37866 | 886 | bool canBeOptimizedOrInlined() { return false; } |
6fe7ccc8 A |
887 | // Enables use of value profiler with tiered compilation turned off, |
888 | // in which case all code gets profiled. | |
93a37866 | 889 | bool shouldEmitProfiling() { return false; } |
6fe7ccc8 A |
890 | #endif |
891 | ||
9dae56ea | 892 | Interpreter* m_interpreter; |
93a37866 | 893 | VM* m_vm; |
9dae56ea A |
894 | CodeBlock* m_codeBlock; |
895 | ||
896 | Vector<CallRecord> m_calls; | |
897 | Vector<Label> m_labels; | |
898 | Vector<PropertyStubCompilationInfo> m_propertyAccessCompilationInfo; | |
93a37866 | 899 | Vector<ByValCompilationInfo> m_byValCompilationInfo; |
9dae56ea A |
900 | Vector<StructureStubCompilationInfo> m_callStructureStubCompilationInfo; |
901 | Vector<JumpTable> m_jmpTable; | |
902 | ||
14957cd0 | 903 | unsigned m_bytecodeOffset; |
9dae56ea A |
904 | Vector<SlowCaseEntry> m_slowCases; |
905 | Vector<SwitchRecord> m_switches; | |
906 | ||
ba379fdc | 907 | unsigned m_propertyAccessInstructionIndex; |
93a37866 | 908 | unsigned m_byValInstructionIndex; |
ba379fdc A |
909 | unsigned m_globalResolveInfoIndex; |
910 | unsigned m_callLinkInfoIndex; | |
911 | ||
912 | #if USE(JSVALUE32_64) | |
913 | unsigned m_jumpTargetIndex; | |
14957cd0 | 914 | unsigned m_mappedBytecodeOffset; |
6fe7ccc8 | 915 | int m_mappedVirtualRegisterIndex; |
ba379fdc A |
916 | RegisterID m_mappedTag; |
917 | RegisterID m_mappedPayload; | |
918 | #else | |
9dae56ea | 919 | int m_lastResultBytecodeRegister; |
f9bf01c6 | 920 | #endif |
14957cd0 | 921 | unsigned m_jumpTargetsPosition; |
f9bf01c6 A |
922 | |
923 | #ifndef NDEBUG | |
924 | #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL | |
925 | Label m_uninterruptedInstructionSequenceBegin; | |
926 | int m_uninterruptedConstantSequenceBegin; | |
927 | #endif | |
ba379fdc | 928 | #endif |
93a37866 A |
929 | OwnPtr<JITDisassembler> m_disassembler; |
930 | RefPtr<Profiler::Compilation> m_compilation; | |
14957cd0 | 931 | WeakRandom m_randomGenerator; |
93a37866 | 932 | static CodeRef stringGetByValStubGenerator(VM*); |
6fe7ccc8 A |
933 | |
934 | #if ENABLE(VALUE_PROFILER) | |
935 | bool m_canBeOptimized; | |
93a37866 A |
936 | bool m_canBeOptimizedOrInlined; |
937 | bool m_shouldEmitProfiling; | |
6fe7ccc8 | 938 | #endif |
ba379fdc | 939 | } JIT_CLASS_ALIGNMENT; |
f9bf01c6 | 940 | |
ba379fdc | 941 | } // namespace JSC |
9dae56ea A |
942 | |
943 | #endif // ENABLE(JIT) | |
944 | ||
945 | #endif // JIT_h |