1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QV4PLATFORMASSEMBLER_P_H
41#define QV4PLATFORMASSEMBLER_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <private/qv4engine_p.h>
55#include <private/qv4global_p.h>
56#include <private/qv4function_p.h>
57#include <QHash>
58#include <wtf/Vector.h>
59#include <assembler/MacroAssembler.h>
60
61#if QT_CONFIG(qml_jit)
62
63QT_BEGIN_NAMESPACE
64
65namespace QV4 {
66namespace JIT {
67
68#if defined(Q_PROCESSOR_X86_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
69#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN)
70
71class PlatformAssembler_X86_64_SysV : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
72{
73public:
74 static constexpr int NativeStackAlignment = 16;
75
76 static const RegisterID NoRegister = RegisterID(-1);
77
78 static const RegisterID ReturnValueRegister = RegisterID::eax;
79 static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
80 static const RegisterID AccumulatorRegister = RegisterID::eax;
81 static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
82 static const RegisterID ScratchRegister = RegisterID::r10;
83 static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg5Reg, so do not use while setting up a call!
84 static const RegisterID JSStackFrameRegister = RegisterID::r12;
85 static const RegisterID CppStackFrameRegister = RegisterID::r13;
86 static const RegisterID EngineRegister = RegisterID::r14;
87 static const RegisterID StackPointerRegister = RegisterID::esp;
88 static const RegisterID FramePointerRegister = RegisterID::ebp;
89 static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
90 static const FPRegisterID FPScratchRegister2 = FPRegisterID::xmm2;
91
92 static const RegisterID Arg0Reg = RegisterID::edi;
93 static const RegisterID Arg1Reg = RegisterID::esi;
94 static const RegisterID Arg2Reg = RegisterID::edx;
95 static const RegisterID Arg3Reg = RegisterID::ecx;
96 static const RegisterID Arg4Reg = RegisterID::r8;
97 static const RegisterID Arg5Reg = RegisterID::r9;
98 static const RegisterID Arg6Reg = NoRegister;
99 static const RegisterID Arg7Reg = NoRegister;
100 static const int ArgInRegCount = 6;
101
102 void popValue()
103 {
104 addPtr(imm: TrustedImmPtr(sizeof(ReturnedValue)), dest: StackPointerRegister);
105 }
106
107 void generatePlatformFunctionEntry()
108 {
109 push(src: FramePointerRegister);
110 move(src: StackPointerRegister, dest: FramePointerRegister);
111 move(imm: TrustedImmPtr(nullptr), dest: AccumulatorRegister); push(src: AccumulatorRegister); // exceptionHandler
112 push(src: JSStackFrameRegister);
113 push(src: CppStackFrameRegister);
114 push(src: EngineRegister);
115 move(src: Arg0Reg, dest: CppStackFrameRegister);
116 move(src: Arg1Reg, dest: EngineRegister);
117 }
118
119 void generatePlatformFunctionExit(bool tailCall = false)
120 {
121 pop(dest: EngineRegister);
122 pop(dest: CppStackFrameRegister);
123 pop(dest: JSStackFrameRegister);
124 pop(); // exceptionHandler
125 pop(dest: FramePointerRegister);
126 if (!tailCall)
127 ret();
128 }
129
130 void callAbsolute(const void *funcPtr)
131 {
132 move(imm: TrustedImmPtr(funcPtr), dest: ScratchRegister);
133 call(target: ScratchRegister);
134 }
135
136 void jumpAbsolute(const void *funcPtr)
137 {
138 move(imm: TrustedImmPtr(funcPtr), dest: ScratchRegister);
139 jump(target: ScratchRegister);
140 }
141
142 void pushAligned(RegisterID reg)
143 {
144 subPtr(imm: TrustedImm32(PointerSize), dest: StackPointerRegister);
145 push(src: reg);
146 }
147
148 void popAligned(RegisterID reg)
149 {
150 pop(dest: reg);
151 addPtr(imm: TrustedImm32(PointerSize), srcDest: StackPointerRegister);
152 }
153};
154
155typedef PlatformAssembler_X86_64_SysV PlatformAssemblerBase;
156
157#endif
158#if defined(Q_OS_WIN)
159
160class PlatformAssembler_Win64 : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
161{
162public:
163 static const RegisterID NoRegister = RegisterID(-1);
164
165 static const RegisterID ReturnValueRegister = RegisterID::eax;
166 static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
167 static const RegisterID AccumulatorRegister = RegisterID::eax;
168 static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
169 static const RegisterID ScratchRegister = RegisterID::r10;
170 static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg3Reg, so do not use while setting up a call!
171 static const RegisterID JSStackFrameRegister = RegisterID::r12;
172 static const RegisterID CppStackFrameRegister = RegisterID::r13;
173 static const RegisterID EngineRegister = RegisterID::r14;
174 static const RegisterID StackPointerRegister = RegisterID::esp;
175 static const RegisterID FramePointerRegister = RegisterID::ebp;
176 static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
177
178 static const RegisterID Arg0Reg = RegisterID::ecx;
179 static const RegisterID Arg1Reg = RegisterID::edx;
180 static const RegisterID Arg2Reg = RegisterID::r8;
181 static const RegisterID Arg3Reg = RegisterID::r9;
182 static const RegisterID Arg4Reg = NoRegister;
183 static const RegisterID Arg5Reg = NoRegister;
184 static const RegisterID Arg6Reg = NoRegister;
185 static const RegisterID Arg7Reg = NoRegister;
186 static const int ArgInRegCount = 4;
187
188 void popValue()
189 {
190 addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
191 }
192
193 void generatePlatformFunctionEntry()
194 {
195 push(FramePointerRegister);
196 move(StackPointerRegister, FramePointerRegister);
197 move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
198 push(JSStackFrameRegister);
199 push(CppStackFrameRegister);
200 push(EngineRegister);
201 move(Arg0Reg, CppStackFrameRegister);
202 move(Arg1Reg, EngineRegister);
203 }
204
205 void generatePlatformFunctionExit(bool tailCall = false)
206 {
207 pop(EngineRegister);
208 pop(CppStackFrameRegister);
209 pop(JSStackFrameRegister);
210 pop(); // exceptionHandler
211 pop(FramePointerRegister);
212 if (!tailCall)
213 ret();
214 }
215
216 void callAbsolute(const void *funcPtr)
217 {
218 move(TrustedImmPtr(funcPtr), ScratchRegister);
219 subPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
220 call(ScratchRegister);
221 addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
222 }
223
224 void jumpAbsolute(const void *funcPtr)
225 {
226 move(TrustedImmPtr(funcPtr), ScratchRegister);
227 jump(ScratchRegister);
228 }
229
230 void pushAligned(RegisterID reg)
231 {
232 subPtr(TrustedImm32(PointerSize), StackPointerRegister);
233 push(reg);
234 }
235
236 void popAligned(RegisterID reg)
237 {
238 pop(reg);
239 addPtr(TrustedImm32(PointerSize), StackPointerRegister);
240 }
241};
242
243typedef PlatformAssembler_Win64 PlatformAssemblerBase;
244
245#endif
246#endif
247
248#if (defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_X86_64)) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
249
250class PlatformAssembler_X86_All : public JSC::MacroAssembler<JSC::MacroAssemblerX86>
251{
252public:
253 static const RegisterID NoRegister = RegisterID(-1);
254
255 static const RegisterID ReturnValueRegisterValue = RegisterID::eax;
256 static const RegisterID ReturnValueRegisterTag = RegisterID::edx;
257 static const RegisterID ScratchRegister = RegisterID::ecx;
258 static const RegisterID AccumulatorRegisterValue = ReturnValueRegisterValue;
259 static const RegisterID AccumulatorRegisterTag = ReturnValueRegisterTag;
260 static const RegisterID JSStackFrameRegister = RegisterID::ebx;
261 static const RegisterID CppStackFrameRegister = RegisterID::esi;
262 static const RegisterID EngineRegister = RegisterID::edi;
263 static const RegisterID StackPointerRegister = RegisterID::esp;
264 static const RegisterID FramePointerRegister = RegisterID::ebp;
265 static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
266
267 static const RegisterID Arg0Reg = NoRegister;
268 static const RegisterID Arg1Reg = NoRegister;
269 static const RegisterID Arg2Reg = NoRegister;
270 static const RegisterID Arg3Reg = NoRegister;
271 static const RegisterID Arg4Reg = NoRegister;
272 static const RegisterID Arg5Reg = NoRegister;
273 static const RegisterID Arg6Reg = NoRegister;
274 static const RegisterID Arg7Reg = NoRegister;
275 static const int ArgInRegCount = 0;
276
277 void popValue()
278 {
279 addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
280 }
281
282 void generatePlatformFunctionEntry()
283 {
284 push(RegisterID::ebp);
285 move(RegisterID::esp, RegisterID::ebp);
286 move(TrustedImmPtr(nullptr), AccumulatorRegisterValue); push(AccumulatorRegisterValue); // exceptionHandler
287 push(JSStackFrameRegister);
288 push(CppStackFrameRegister);
289 push(EngineRegister);
290 // Ensure the stack is 16-byte aligned in order for compiler generated aligned SSE2
291 // instructions to be able to target the stack.
292 subPtr(TrustedImm32(8), StackPointerRegister);
293 loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister);
294 loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
295 }
296
297 void generatePlatformFunctionExit(bool tailCall = false)
298 {
299 addPtr(TrustedImm32(8), StackPointerRegister);
300 pop(EngineRegister);
301 pop(CppStackFrameRegister);
302 pop(JSStackFrameRegister);
303 pop(); // exceptionHandler
304 pop(RegisterID::ebp);
305 if (!tailCall)
306 ret();
307 }
308
309 void callAbsolute(const void *funcPtr)
310 {
311 move(TrustedImmPtr(funcPtr), ScratchRegister);
312 call(ScratchRegister);
313 }
314
315 void jumpAbsolute(const void *funcPtr)
316 {
317 move(TrustedImmPtr(funcPtr), ScratchRegister);
318 jump(ScratchRegister);
319 }
320
321 void pushAligned(RegisterID reg)
322 {
323 subPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
324 push(reg);
325 }
326
327 void popAligned(RegisterID reg)
328 {
329 pop(reg);
330 addPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
331 }
332};
333
334typedef PlatformAssembler_X86_All PlatformAssemblerBase;
335
336#endif
337
338#if defined(Q_PROCESSOR_ARM_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
339
340class PlatformAssembler_ARM64 : public JSC::MacroAssembler<JSC::MacroAssemblerARM64>
341{
342public:
343 static const RegisterID NoRegister = RegisterID(-1);
344
345 static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
346 static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
347 static const RegisterID AccumulatorRegister = JSC::ARM64Registers::x9;
348 static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
349 static const RegisterID ScratchRegister = JSC::ARM64Registers::x10;
350 static const RegisterID ScratchRegister2 = JSC::ARM64Registers::x7; // Note: overlaps with Arg7Reg, so do not use while setting up a call!
351 static const RegisterID JSStackFrameRegister = JSC::ARM64Registers::x19;
352 static const RegisterID CppStackFrameRegister = JSC::ARM64Registers::x20;
353 static const RegisterID EngineRegister = JSC::ARM64Registers::x21;
354 static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
355 static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
356 static const FPRegisterID FPScratchRegister = JSC::ARM64Registers::q1;
357
358 static const RegisterID Arg0Reg = JSC::ARM64Registers::x0;
359 static const RegisterID Arg1Reg = JSC::ARM64Registers::x1;
360 static const RegisterID Arg2Reg = JSC::ARM64Registers::x2;
361 static const RegisterID Arg3Reg = JSC::ARM64Registers::x3;
362 static const RegisterID Arg4Reg = JSC::ARM64Registers::x4;
363 static const RegisterID Arg5Reg = JSC::ARM64Registers::x5;
364 static const RegisterID Arg6Reg = JSC::ARM64Registers::x6;
365 static const RegisterID Arg7Reg = JSC::ARM64Registers::x7;
366 static const int ArgInRegCount = 8;
367
368 void push(RegisterID src)
369 {
370 pushToSave(src);
371 }
372
373 void pop(RegisterID dest)
374 {
375 popToRestore(dest);
376 }
377
378 void pop()
379 {
380 add64(TrustedImm32(16), stackPointerRegister);
381 }
382
383 void popValue()
384 {
385 pop();
386 }
387
388 void generatePlatformFunctionEntry()
389 {
390 pushPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
391 move(RegisterID::sp, RegisterID::fp);
392 move(TrustedImmPtr(nullptr), AccumulatorRegister); // exceptionHandler
393 pushPair(JSStackFrameRegister, AccumulatorRegister);
394 pushPair(EngineRegister, CppStackFrameRegister);
395 move(Arg0Reg, CppStackFrameRegister);
396 move(Arg1Reg, EngineRegister);
397 }
398
399 void generatePlatformFunctionExit(bool tailCall = false)
400 {
401 if (!tailCall) // do not overwrite arg0 (used in the tail call)
402 move(AccumulatorRegister, ReturnValueRegister);
403 popPair(EngineRegister, CppStackFrameRegister);
404 popPair(JSStackFrameRegister, AccumulatorRegister);
405 popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
406 if (!tailCall)
407 ret();
408 }
409
410 void callAbsolute(const void *funcPtr)
411 {
412 move(TrustedImmPtr(funcPtr), ScratchRegister);
413 call(ScratchRegister);
414 }
415
416 void jumpAbsolute(const void *funcPtr)
417 {
418 move(TrustedImmPtr(funcPtr), ScratchRegister);
419 jump(ScratchRegister);
420 }
421
422 void pushAligned(RegisterID reg)
423 {
424 pushToSave(reg);
425 }
426
427 void popAligned(RegisterID reg)
428 {
429 popToRestore(reg);
430 }
431};
432
433typedef PlatformAssembler_ARM64 PlatformAssemblerBase;
434
435#endif
436
437#if defined(Q_PROCESSOR_ARM_32) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
438
439class PlatformAssembler_ARM32 : public JSC::MacroAssembler<JSC::MacroAssemblerARMv7>
440{
441public:
442 static const RegisterID NoRegister = RegisterID(-1);
443
444 static const RegisterID ReturnValueRegisterValue = JSC::ARMRegisters::r0;
445 static const RegisterID ReturnValueRegisterTag = JSC::ARMRegisters::r1;
446 static const RegisterID ScratchRegister = JSC::ARMRegisters::r2;
447 static const RegisterID AccumulatorRegisterValue = JSC::ARMRegisters::r4;
448 static const RegisterID AccumulatorRegisterTag = JSC::ARMRegisters::r5;
449 // r6 is used by MacroAssemblerARMv7
450 static const RegisterID JSStackFrameRegister = JSC::ARMRegisters::r8;
451 static const RegisterID CppStackFrameRegister = JSC::ARMRegisters::r10;
452#if CPU(ARM_THUMB2)
453 static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
454 static const RegisterID EngineRegister = JSC::ARMRegisters::r11;
455#else // Thumbs down
456 static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
457 static const RegisterID EngineRegister = JSC::ARMRegisters::r7;
458#endif
459 static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
460 static const FPRegisterID FPScratchRegister = JSC::ARMRegisters::d1;
461
462 static const RegisterID Arg0Reg = JSC::ARMRegisters::r0;
463 static const RegisterID Arg1Reg = JSC::ARMRegisters::r1;
464 static const RegisterID Arg2Reg = JSC::ARMRegisters::r2;
465 static const RegisterID Arg3Reg = JSC::ARMRegisters::r3;
466 static const RegisterID Arg4Reg = NoRegister;
467 static const RegisterID Arg5Reg = NoRegister;
468 static const RegisterID Arg6Reg = NoRegister;
469 static const RegisterID Arg7Reg = NoRegister;
470 static const int ArgInRegCount = 4;
471
472 void popValue()
473 {
474 addPtr(TrustedImm32(sizeof(ReturnedValue)), StackPointerRegister);
475 }
476
477 void generatePlatformFunctionEntry()
478 {
479 push(JSC::ARMRegisters::lr);
480 push(FramePointerRegister);
481 move(StackPointerRegister, FramePointerRegister);
482 push(TrustedImm32(0)); // exceptionHandler
483 push(AccumulatorRegisterValue);
484 push(AccumulatorRegisterTag);
485 push(addressTempRegister);
486 push(JSStackFrameRegister);
487 push(CppStackFrameRegister);
488 push(EngineRegister);
489 subPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
490 move(Arg0Reg, CppStackFrameRegister);
491 move(Arg1Reg, EngineRegister);
492 }
493
494 void generatePlatformFunctionExit(bool tailCall = false)
495 {
496 if (!tailCall) { // do not overwrite arg0 and arg1 (used in the tail call)
497 move(AccumulatorRegisterValue, ReturnValueRegisterValue);
498 move(AccumulatorRegisterTag, ReturnValueRegisterTag);
499 }
500 addPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
501 pop(EngineRegister);
502 pop(CppStackFrameRegister);
503 pop(JSStackFrameRegister);
504 pop(addressTempRegister);
505 pop(AccumulatorRegisterTag);
506 pop(AccumulatorRegisterValue);
507 pop(); // exceptionHandler
508 pop(FramePointerRegister);
509 pop(JSC::ARMRegisters::lr);
510 if (!tailCall)
511 ret();
512 }
513
514 void callAbsolute(const void *funcPtr)
515 {
516 move(TrustedImmPtr(funcPtr), dataTempRegister);
517 call(dataTempRegister);
518 }
519
520 void jumpAbsolute(const void *funcPtr)
521 {
522 move(TrustedImmPtr(funcPtr), dataTempRegister);
523 jump(dataTempRegister);
524 }
525
526 void pushAligned(RegisterID reg)
527 {
528 subPtr(TrustedImm32(PointerSize), StackPointerRegister);
529 push(reg);
530 }
531
532 void popAligned(RegisterID reg)
533 {
534 pop(reg);
535 addPtr(TrustedImm32(PointerSize), StackPointerRegister);
536 }
537};
538
539typedef PlatformAssembler_ARM32 PlatformAssemblerBase;
540#endif
541
542class PlatformAssemblerCommon : public JIT::PlatformAssemblerBase
543{
544public:
545 PlatformAssemblerCommon(const Value *constantTable)
546 : constantTable(constantTable)
547 {}
548
549 virtual ~PlatformAssemblerCommon();
550
551 Address exceptionHandlerAddress() const
552 {
553 return Address(FramePointerRegister, -1 * PointerSize);
554 }
555
556 Address contextAddress() const
557 {
558 return Address(JSStackFrameRegister, offsetof(CallData, context));
559 }
560
561 RegisterID registerForArg(int arg) const
562 {
563 Q_ASSERT(arg >= 0);
564 Q_ASSERT(arg < ArgInRegCount);
565 switch (arg) {
566 case 0: return Arg0Reg;
567 case 1: return Arg1Reg;
568 case 2: return Arg2Reg;
569 case 3: return Arg3Reg;
570 case 4: return Arg4Reg;
571 case 5: return Arg5Reg;
572 case 6: return Arg6Reg;
573 case 7: return Arg7Reg;
574 default:
575 Q_UNIMPLEMENTED();
576 Q_UNREACHABLE();
577 }
578 }
579
580 Address loadFunctionPtr(RegisterID target)
581 {
582 Address addr(CppStackFrameRegister, offsetof(CppStackFrame, v4Function));
583 loadPtr(address: addr, dest: target);
584 return Address(target);
585 }
586
587 Address loadCompilationUnitPtr(RegisterID target)
588 {
589 Address addr = loadFunctionPtr(target);
590 addr.offset = offsetof(QV4::FunctionData, compilationUnit);
591 loadPtr(address: addr, dest: target);
592 return Address(target);
593 }
594
595 Address loadConstAddress(int constIndex, RegisterID baseReg = ScratchRegister)
596 {
597 Address addr = loadCompilationUnitPtr(target: baseReg);
598 addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, constants);
599 loadPtr(address: addr, dest: baseReg);
600 addr.offset = constIndex * int(sizeof(QV4::Value));
601 return addr;
602 }
603
604 Address loadStringAddress(int stringId)
605 {
606 Address addr = loadCompilationUnitPtr(target: ScratchRegister);
607 addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, runtimeStrings);
608 loadPtr(address: addr, dest: ScratchRegister);
609 return Address(ScratchRegister, stringId * PointerSize);
610 }
611
612 void passAsArg(RegisterID src, int arg)
613 {
614 move(src, dest: registerForArg(arg));
615 }
616
617 void generateCatchTrampoline(std::function<void()> loadUndefined)
618 {
619 for (Jump j : catchyJumps)
620 j.link(masm: this);
621
622 // We don't need to check for isInterrupted here because if that is set,
623 // then the first checkException() in any exception handler will find another "exception"
624 // and jump out of the exception handler.
625 loadPtr(address: exceptionHandlerAddress(), dest: ScratchRegister);
626 Jump exitFunction = branchPtr(cond: Equal, left: ScratchRegister, right: TrustedImmPtr(0));
627 loadUndefined();
628 jump(target: ScratchRegister);
629 exitFunction.link(masm: this);
630
631 if (functionExit.isSet())
632 jump(target: functionExit);
633 else
634 generateFunctionExit();
635 }
636
637 void checkException()
638 {
639 // This actually reads 4 bytes, starting at hasException.
640 // Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
641 addCatchyJump(
642 j: branch32(cond: NotEqual,
643 left: Address(EngineRegister, offsetof(EngineBase, hasException)),
644 right: TrustedImm32(0)));
645 }
646
647 void addCatchyJump(Jump j)
648 {
649 Q_ASSERT(j.isSet());
650 catchyJumps.push_back(x: j);
651 }
652
653 void generateFunctionEntry()
654 {
655 generatePlatformFunctionEntry();
656 loadPtr(address: Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), dest: JSStackFrameRegister);
657 allocateStackSpace();
658 }
659
660 virtual void allocateStackSpace() {}
661
662 void generateFunctionExit()
663 {
664 if (functionExit.isSet()) {
665 jump(target: functionExit);
666 return;
667 }
668
669 functionExit = label();
670 freeStackSpace();
671 generatePlatformFunctionExit();
672 }
673
674 virtual void freeStackSpace() {}
675
676 void addLabelForOffset(int offset)
677 {
678 if (!labelForOffset.contains(akey: offset))
679 labelForOffset.insert(akey: offset, avalue: label());
680 }
681
682 void addJumpToOffset(const Jump &jump, int offset)
683 {
684 jumpsToLink.push_back(x: { .jump: jump, .offset: offset });
685 }
686
687 void addEHTarget(const DataLabelPtr &label, int offset)
688 {
689 ehTargets.push_back(x: { .label: label, .offset: offset });
690 }
691
692 void link(Function *function, const char *jitKind);
693
694 Value constant(int idx) const
695 { return constantTable[idx]; }
696
697 // stuff for runtime calls
698 void prepareCallWithArgCount(int argc);
699 void storeInstructionPointer(int instructionOffset);
700 void passAccumulatorAsArg(int arg);
701 void pushAccumulatorAsArg(int arg);
702 void passFunctionAsArg(int arg);
703 void passEngineAsArg(int arg);
704 void passJSSlotAsArg(int reg, int arg);
705 void passAddressAsArg(Address addr, int arg);
706 void passCppFrameAsArg(int arg);
707 void passInt32AsArg(int value, int arg);
708 void passPointerAsArg(void *ptr, int arg);
709 void callRuntime(const void *funcPtr, const char *functionName = nullptr);
710 void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
711 void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
712 void setTailCallArg(RegisterID src, int arg);
713 Address jsAlloca(int slotCount);
714 void storeInt32AsValue(int srcInt, Address destAddr);
715
716private:
717 void passAccumulatorAsArg_internal(int arg, bool doPush);
718 static Address argStackAddress(int arg);
719
720private:
721 const Value* constantTable;
722 struct JumpTarget { JSC::MacroAssemblerBase::Jump jump; int offset; };
723 std::vector<JumpTarget> jumpsToLink;
724 struct ExceptionHanlderTarget { JSC::MacroAssemblerBase::DataLabelPtr label; int offset; };
725 std::vector<ExceptionHanlderTarget> ehTargets;
726 QHash<int, JSC::MacroAssemblerBase::Label> labelForOffset;
727 QHash<const void *, const char *> functions;
728 std::vector<Jump> catchyJumps;
729 Label functionExit;
730
731#ifndef QT_NO_DEBUG
732 enum { NoCall = -1 };
733 int remainingArgcForCall = NoCall;
734#endif
735 int argcOnStackForCall = 0;
736};
737
738} // JIT namespace
739} // QV4 namespace
740
741QT_END_NAMESPACE
742
743#endif // QT_CONFIG(qml_jit)
744
745#endif // QV4PLATFORMASSEMBLER_P_H
746

source code of qtdeclarative/src/qml/jit/qv4assemblercommon_p.h