DFG Int52 boxing code may clobber the source without telling anyone
[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->baselineAlternative() : 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) || CPU(ARM64)
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         storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
137     }
138
139     void emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
140     {
141         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
142     }
143
144     void emitGetCallerFrameFromCallFrameHeaderPtr(RegisterID to)
145     {
146         loadPtr(Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()), to);
147     }
148     void emitPutCallerFrameToCallFrameHeader(RegisterID from)
149     {
150         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()));
151     }
152
153     void emitGetReturnPCFromCallFrameHeaderPtr(RegisterID to)
154     {
155         loadPtr(Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()), to);
156     }
157     void emitPutReturnPCToCallFrameHeader(RegisterID from)
158     {
159         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
160     }
161     void emitPutReturnPCToCallFrameHeader(TrustedImmPtr from)
162     {
163         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
164     }
165
166     Jump branchIfNotCell(GPRReg reg)
167     {
168 #if USE(JSVALUE64)
169         return branchTest64(MacroAssembler::NonZero, reg, GPRInfo::tagMaskRegister);
170 #else
171         return branch32(MacroAssembler::NotEqual, reg, TrustedImm32(JSValue::CellTag));
172 #endif
173     }
174     
175     static Address addressForByteOffset(ptrdiff_t byteOffset)
176     {
177         return Address(GPRInfo::callFrameRegister, byteOffset);
178     }
179     static Address addressFor(VirtualRegister virtualRegister, GPRReg baseReg)
180     {
181         ASSERT(virtualRegister.isValid());
182         return Address(baseReg, virtualRegister.offset() * sizeof(Register));
183     }
184     static Address addressFor(VirtualRegister virtualRegister)
185     {
186         ASSERT(virtualRegister.isValid());
187         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register));
188     }
189     static Address addressFor(int operand)
190     {
191         return addressFor(static_cast<VirtualRegister>(operand));
192     }
193
194     static Address tagFor(VirtualRegister virtualRegister)
195     {
196         ASSERT(virtualRegister.isValid());
197         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
198     }
199     static Address tagFor(int operand)
200     {
201         return tagFor(static_cast<VirtualRegister>(operand));
202     }
203
204     static Address payloadFor(VirtualRegister virtualRegister)
205     {
206         ASSERT(virtualRegister.isValid());
207         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
208     }
209     static Address payloadFor(int operand)
210     {
211         return payloadFor(static_cast<VirtualRegister>(operand));
212     }
213
214     Jump branchIfNotObject(GPRReg structureReg)
215     {
216         return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
217     }
218
219     static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg)
220     {
221         if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0)
222             return GPRInfo::regT0;
223
224         if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1)
225             return GPRInfo::regT1;
226
227         if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2)
228             return GPRInfo::regT2;
229
230         if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3)
231             return GPRInfo::regT3;
232
233         return GPRInfo::regT4;
234     }
235
236     // Add a debug call. This call has no effect on JIT code execution state.
237     void debugCall(V_DebugOperation_EPP function, void* argument)
238     {
239         size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
240         ScratchBuffer* scratchBuffer = m_vm->scratchBufferForSize(scratchSize);
241         EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
242
243         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
244 #if USE(JSVALUE64)
245             store64(GPRInfo::toRegister(i), buffer + i);
246 #else
247             store32(GPRInfo::toRegister(i), buffer + i);
248 #endif
249         }
250
251         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
252             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
253             storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
254         }
255
256         // Tell GC mark phase how much of the scratch buffer is active during call.
257         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
258         storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
259
260 #if CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(MIPS) || CPU(SH4)
261         move(TrustedImmPtr(buffer), GPRInfo::argumentGPR2);
262         move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
263         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
264         GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::argumentGPR2);
265 #elif CPU(X86)
266         poke(GPRInfo::callFrameRegister, 0);
267         poke(TrustedImmPtr(argument), 1);
268         poke(TrustedImmPtr(buffer), 2);
269         GPRReg scratch = GPRInfo::regT0;
270 #else
271 #error "JIT not supported on this platform."
272 #endif
273         move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
274         call(scratch);
275
276         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
277         storePtr(TrustedImmPtr(0), GPRInfo::regT0);
278
279         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
280             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
281             loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
282         }
283         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
284 #if USE(JSVALUE64)
285             load64(buffer + i, GPRInfo::toRegister(i));
286 #else
287             load32(buffer + i, GPRInfo::toRegister(i));
288 #endif
289         }
290     }
291
292     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
293 #if !ASSERT_DISABLED
294     void jitAssertIsInt32(GPRReg);
295     void jitAssertIsJSInt32(GPRReg);
296     void jitAssertIsJSNumber(GPRReg);
297     void jitAssertIsJSDouble(GPRReg);
298     void jitAssertIsCell(GPRReg);
299     void jitAssertHasValidCallFrame();
300     void jitAssertIsNull(GPRReg);
301 #else
302     void jitAssertIsInt32(GPRReg) { }
303     void jitAssertIsJSInt32(GPRReg) { }
304     void jitAssertIsJSNumber(GPRReg) { }
305     void jitAssertIsJSDouble(GPRReg) { }
306     void jitAssertIsCell(GPRReg) { }
307     void jitAssertHasValidCallFrame() { }
308     void jitAssertIsNull(GPRReg) { }
309 #endif
310
311     // These methods convert between doubles, and doubles boxed and JSValues.
312 #if USE(JSVALUE64)
313     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
314     {
315         moveDoubleTo64(fpr, gpr);
316         sub64(GPRInfo::tagTypeNumberRegister, gpr);
317         jitAssertIsJSDouble(gpr);
318         return gpr;
319     }
320     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
321     {
322         jitAssertIsJSDouble(gpr);
323         add64(GPRInfo::tagTypeNumberRegister, gpr);
324         move64ToDouble(gpr, fpr);
325         return fpr;
326     }
327     
328     // Here are possible arrangements of source, target, scratch:
329     // - source, target, scratch can all be separate registers.
330     // - source and target can be the same but scratch is separate.
331     // - target and scratch can be the same but source is separate.
332     void boxInt52(GPRReg source, GPRReg target, GPRReg scratch, FPRReg fpScratch)
333     {
334         // Is it an int32?
335         signExtend32ToPtr(source, scratch);
336         Jump isInt32 = branch64(Equal, source, scratch);
337         
338         // Nope, it's not, but regT0 contains the int64 value.
339         convertInt64ToDouble(source, fpScratch);
340         boxDouble(fpScratch, target);
341         Jump done = jump();
342         
343         isInt32.link(this);
344         zeroExtend32ToPtr(source, target);
345         or64(GPRInfo::tagTypeNumberRegister, target);
346         
347         done.link(this);
348     }
349 #endif
350
351 #if USE(JSVALUE32_64)
352     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
353     {
354         moveDoubleToInts(fpr, payloadGPR, tagGPR);
355     }
356     void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
357     {
358         moveIntsToDouble(payloadGPR, tagGPR, fpr, scratchFPR);
359     }
360 #endif
361     
362     enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
363     Jump emitExceptionCheck(ExceptionCheckKind kind = NormalExceptionCheck)
364     {
365 #if USE(JSVALUE64)
366         return branchTest64(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(vm()->addressOfException()));
367 #elif USE(JSVALUE32_64)
368         return branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(reinterpret_cast<char*>(vm()->addressOfException()) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
369 #endif
370     }
371
372 #if ENABLE(SAMPLING_COUNTERS)
373     static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
374     {
375         jit.add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
376     }
377     void emitCount(AbstractSamplingCounter& counter, int32_t increment = 1)
378     {
379         add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
380     }
381 #endif
382
383 #if ENABLE(SAMPLING_FLAGS)
384     void setSamplingFlag(int32_t);
385     void clearSamplingFlag(int32_t flag);
386 #endif
387
388     JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
389     {
390         return codeBlock()->globalObjectFor(codeOrigin);
391     }
392     
393     bool isStrictModeFor(CodeOrigin codeOrigin)
394     {
395         if (!codeOrigin.inlineCallFrame)
396             return codeBlock()->isStrictMode();
397         return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode();
398     }
399     
400     ECMAMode ecmaModeFor(CodeOrigin codeOrigin)
401     {
402         return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode;
403     }
404     
405     ExecutableBase* executableFor(const CodeOrigin& codeOrigin);
406     
407     CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
408     {
409         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock());
410     }
411     
412     CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
413     {
414         if (!inlineCallFrame)
415             return baselineCodeBlock();
416         return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
417     }
418     
419     CodeBlock* baselineCodeBlock()
420     {
421         return m_baselineCodeBlock;
422     }
423     
424     VirtualRegister baselineArgumentsRegisterFor(InlineCallFrame* inlineCallFrame)
425     {
426         if (!inlineCallFrame)
427             return baselineCodeBlock()->argumentsRegister();
428         
429         return VirtualRegister(baselineCodeBlockForInlineCallFrame(
430             inlineCallFrame)->argumentsRegister().offset() + inlineCallFrame->stackOffset);
431     }
432     
433     VirtualRegister baselineArgumentsRegisterFor(const CodeOrigin& codeOrigin)
434     {
435         return baselineArgumentsRegisterFor(codeOrigin.inlineCallFrame);
436     }
437     
438     SharedSymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
439     {
440         return baselineCodeBlockFor(codeOrigin)->symbolTable();
441     }
442
443     int offsetOfLocals(const CodeOrigin& codeOrigin)
444     {
445         if (!codeOrigin.inlineCallFrame)
446             return 0;
447         return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register);
448     }
449
450     int offsetOfArgumentsIncludingThis(InlineCallFrame* inlineCallFrame)
451     {
452         if (!inlineCallFrame)
453             return CallFrame::argumentOffsetIncludingThis(0) * sizeof(Register);
454         if (inlineCallFrame->arguments.size() <= 1)
455             return 0;
456         ValueRecovery recovery = inlineCallFrame->arguments[1];
457         RELEASE_ASSERT(recovery.technique() == DisplacedInJSStack);
458         return (recovery.virtualRegister().offset() - 1) * sizeof(Register);
459     }
460     
461     int offsetOfArgumentsIncludingThis(const CodeOrigin& codeOrigin)
462     {
463         return offsetOfArgumentsIncludingThis(codeOrigin.inlineCallFrame);
464     }
465
466     void writeBarrier(GPRReg owner, GPRReg scratch1, GPRReg scratch2, WriteBarrierUseKind useKind)
467     {
468         UNUSED_PARAM(owner);
469         UNUSED_PARAM(scratch1);
470         UNUSED_PARAM(scratch2);
471         UNUSED_PARAM(useKind);
472         ASSERT(owner != scratch1);
473         ASSERT(owner != scratch2);
474         ASSERT(scratch1 != scratch2);
475         
476 #if ENABLE(WRITE_BARRIER_PROFILING)
477         emitCount(WriteBarrierCounters::jitCounterFor(useKind));
478 #endif
479     }
480
481     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
482     
483 protected:
484     VM* m_vm;
485     CodeBlock* m_codeBlock;
486     CodeBlock* m_baselineCodeBlock;
487
488     HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset>> m_decodedCodeMaps;
489 };
490
491 } // namespace JSC
492
493 #endif // ENABLE(JIT)
494
495 #endif // AssemblyHelpers_h
496