Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/wasm/jump-table-assembler.h"
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/macro-assembler-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 : namespace wasm {
13 :
14 : // The implementation is compact enough to implement it inline here. If it gets
15 : // much bigger, we might want to split it in a separate file per architecture.
16 : #if V8_TARGET_ARCH_X64
17 17599 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
18 : Address lazy_compile_target) {
19 : // TODO(clemensh): Try more efficient sequences.
20 : // Alternative 1:
21 : // [header]: mov r10, [lazy_compile_target]
22 : // jmp r10
23 : // [slot 0]: push [0]
24 : // jmp [header] // pc-relative --> slot size: 10 bytes
25 : //
26 : // Alternative 2:
27 : // [header]: lea r10, [rip - [header]]
28 : // shr r10, 3 // compute index from offset
29 : // push r10
30 : // mov r10, [lazy_compile_target]
31 : // jmp r10
32 : // [slot 0]: call [header]
33 : // ret // -> slot size: 5 bytes
34 :
35 : // Use a push, because mov to an extended register takes 6 bytes.
36 35198 : pushq(Immediate(func_index)); // max 5 bytes
37 17599 : movq(kScratchRegister, uint64_t{lazy_compile_target}); // max 10 bytes
38 17599 : jmp(kScratchRegister); // 3 bytes
39 :
40 17599 : PatchConstPool(); // force patching entries for partial const pool
41 17599 : }
42 :
43 1790827 : void JumpTableAssembler::EmitJumpSlot(Address target) {
44 1790827 : movq(kScratchRegister, static_cast<uint64_t>(target));
45 1790828 : jmp(kScratchRegister);
46 1790820 : }
47 :
48 1808424 : void JumpTableAssembler::NopBytes(int bytes) {
49 : DCHECK_LE(0, bytes);
50 1808424 : Nop(bytes);
51 1808427 : }
52 :
53 : #elif V8_TARGET_ARCH_IA32
54 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
55 : Address lazy_compile_target) {
56 : mov(kWasmCompileLazyFuncIndexRegister, func_index); // 5 bytes
57 : jmp(lazy_compile_target, RelocInfo::NONE); // 5 bytes
58 : }
59 :
60 : void JumpTableAssembler::EmitJumpSlot(Address target) {
61 : jmp(target, RelocInfo::NONE);
62 : }
63 :
64 : void JumpTableAssembler::NopBytes(int bytes) {
65 : DCHECK_LE(0, bytes);
66 : Nop(bytes);
67 : }
68 :
69 : #elif V8_TARGET_ARCH_ARM
70 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
71 : Address lazy_compile_target) {
72 : // Load function index to a register.
73 : // This generates [movw, movt] on ARMv7 and later, [ldr, constant pool marker,
74 : // constant] on ARMv6.
75 : Move32BitImmediate(kWasmCompileLazyFuncIndexRegister, Operand(func_index));
76 : // EmitJumpSlot emits either [b], [movw, movt, mov] (ARMv7+), or [ldr,
77 : // constant].
78 : // In total, this is <=5 instructions on all architectures.
79 : // TODO(arm): Optimize this for code size; lazy compile is not performance
80 : // critical, as it's only executed once per function.
81 : EmitJumpSlot(lazy_compile_target);
82 : }
83 :
84 : void JumpTableAssembler::EmitJumpSlot(Address target) {
85 : // Note that {Move32BitImmediate} emits [ldr, constant] for the relocation
86 : // mode used below, we need this to allow concurrent patching of this slot.
87 : Move32BitImmediate(pc, Operand(target, RelocInfo::WASM_CALL));
88 : CheckConstPool(true, false); // force emit of const pool
89 : }
90 :
91 : void JumpTableAssembler::NopBytes(int bytes) {
92 : DCHECK_LE(0, bytes);
93 : DCHECK_EQ(0, bytes % kInstrSize);
94 : for (; bytes > 0; bytes -= kInstrSize) {
95 : nop();
96 : }
97 : }
98 :
99 : #elif V8_TARGET_ARCH_ARM64
100 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
101 : Address lazy_compile_target) {
102 : Mov(kWasmCompileLazyFuncIndexRegister.W(), func_index); // max. 2 instr
103 : Jump(lazy_compile_target, RelocInfo::NONE); // 1 instr
104 : }
105 :
106 : void JumpTableAssembler::EmitJumpSlot(Address target) {
107 : // TODO(wasm): Currently this is guaranteed to be a {near_call} and hence is
108 : // patchable concurrently. Once {kMaxWasmCodeMemory} is raised on ARM64, make
109 : // sure concurrent patching is still supported.
110 : Jump(target, RelocInfo::NONE);
111 : }
112 :
113 : void JumpTableAssembler::NopBytes(int bytes) {
114 : DCHECK_LE(0, bytes);
115 : DCHECK_EQ(0, bytes % kInstrSize);
116 : for (; bytes > 0; bytes -= kInstrSize) {
117 : nop();
118 : }
119 : }
120 :
121 : #elif V8_TARGET_ARCH_S390
122 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
123 : Address lazy_compile_target) {
124 : // Load function index to r7. 6 bytes
125 : lgfi(kWasmCompileLazyFuncIndexRegister, Operand(func_index));
126 : // Jump to {lazy_compile_target}. 6 bytes or 12 bytes
127 : mov(r1, Operand(lazy_compile_target));
128 : b(r1); // 2 bytes
129 : }
130 :
131 : void JumpTableAssembler::EmitJumpSlot(Address target) {
132 : mov(r1, Operand(target));
133 : b(r1);
134 : }
135 :
136 : void JumpTableAssembler::NopBytes(int bytes) {
137 : DCHECK_LE(0, bytes);
138 : DCHECK_EQ(0, bytes % 2);
139 : for (; bytes > 0; bytes -= 2) {
140 : nop(0);
141 : }
142 : }
143 :
144 : #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
145 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
146 : Address lazy_compile_target) {
147 : li(kWasmCompileLazyFuncIndexRegister, func_index); // max. 2 instr
148 : // Jump produces max. 4 instructions for 32-bit platform
149 : // and max. 6 instructions for 64-bit platform.
150 : Jump(lazy_compile_target, RelocInfo::NONE);
151 : }
152 :
153 : void JumpTableAssembler::EmitJumpSlot(Address target) {
154 : Jump(target, RelocInfo::NONE);
155 : }
156 :
157 : void JumpTableAssembler::NopBytes(int bytes) {
158 : DCHECK_LE(0, bytes);
159 : DCHECK_EQ(0, bytes % kInstrSize);
160 : for (; bytes > 0; bytes -= kInstrSize) {
161 : nop();
162 : }
163 : }
164 :
165 : #elif V8_TARGET_ARCH_PPC
166 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
167 : Address lazy_compile_target) {
168 : // Load function index to register. max 5 instrs
169 : mov(kWasmCompileLazyFuncIndexRegister, Operand(func_index));
170 : // Jump to {lazy_compile_target}. max 5 instrs
171 : mov(r0, Operand(lazy_compile_target));
172 : mtctr(r0);
173 : bctr();
174 : }
175 :
176 : void JumpTableAssembler::EmitJumpSlot(Address target) {
177 : mov(r0, Operand(target));
178 : mtctr(r0);
179 : bctr();
180 : }
181 :
182 : void JumpTableAssembler::NopBytes(int bytes) {
183 : DCHECK_LE(0, bytes);
184 : DCHECK_EQ(0, bytes % 4);
185 : for (; bytes > 0; bytes -= 4) {
186 : nop(0);
187 : }
188 : }
189 :
190 : #else
191 : void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index,
192 : Address lazy_compile_target) {
193 : UNIMPLEMENTED();
194 : }
195 :
196 : void JumpTableAssembler::EmitJumpSlot(Address target) { UNIMPLEMENTED(); }
197 :
198 : void JumpTableAssembler::NopBytes(int bytes) {
199 : DCHECK_LE(0, bytes);
200 : UNIMPLEMENTED();
201 : }
202 : #endif
203 :
204 : } // namespace wasm
205 : } // namespace internal
206 183867 : } // namespace v8
|