Unreviewed, rolling out r156474.
[WebKit-https.git] / Source / JavaScriptCore / jit / AssemblyHelpers.h
1 /*
2  * Copyright (C) 2011, 2013 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 #ifndef AssemblyHelpers_h
27 #define AssemblyHelpers_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(JIT)
32
33 #include "CodeBlock.h"
34 #include "FPRInfo.h"
35 #include "GPRInfo.h"
36 #include "JITCode.h"
37 #include "MacroAssembler.h"
38 #include "VM.h"
39
40 namespace JSC {
41
42 typedef void (*V_DebugOperation_EPP)(ExecState*, void*, void*);
43
44 class AssemblyHelpers : public MacroAssembler {
45 public:
46     AssemblyHelpers(VM* vm, CodeBlock* codeBlock)
47         : m_vm(vm)
48         , m_codeBlock(codeBlock)
49         , m_baselineCodeBlock(codeBlock ? codeBlock->baselineVersion() : 0)
50     {
51         if (m_codeBlock) {
52             ASSERT(m_baselineCodeBlock);
53             ASSERT(!m_baselineCodeBlock->alternative());
54             ASSERT(m_baselineCodeBlock->jitType() == JITCode::None || JITCode::isBaselineCode(m_baselineCodeBlock->jitType()));
55         }
56     }
57     
58     CodeBlock* codeBlock() { return m_codeBlock; }
59     VM* vm() { return m_vm; }
60     AssemblerType_T& assembler() { return m_assembler; }
61     
62 #if CPU(X86_64) || CPU(X86)
63     void preserveReturnAddressAfterCall(GPRReg reg)
64     {
65         pop(reg);
66     }
67
68     void restoreReturnAddressBeforeReturn(GPRReg reg)
69     {
70         push(reg);
71     }
72
73     void restoreReturnAddressBeforeReturn(Address address)
74     {
75         push(address);
76     }
77 #endif // CPU(X86_64) || CPU(X86)
78
79 #if CPU(ARM)
80     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
81     {
82         move(linkRegister, reg);
83     }
84
85     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
86     {
87         move(reg, linkRegister);
88     }
89
90     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
91     {
92         loadPtr(address, linkRegister);
93     }
94 #endif
95
96 #if CPU(MIPS)
97     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
98     {
99         move(returnAddressRegister, reg);
100     }
101
102     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
103     {
104         move(reg, returnAddressRegister);
105     }
106
107     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
108     {
109         loadPtr(address, returnAddressRegister);
110     }
111 #endif
112
113 #if CPU(SH4)
114     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
115     {
116         m_assembler.stspr(reg);
117     }
118
119     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
120     {
121         m_assembler.ldspr(reg);
122     }
123
124     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
125     {
126         loadPtrLinkReg(address);
127     }
128 #endif
129
130     void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, GPRReg to)
131     {
132         loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
133     }
134     void emitPutToCallFrameHeader(GPRReg from, JSStack::CallFrameHeaderEntry entry)
135     {
136 #if USE(JSVALUE64)
137         store64(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
138 #else
139         store32(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
140 #endif
141     }
142
143     void emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
144     {
145         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
146     }
147
148     Jump branchIfNotCell(GPRReg reg)
149     {
150 #if USE(JSVALUE64)
151         return branchTest64(MacroAssembler::NonZero, reg, GPRInfo::tagMaskRegister);
152 #else
153         return branch32(MacroAssembler::NotEqual, reg, TrustedImm32(JSValue::CellTag));
154 #endif
155     }
156     
157     static Address addressFor(VirtualRegister virtualRegister)
158     {
159         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
160     }
161     static Address addressFor(int operand)
162     {
163         return addressFor(static_cast<VirtualRegister>(operand));
164     }
165
166     static Address tagFor(VirtualRegister virtualRegister)
167     {
168         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
169     }
170     static Address tagFor(int operand)
171     {
172         return tagFor(static_cast<VirtualRegister>(operand));
173     }
174
175     static Address payloadFor(VirtualRegister virtualRegister)
176     {
177         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
178     }
179     static Address payloadFor(int operand)
180     {
181         return payloadFor(static_cast<VirtualRegister>(operand));
182     }
183
184     Jump branchIfNotObject(GPRReg structureReg)
185     {
186         return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
187     }
188
189     static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg)
190     {
191         if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0)
192             return GPRInfo::regT0;
193
194         if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1)
195             return GPRInfo::regT1;
196
197         if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2)
198             return GPRInfo::regT2;
199
200         if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3)
201             return GPRInfo::regT3;
202
203         return GPRInfo::regT4;
204     }
205
206     // Add a debug call. This call has no effect on JIT code execution state.
207     void debugCall(V_DebugOperation_EPP function, void* argument)
208     {
209         size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
210         ScratchBuffer* scratchBuffer = m_vm->scratchBufferForSize(scratchSize);
211         EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
212
213         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
214 #if USE(JSVALUE64)
215             store64(GPRInfo::toRegister(i), buffer + i);
216 #else
217             store32(GPRInfo::toRegister(i), buffer + i);
218 #endif
219         }
220
221         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
222             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
223             storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
224         }
225
226         // Tell GC mark phase how much of the scratch buffer is active during call.
227         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
228         storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
229
230 #if CPU(X86_64) || CPU(ARM) || CPU(MIPS) || CPU(SH4)
231         move(TrustedImmPtr(buffer), GPRInfo::argumentGPR2);
232         move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
233         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
234         GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::argumentGPR2);
235 #elif CPU(X86)
236         poke(GPRInfo::callFrameRegister, 0);
237         poke(TrustedImmPtr(argument), 1);
238         poke(TrustedImmPtr(buffer), 2);
239         GPRReg scratch = GPRInfo::regT0;
240 #else
241 #error "JIT not supported on this platform."
242 #endif
243         move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
244         call(scratch);
245
246         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
247         storePtr(TrustedImmPtr(0), GPRInfo::regT0);
248
249         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
250             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
251             loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
252         }
253         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
254 #if USE(JSVALUE64)
255             load64(buffer + i, GPRInfo::toRegister(i));
256 #else
257             load32(buffer + i, GPRInfo::toRegister(i));
258 #endif
259         }
260     }
261
262     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
263 #if !ASSERT_DISABLED
264     void jitAssertIsInt32(GPRReg);
265     void jitAssertIsJSInt32(GPRReg);
266     void jitAssertIsJSNumber(GPRReg);
267     void jitAssertIsJSDouble(GPRReg);
268     void jitAssertIsCell(GPRReg);
269     void jitAssertHasValidCallFrame();
270 #else
271     void jitAssertIsInt32(GPRReg) { }
272     void jitAssertIsJSInt32(GPRReg) { }
273     void jitAssertIsJSNumber(GPRReg) { }
274     void jitAssertIsJSDouble(GPRReg) { }
275     void jitAssertIsCell(GPRReg) { }
276     void jitAssertHasValidCallFrame() { }
277 #endif
278
279     // These methods convert between doubles, and doubles boxed and JSValues.
280 #if USE(JSVALUE64)
281     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
282     {
283         moveDoubleTo64(fpr, gpr);
284         sub64(GPRInfo::tagTypeNumberRegister, gpr);
285         jitAssertIsJSDouble(gpr);
286         return gpr;
287     }
288     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
289     {
290         jitAssertIsJSDouble(gpr);
291         add64(GPRInfo::tagTypeNumberRegister, gpr);
292         move64ToDouble(gpr, fpr);
293         return fpr;
294     }
295     
296     void boxInt52(GPRReg source, GPRReg target, GPRReg scratch, FPRReg fpScratch)
297     {
298         // Is it an int32?
299         signExtend32ToPtr(source, scratch);
300         Jump isInt32 = branch64(Equal, source, scratch);
301         
302         // Nope, it's not, but regT0 contains the int64 value.
303         convertInt64ToDouble(source, fpScratch);
304         boxDouble(fpScratch, target);
305         Jump done = jump();
306         
307         isInt32.link(this);
308         zeroExtend32ToPtr(source, target);
309         or64(GPRInfo::tagTypeNumberRegister, target);
310         
311         done.link(this);
312     }
313 #endif
314
315 #if USE(JSVALUE32_64)
316     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
317     {
318         moveDoubleToInts(fpr, payloadGPR, tagGPR);
319     }
320     void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
321     {
322         moveIntsToDouble(payloadGPR, tagGPR, fpr, scratchFPR);
323     }
324 #endif
325     
326     enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
327     Jump emitExceptionCheck(ExceptionCheckKind kind = NormalExceptionCheck)
328     {
329 #if USE(JSVALUE64)
330         return branchTest64(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(vm()->addressOfException()));
331 #elif USE(JSVALUE32_64)
332         return branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(reinterpret_cast<char*>(vm()->addressOfException()) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
333 #endif
334     }
335
336 #if ENABLE(SAMPLING_COUNTERS)
337     static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
338     {
339         jit.add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
340     }
341     void emitCount(AbstractSamplingCounter& counter, int32_t increment = 1)
342     {
343         add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
344     }
345 #endif
346
347 #if ENABLE(SAMPLING_FLAGS)
348     void setSamplingFlag(int32_t);
349     void clearSamplingFlag(int32_t flag);
350 #endif
351
352     JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
353     {
354         return codeBlock()->globalObjectFor(codeOrigin);
355     }
356     
357     bool strictModeFor(CodeOrigin codeOrigin)
358     {
359         if (!codeOrigin.inlineCallFrame)
360             return codeBlock()->isStrictMode();
361         return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode();
362     }
363     
364     ExecutableBase* executableFor(const CodeOrigin& codeOrigin);
365     
366     CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
367     {
368         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock());
369     }
370     
371     CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
372     {
373         if (!inlineCallFrame)
374             return baselineCodeBlock();
375         return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
376     }
377     
378     CodeBlock* baselineCodeBlock()
379     {
380         return m_baselineCodeBlock;
381     }
382     
383     int argumentsRegisterFor(InlineCallFrame* inlineCallFrame)
384     {
385         if (!inlineCallFrame)
386             return codeBlock()->argumentsRegister();
387         
388         return baselineCodeBlockForInlineCallFrame(
389             inlineCallFrame)->argumentsRegister() + inlineCallFrame->stackOffset;
390     }
391     
392     int argumentsRegisterFor(const CodeOrigin& codeOrigin)
393     {
394         return argumentsRegisterFor(codeOrigin.inlineCallFrame);
395     }
396     
397     SharedSymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
398     {
399         return baselineCodeBlockFor(codeOrigin)->symbolTable();
400     }
401
402     int offsetOfLocals(const CodeOrigin& codeOrigin)
403     {
404         if (!codeOrigin.inlineCallFrame)
405             return 0;
406         return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register);
407     }
408
409     int offsetOfArgumentsIncludingThis(const CodeOrigin& codeOrigin)
410     {
411         if (!codeOrigin.inlineCallFrame)
412             return CallFrame::argumentOffsetIncludingThis(0) * sizeof(Register);
413         return (codeOrigin.inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
414     }
415
416     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
417     
418 protected:
419     VM* m_vm;
420     CodeBlock* m_codeBlock;
421     CodeBlock* m_baselineCodeBlock;
422
423     HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset> > m_decodedCodeMaps;
424 };
425
426 } // namespace JSC
427
428 #endif // ENABLE(JIT)
429
430 #endif // AssemblyHelpers_h
431