1/*
2 * Copyright (C) 2008, 2014 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 MacroAssemblerX86_h
27#define MacroAssemblerX86_h
28
29#if ENABLE(ASSEMBLER) && CPU(X86)
30
31#include "MacroAssemblerX86Common.h"
32
33#if USE(MASM_PROBE)
34#include <wtf/StdLibExtras.h>
35#endif
36
37namespace JSC {
38
39class MacroAssemblerX86 : public MacroAssemblerX86Common {
40public:
41    static const Scale ScalePtr = TimesFour;
42
43    using MacroAssemblerX86Common::add32;
44    using MacroAssemblerX86Common::and32;
45    using MacroAssemblerX86Common::branchAdd32;
46    using MacroAssemblerX86Common::branchSub32;
47    using MacroAssemblerX86Common::sub32;
48    using MacroAssemblerX86Common::or32;
49    using MacroAssemblerX86Common::load32;
50    using MacroAssemblerX86Common::load8;
51    using MacroAssemblerX86Common::store32;
52    using MacroAssemblerX86Common::store8;
53    using MacroAssemblerX86Common::branch32;
54    using MacroAssemblerX86Common::call;
55    using MacroAssemblerX86Common::jump;
56    using MacroAssemblerX86Common::addDouble;
57    using MacroAssemblerX86Common::loadDouble;
58    using MacroAssemblerX86Common::storeDouble;
59    using MacroAssemblerX86Common::convertInt32ToDouble;
60    using MacroAssemblerX86Common::branch8;
61    using MacroAssemblerX86Common::branchTest8;
62
63    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
64    {
65        m_assembler.leal_mr(imm.m_value, src, dest);
66    }
67
68    void add32(TrustedImm32 imm, AbsoluteAddress address)
69    {
70        m_assembler.addl_im(imm.m_value, address.m_ptr);
71    }
72
73    void add32(AbsoluteAddress address, RegisterID dest)
74    {
75        m_assembler.addl_mr(address.m_ptr, dest);
76    }
77
78    void add64(TrustedImm32 imm, AbsoluteAddress address)
79    {
80        m_assembler.addl_im(imm.m_value, address.m_ptr);
81        m_assembler.adcl_im(imm.m_value >> 31, reinterpret_cast<const char*>(address.m_ptr) + sizeof(int32_t));
82    }
83
84    void and32(TrustedImm32 imm, AbsoluteAddress address)
85    {
86        m_assembler.andl_im(imm.m_value, address.m_ptr);
87    }
88
89    void or32(TrustedImm32 imm, AbsoluteAddress address)
90    {
91        m_assembler.orl_im(imm.m_value, address.m_ptr);
92    }
93
94    void or32(RegisterID reg, AbsoluteAddress address)
95    {
96        m_assembler.orl_rm(reg, address.m_ptr);
97    }
98
99    void sub32(TrustedImm32 imm, AbsoluteAddress address)
100    {
101        m_assembler.subl_im(imm.m_value, address.m_ptr);
102    }
103
104    void load32(const void* address, RegisterID dest)
105    {
106        m_assembler.movl_mr(address, dest);
107    }
108
109    void load8(const void* address, RegisterID dest)
110    {
111        m_assembler.movzbl_mr(address, dest);
112    }
113
114    void abortWithReason(AbortReason reason)
115    {
116        move(TrustedImm32(reason), X86Registers::eax);
117        breakpoint();
118    }
119
120    void abortWithReason(AbortReason reason, intptr_t misc)
121    {
122        move(TrustedImm32(misc), X86Registers::edx);
123        abortWithReason(reason);
124    }
125
126    ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
127    {
128        ConvertibleLoadLabel result = ConvertibleLoadLabel(this);
129        m_assembler.movl_mr(address.offset, address.base, dest);
130        return result;
131    }
132
133    void addDouble(AbsoluteAddress address, FPRegisterID dest)
134    {
135        m_assembler.addsd_mr(address.m_ptr, dest);
136    }
137
138    void storeDouble(FPRegisterID src, TrustedImmPtr address)
139    {
140        ASSERT(isSSE2Present());
141        ASSERT(address.m_value);
142        m_assembler.movsd_rm(src, address.m_value);
143    }
144
145    void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
146    {
147        m_assembler.cvtsi2sd_mr(src.m_ptr, dest);
148    }
149
150    void store32(TrustedImm32 imm, void* address)
151    {
152        m_assembler.movl_i32m(imm.m_value, address);
153    }
154
155    void store32(RegisterID src, void* address)
156    {
157        m_assembler.movl_rm(src, address);
158    }
159
160    void store8(RegisterID src, void* address)
161    {
162        m_assembler.movb_rm(src, address);
163    }
164
165    void store8(TrustedImm32 imm, void* address)
166    {
167        ASSERT(-128 <= imm.m_value && imm.m_value < 128);
168        m_assembler.movb_i8m(imm.m_value, address);
169    }
170
171    // Possibly clobbers src.
172    // FIXME: Don't do that.
173    // https://bugs.webkit.org/show_bug.cgi?id=131690
174    void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
175    {
176        movePackedToInt32(src, dest1);
177        rshiftPacked(TrustedImm32(32), src);
178        movePackedToInt32(src, dest2);
179    }
180
181    void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
182    {
183        moveInt32ToPacked(src1, dest);
184        moveInt32ToPacked(src2, scratch);
185        lshiftPacked(TrustedImm32(32), scratch);
186        orPacked(scratch, dest);
187    }
188
189    Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
190    {
191        m_assembler.addl_im(imm.m_value, dest.m_ptr);
192        return Jump(m_assembler.jCC(x86Condition(cond)));
193    }
194
195    Jump branchSub32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
196    {
197        m_assembler.subl_im(imm.m_value, dest.m_ptr);
198        return Jump(m_assembler.jCC(x86Condition(cond)));
199    }
200
201    Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
202    {
203        m_assembler.cmpl_rm(right, left.m_ptr);
204        return Jump(m_assembler.jCC(x86Condition(cond)));
205    }
206
207    Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
208    {
209        m_assembler.cmpl_im(right.m_value, left.m_ptr);
210        return Jump(m_assembler.jCC(x86Condition(cond)));
211    }
212
213    Call call()
214    {
215        return Call(m_assembler.call(), Call::Linkable);
216    }
217
218    // Address is a memory location containing the address to jump to
219    void jump(AbsoluteAddress address)
220    {
221        m_assembler.jmp_m(address.m_ptr);
222    }
223
224    Call tailRecursiveCall()
225    {
226        return Call::fromTailJump(jump());
227    }
228
229    Call makeTailRecursiveCall(Jump oldJump)
230    {
231        return Call::fromTailJump(oldJump);
232    }
233
234
235    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
236    {
237        padBeforePatch();
238        m_assembler.movl_i32r(initialValue.asIntptr(), dest);
239        return DataLabelPtr(this);
240    }
241
242    Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
243    {
244        m_assembler.cmpb_im(right.m_value, left.m_ptr);
245        return Jump(m_assembler.jCC(x86Condition(cond)));
246    }
247
248    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
249    {
250        ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
251        if (mask.m_value == -1)
252            m_assembler.cmpb_im(0, address.m_ptr);
253        else
254            m_assembler.testb_im(mask.m_value, address.m_ptr);
255        return Jump(m_assembler.jCC(x86Condition(cond)));
256    }
257
258    Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
259    {
260        padBeforePatch();
261        m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left);
262        dataLabel = DataLabelPtr(this);
263        return Jump(m_assembler.jCC(x86Condition(cond)));
264    }
265
266    Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
267    {
268        padBeforePatch();
269        m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base);
270        dataLabel = DataLabelPtr(this);
271        return Jump(m_assembler.jCC(x86Condition(cond)));
272    }
273
274    Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
275    {
276        padBeforePatch();
277        m_assembler.cmpl_im_force32(initialRightValue.m_value, left.offset, left.base);
278        dataLabel = DataLabel32(this);
279        return Jump(m_assembler.jCC(x86Condition(cond)));
280    }
281
282    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
283    {
284        padBeforePatch();
285        m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
286        return DataLabelPtr(this);
287    }
288
289    static bool supportsFloatingPoint() { return isSSE2Present(); }
290    // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
291    static bool supportsFloatingPointTruncate() { return isSSE2Present(); }
292    static bool supportsFloatingPointSqrt() { return isSSE2Present(); }
293    static bool supportsFloatingPointAbs() { return isSSE2Present(); }
294
295    static FunctionPtr readCallTarget(CodeLocationCall call)
296    {
297        intptr_t offset = reinterpret_cast<int32_t*>(call.dataLocation())[-1];
298        return FunctionPtr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(call.dataLocation()) + offset));
299    }
300
301    static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
302    static bool canJumpReplacePatchableBranch32WithPatch() { return true; }
303
304    static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
305    {
306        const int opcodeBytes = 1;
307        const int modRMBytes = 1;
308        const int immediateBytes = 4;
309        const int totalBytes = opcodeBytes + modRMBytes + immediateBytes;
310        ASSERT(totalBytes >= maxJumpReplacementSize());
311        return label.labelAtOffset(-totalBytes);
312    }
313
314    static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label)
315    {
316        const int opcodeBytes = 1;
317        const int modRMBytes = 1;
318        const int offsetBytes = 0;
319        const int immediateBytes = 4;
320        const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes;
321        ASSERT(totalBytes >= maxJumpReplacementSize());
322        return label.labelAtOffset(-totalBytes);
323    }
324
325    static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32 label)
326    {
327        const int opcodeBytes = 1;
328        const int modRMBytes = 1;
329        const int offsetBytes = 0;
330        const int immediateBytes = 4;
331        const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes;
332        ASSERT(totalBytes >= maxJumpReplacementSize());
333        return label.labelAtOffset(-totalBytes);
334    }
335
336    static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue)
337    {
338        X86Assembler::revertJumpTo_cmpl_ir_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), reg);
339    }
340
341    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address address, void* initialValue)
342    {
343        ASSERT(!address.offset);
344        X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), 0, address.base);
345    }
346
347    static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel instructionStart, Address address, int32_t initialValue)
348    {
349        ASSERT(!address.offset);
350        X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), initialValue, 0, address.base);
351    }
352
353#if USE(MASM_PROBE)
354    // For details about probe(), see comment in MacroAssemblerX86_64.h.
355    void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
356#endif // USE(MASM_PROBE)
357
358private:
359    friend class LinkBuffer;
360    friend class RepatchBuffer;
361
362    static void linkCall(void* code, Call call, FunctionPtr function)
363    {
364        X86Assembler::linkCall(code, call.m_label, function.value());
365    }
366
367    static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
368    {
369        X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
370    }
371
372    static void repatchCall(CodeLocationCall call, FunctionPtr destination)
373    {
374        X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
375    }
376
377#if USE(MASM_PROBE)
378    inline TrustedImm32 trustedImm32FromPtr(void* ptr)
379    {
380        return TrustedImm32(TrustedImmPtr(ptr));
381    }
382
383    inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
384    {
385        return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
386    }
387
388    inline TrustedImm32 trustedImm32FromPtr(void (*function)())
389    {
390        return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
391    }
392#endif
393};
394
395#if USE(MASM_PROBE)
396
397extern "C" void ctiMasmProbeTrampoline();
398
399// For details on "What code is emitted for the probe?" and "What values are in
400// the saved registers?", see comment for MacroAssemblerX86::probe() in
401// MacroAssemblerX86_64.h.
402
403inline void MacroAssemblerX86::probe(MacroAssemblerX86::ProbeFunction function, void* arg1, void* arg2)
404{
405    push(RegisterID::esp);
406    push(RegisterID::eax);
407    push(trustedImm32FromPtr(arg2));
408    push(trustedImm32FromPtr(arg1));
409    push(trustedImm32FromPtr(function));
410
411    move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::eax);
412    call(RegisterID::eax);
413}
414#endif // USE(MASM_PROBE)
415
416} // namespace JSC
417
418#endif // ENABLE(ASSEMBLER)
419
420#endif // MacroAssemblerX86_h
421