]>
Commit | Line | Data |
---|---|---|
ba379fdc | 1 | /* |
81345200 | 2 | * Copyright (C) 2009, 2012, 2013 Apple Inc. All rights reserved. |
4e4e5a6f | 3 | * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> |
ba379fdc A |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
18 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
21 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
22 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | */ | |
26 | ||
27 | #include "config.h" | |
ba379fdc | 28 | #if ENABLE(JIT) |
14957cd0 | 29 | #include "JIT.h" |
ba379fdc | 30 | |
14957cd0 | 31 | #include "Arguments.h" |
93a37866 | 32 | #include "CopiedSpaceInlines.h" |
81345200 | 33 | #include "Debugger.h" |
6fe7ccc8 | 34 | #include "Heap.h" |
93a37866 | 35 | #include "JITInlines.h" |
ba379fdc A |
36 | #include "JSArray.h" |
37 | #include "JSCell.h" | |
38 | #include "JSFunction.h" | |
f9bf01c6 | 39 | #include "JSPropertyNameIterator.h" |
81345200 A |
40 | #include "MaxFrameExtentForSlowPathCall.h" |
41 | #include "SlowPathCall.h" | |
42 | #include "VirtualRegister.h" | |
ba379fdc A |
43 | |
44 | namespace JSC { | |
45 | ||
14957cd0 | 46 | #if USE(JSVALUE64) |
ba379fdc | 47 | |
93a37866 | 48 | JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction) |
ba379fdc | 49 | { |
93a37866 | 50 | return vm->getCTIStub(nativeCallGenerator); |
ba379fdc A |
51 | } |
52 | ||
53 | void JIT::emit_op_mov(Instruction* currentInstruction) | |
54 | { | |
55 | int dst = currentInstruction[1].u.operand; | |
56 | int src = currentInstruction[2].u.operand; | |
57 | ||
81345200 A |
58 | emitGetVirtualRegister(src, regT0); |
59 | emitPutVirtualRegister(dst); | |
60 | } | |
61 | ||
62 | void JIT::emit_op_captured_mov(Instruction* currentInstruction) | |
63 | { | |
64 | int dst = currentInstruction[1].u.operand; | |
65 | int src = currentInstruction[2].u.operand; | |
66 | ||
67 | emitGetVirtualRegister(src, regT0); | |
68 | emitNotifyWrite(regT0, regT1, currentInstruction[3].u.watchpointSet); | |
69 | emitPutVirtualRegister(dst); | |
ba379fdc A |
70 | } |
71 | ||
72 | void JIT::emit_op_end(Instruction* currentInstruction) | |
73 | { | |
81345200 A |
74 | RELEASE_ASSERT(returnValueGPR != callFrameRegister); |
75 | emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueGPR); | |
76 | emitFunctionEpilogue(); | |
ba379fdc A |
77 | ret(); |
78 | } | |
79 | ||
80 | void JIT::emit_op_jmp(Instruction* currentInstruction) | |
81 | { | |
82 | unsigned target = currentInstruction[1].u.operand; | |
f9bf01c6 | 83 | addJump(jump(), target); |
ba379fdc A |
84 | } |
85 | ||
6fe7ccc8 | 86 | void JIT::emit_op_new_object(Instruction* currentInstruction) |
ba379fdc | 87 | { |
93a37866 | 88 | Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure(); |
81345200 | 89 | size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); |
93a37866 A |
90 | MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize); |
91 | ||
92 | RegisterID resultReg = regT0; | |
93 | RegisterID allocatorReg = regT1; | |
94 | RegisterID scratchReg = regT2; | |
95 | ||
96 | move(TrustedImmPtr(allocator), allocatorReg); | |
97 | emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg); | |
6fe7ccc8 | 98 | emitPutVirtualRegister(currentInstruction[1].u.operand); |
ba379fdc A |
99 | } |
100 | ||
6fe7ccc8 | 101 | void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
ba379fdc | 102 | { |
6fe7ccc8 | 103 | linkSlowCase(iter); |
81345200 A |
104 | int dst = currentInstruction[1].u.operand; |
105 | Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure(); | |
106 | callOperation(operationNewObject, structure); | |
107 | emitStoreCell(dst, returnValueGPR); | |
ba379fdc A |
108 | } |
109 | ||
14957cd0 A |
110 | void JIT::emit_op_check_has_instance(Instruction* currentInstruction) |
111 | { | |
81345200 | 112 | int baseVal = currentInstruction[3].u.operand; |
14957cd0 A |
113 | |
114 | emitGetVirtualRegister(baseVal, regT0); | |
115 | ||
116 | // Check that baseVal is a cell. | |
117 | emitJumpSlowCaseIfNotJSCell(regT0, baseVal); | |
118 | ||
119 | // Check that baseVal 'ImplementsHasInstance'. | |
81345200 | 120 | addSlowCase(branchTest8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); |
14957cd0 A |
121 | } |
122 | ||
ba379fdc A |
123 | void JIT::emit_op_instanceof(Instruction* currentInstruction) |
124 | { | |
81345200 A |
125 | int dst = currentInstruction[1].u.operand; |
126 | int value = currentInstruction[2].u.operand; | |
127 | int proto = currentInstruction[3].u.operand; | |
f9bf01c6 | 128 | |
ba379fdc A |
129 | // Load the operands (baseVal, proto, and value respectively) into registers. |
130 | // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. | |
f9bf01c6 | 131 | emitGetVirtualRegister(value, regT2); |
f9bf01c6 | 132 | emitGetVirtualRegister(proto, regT1); |
ba379fdc | 133 | |
14957cd0 | 134 | // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. |
f9bf01c6 | 135 | emitJumpSlowCaseIfNotJSCell(regT2, value); |
f9bf01c6 | 136 | emitJumpSlowCaseIfNotJSCell(regT1, proto); |
ba379fdc | 137 | |
14957cd0 | 138 | // Check that prototype is an object |
81345200 | 139 | addSlowCase(emitJumpIfCellNotObject(regT1)); |
14957cd0 | 140 | |
ba379fdc A |
141 | // Optimistically load the result true, and start looping. |
142 | // Initially, regT1 still contains proto and regT2 still contains value. | |
143 | // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. | |
93a37866 | 144 | move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0); |
ba379fdc A |
145 | Label loop(this); |
146 | ||
147 | // Load the prototype of the object in regT2. If this is equal to regT1 - WIN! | |
148 | // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. | |
81345200 | 149 | emitLoadStructure(regT2, regT2, regT3); |
93a37866 | 150 | load64(Address(regT2, Structure::prototypeOffset()), regT2); |
ba379fdc | 151 | Jump isInstance = branchPtr(Equal, regT2, regT1); |
f9bf01c6 | 152 | emitJumpIfJSCell(regT2).linkTo(loop, this); |
ba379fdc A |
153 | |
154 | // We get here either by dropping out of the loop, or if value was not an Object. Result is false. | |
93a37866 | 155 | move(TrustedImm64(JSValue::encode(jsBoolean(false))), regT0); |
ba379fdc A |
156 | |
157 | // isInstance jumps right down to here, to skip setting the result to false (it has already set true). | |
158 | isInstance.link(this); | |
f9bf01c6 | 159 | emitPutVirtualRegister(dst); |
ba379fdc A |
160 | } |
161 | ||
6fe7ccc8 | 162 | void JIT::emit_op_is_undefined(Instruction* currentInstruction) |
ba379fdc | 163 | { |
81345200 A |
164 | int dst = currentInstruction[1].u.operand; |
165 | int value = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
166 | |
167 | emitGetVirtualRegister(value, regT0); | |
168 | Jump isCell = emitJumpIfJSCell(regT0); | |
169 | ||
93a37866 | 170 | compare64(Equal, regT0, TrustedImm32(ValueUndefined), regT0); |
6fe7ccc8 A |
171 | Jump done = jump(); |
172 | ||
173 | isCell.link(this); | |
81345200 | 174 | Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); |
93a37866 A |
175 | move(TrustedImm32(0), regT0); |
176 | Jump notMasqueradesAsUndefined = jump(); | |
177 | ||
178 | isMasqueradesAsUndefined.link(this); | |
81345200 | 179 | emitLoadStructure(regT0, regT1, regT2); |
93a37866 A |
180 | move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); |
181 | loadPtr(Address(regT1, Structure::globalObjectOffset()), regT1); | |
182 | comparePtr(Equal, regT0, regT1, regT0); | |
183 | ||
184 | notMasqueradesAsUndefined.link(this); | |
6fe7ccc8 A |
185 | done.link(this); |
186 | emitTagAsBoolImmediate(regT0); | |
187 | emitPutVirtualRegister(dst); | |
ba379fdc A |
188 | } |
189 | ||
6fe7ccc8 | 190 | void JIT::emit_op_is_boolean(Instruction* currentInstruction) |
ba379fdc | 191 | { |
81345200 A |
192 | int dst = currentInstruction[1].u.operand; |
193 | int value = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
194 | |
195 | emitGetVirtualRegister(value, regT0); | |
93a37866 A |
196 | xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0); |
197 | test64(Zero, regT0, TrustedImm32(static_cast<int32_t>(~1)), regT0); | |
6fe7ccc8 A |
198 | emitTagAsBoolImmediate(regT0); |
199 | emitPutVirtualRegister(dst); | |
ba379fdc A |
200 | } |
201 | ||
6fe7ccc8 | 202 | void JIT::emit_op_is_number(Instruction* currentInstruction) |
ba379fdc | 203 | { |
81345200 A |
204 | int dst = currentInstruction[1].u.operand; |
205 | int value = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
206 | |
207 | emitGetVirtualRegister(value, regT0); | |
93a37866 | 208 | test64(NonZero, regT0, tagTypeNumberRegister, regT0); |
6fe7ccc8 A |
209 | emitTagAsBoolImmediate(regT0); |
210 | emitPutVirtualRegister(dst); | |
ba379fdc A |
211 | } |
212 | ||
6fe7ccc8 | 213 | void JIT::emit_op_is_string(Instruction* currentInstruction) |
ba379fdc | 214 | { |
81345200 A |
215 | int dst = currentInstruction[1].u.operand; |
216 | int value = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
217 | |
218 | emitGetVirtualRegister(value, regT0); | |
219 | Jump isNotCell = emitJumpIfNotJSCell(regT0); | |
220 | ||
81345200 | 221 | compare8(Equal, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType), regT0); |
6fe7ccc8 A |
222 | emitTagAsBoolImmediate(regT0); |
223 | Jump done = jump(); | |
224 | ||
225 | isNotCell.link(this); | |
226 | move(TrustedImm32(ValueFalse), regT0); | |
227 | ||
228 | done.link(this); | |
229 | emitPutVirtualRegister(dst); | |
ba379fdc A |
230 | } |
231 | ||
ba379fdc A |
232 | void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) |
233 | { | |
93a37866 A |
234 | int activation = currentInstruction[1].u.operand; |
235 | Jump activationNotCreated = branchTest64(Zero, addressFor(activation)); | |
81345200 A |
236 | emitGetVirtualRegister(activation, regT0); |
237 | callOperation(operationTearOffActivation, regT0); | |
93a37866 | 238 | activationNotCreated.link(this); |
ba379fdc A |
239 | } |
240 | ||
14957cd0 | 241 | void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction) |
ba379fdc | 242 | { |
93a37866 A |
243 | int arguments = currentInstruction[1].u.operand; |
244 | int activation = currentInstruction[2].u.operand; | |
14957cd0 | 245 | |
81345200 A |
246 | Jump argsNotCreated = branchTest64(Zero, Address(callFrameRegister, sizeof(Register) * (unmodifiedArgumentsRegister(VirtualRegister(arguments)).offset()))); |
247 | emitGetVirtualRegister(unmodifiedArgumentsRegister(VirtualRegister(arguments)).offset(), regT0); | |
248 | emitGetVirtualRegister(activation, regT1); | |
249 | callOperation(operationTearOffArguments, regT0, regT1); | |
14957cd0 | 250 | argsNotCreated.link(this); |
ba379fdc A |
251 | } |
252 | ||
253 | void JIT::emit_op_ret(Instruction* currentInstruction) | |
254 | { | |
ba379fdc | 255 | ASSERT(callFrameRegister != regT1); |
81345200 A |
256 | ASSERT(regT1 != returnValueGPR); |
257 | ASSERT(returnValueGPR != callFrameRegister); | |
ba379fdc A |
258 | |
259 | // Return the result in %eax. | |
81345200 | 260 | emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueGPR); |
ba379fdc | 261 | |
81345200 A |
262 | checkStackPointerAlignment(); |
263 | emitFunctionEpilogue(); | |
ba379fdc A |
264 | ret(); |
265 | } | |
266 | ||
14957cd0 | 267 | void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction) |
ba379fdc | 268 | { |
14957cd0 | 269 | ASSERT(callFrameRegister != regT1); |
81345200 A |
270 | ASSERT(regT1 != returnValueGPR); |
271 | ASSERT(returnValueGPR != callFrameRegister); | |
14957cd0 A |
272 | |
273 | // Return the result in %eax. | |
81345200 A |
274 | emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueGPR); |
275 | Jump notJSCell = emitJumpIfNotJSCell(returnValueGPR); | |
276 | Jump notObject = emitJumpIfCellNotObject(returnValueGPR); | |
14957cd0 A |
277 | |
278 | // Return. | |
81345200 | 279 | emitFunctionEpilogue(); |
14957cd0 A |
280 | ret(); |
281 | ||
282 | // Return 'this' in %eax. | |
283 | notJSCell.link(this); | |
284 | notObject.link(this); | |
81345200 | 285 | emitGetVirtualRegister(currentInstruction[2].u.operand, returnValueGPR); |
14957cd0 A |
286 | |
287 | // Return. | |
81345200 | 288 | emitFunctionEpilogue(); |
14957cd0 | 289 | ret(); |
ba379fdc A |
290 | } |
291 | ||
ba379fdc A |
292 | void JIT::emit_op_to_primitive(Instruction* currentInstruction) |
293 | { | |
294 | int dst = currentInstruction[1].u.operand; | |
295 | int src = currentInstruction[2].u.operand; | |
296 | ||
297 | emitGetVirtualRegister(src, regT0); | |
298 | ||
299 | Jump isImm = emitJumpIfNotJSCell(regT0); | |
81345200 A |
300 | addSlowCase(branchStructure(NotEqual, |
301 | Address(regT0, JSCell::structureIDOffset()), | |
302 | m_vm->stringStructure.get())); | |
ba379fdc A |
303 | isImm.link(this); |
304 | ||
305 | if (dst != src) | |
306 | emitPutVirtualRegister(dst); | |
307 | ||
308 | } | |
309 | ||
310 | void JIT::emit_op_strcat(Instruction* currentInstruction) | |
311 | { | |
81345200 A |
312 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_strcat); |
313 | slowPathCall.call(); | |
ba379fdc A |
314 | } |
315 | ||
ba379fdc A |
316 | void JIT::emit_op_not(Instruction* currentInstruction) |
317 | { | |
318 | emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); | |
14957cd0 A |
319 | |
320 | // Invert against JSValue(false); if the value was tagged as a boolean, then all bits will be | |
321 | // clear other than the low bit (which will be 0 or 1 for false or true inputs respectively). | |
322 | // Then invert against JSValue(true), which will add the tag back in, and flip the low bit. | |
93a37866 | 323 | xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0); |
14957cd0 | 324 | addSlowCase(branchTestPtr(NonZero, regT0, TrustedImm32(static_cast<int32_t>(~1)))); |
93a37866 | 325 | xor64(TrustedImm32(static_cast<int32_t>(ValueTrue)), regT0); |
14957cd0 | 326 | |
ba379fdc A |
327 | emitPutVirtualRegister(currentInstruction[1].u.operand); |
328 | } | |
329 | ||
330 | void JIT::emit_op_jfalse(Instruction* currentInstruction) | |
331 | { | |
332 | unsigned target = currentInstruction[2].u.operand; | |
333 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); | |
334 | ||
93a37866 | 335 | addJump(branch64(Equal, regT0, TrustedImm64(JSValue::encode(jsNumber(0)))), target); |
ba379fdc A |
336 | Jump isNonZero = emitJumpIfImmediateInteger(regT0); |
337 | ||
93a37866 A |
338 | addJump(branch64(Equal, regT0, TrustedImm64(JSValue::encode(jsBoolean(false)))), target); |
339 | addSlowCase(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(jsBoolean(true))))); | |
ba379fdc A |
340 | |
341 | isNonZero.link(this); | |
4e4e5a6f A |
342 | } |
343 | ||
ba379fdc A |
344 | void JIT::emit_op_jeq_null(Instruction* currentInstruction) |
345 | { | |
81345200 | 346 | int src = currentInstruction[1].u.operand; |
ba379fdc A |
347 | unsigned target = currentInstruction[2].u.operand; |
348 | ||
349 | emitGetVirtualRegister(src, regT0); | |
350 | Jump isImmediate = emitJumpIfNotJSCell(regT0); | |
351 | ||
352 | // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. | |
81345200 A |
353 | Jump isNotMasqueradesAsUndefined = branchTest8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); |
354 | emitLoadStructure(regT0, regT2, regT1); | |
93a37866 A |
355 | move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); |
356 | addJump(branchPtr(Equal, Address(regT2, Structure::globalObjectOffset()), regT0), target); | |
357 | Jump masqueradesGlobalObjectIsForeign = jump(); | |
ba379fdc A |
358 | |
359 | // Now handle the immediate cases - undefined & null | |
360 | isImmediate.link(this); | |
93a37866 A |
361 | and64(TrustedImm32(~TagBitUndefined), regT0); |
362 | addJump(branch64(Equal, regT0, TrustedImm64(JSValue::encode(jsNull()))), target); | |
ba379fdc | 363 | |
93a37866 A |
364 | isNotMasqueradesAsUndefined.link(this); |
365 | masqueradesGlobalObjectIsForeign.link(this); | |
ba379fdc A |
366 | }; |
367 | void JIT::emit_op_jneq_null(Instruction* currentInstruction) | |
368 | { | |
81345200 | 369 | int src = currentInstruction[1].u.operand; |
ba379fdc A |
370 | unsigned target = currentInstruction[2].u.operand; |
371 | ||
372 | emitGetVirtualRegister(src, regT0); | |
373 | Jump isImmediate = emitJumpIfNotJSCell(regT0); | |
374 | ||
375 | // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. | |
81345200 A |
376 | addJump(branchTest8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target); |
377 | emitLoadStructure(regT0, regT2, regT1); | |
93a37866 A |
378 | move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); |
379 | addJump(branchPtr(NotEqual, Address(regT2, Structure::globalObjectOffset()), regT0), target); | |
ba379fdc A |
380 | Jump wasNotImmediate = jump(); |
381 | ||
382 | // Now handle the immediate cases - undefined & null | |
383 | isImmediate.link(this); | |
93a37866 A |
384 | and64(TrustedImm32(~TagBitUndefined), regT0); |
385 | addJump(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(jsNull()))), target); | |
ba379fdc A |
386 | |
387 | wasNotImmediate.link(this); | |
ba379fdc A |
388 | } |
389 | ||
390 | void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) | |
391 | { | |
81345200 | 392 | int src = currentInstruction[1].u.operand; |
93a37866 | 393 | Special::Pointer ptr = currentInstruction[2].u.specialPointer; |
ba379fdc A |
394 | unsigned target = currentInstruction[3].u.operand; |
395 | ||
396 | emitGetVirtualRegister(src, regT0); | |
93a37866 | 397 | addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr))), target); |
ba379fdc A |
398 | } |
399 | ||
ba379fdc A |
400 | void JIT::emit_op_eq(Instruction* currentInstruction) |
401 | { | |
402 | emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); | |
403 | emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); | |
14957cd0 | 404 | compare32(Equal, regT1, regT0, regT0); |
ba379fdc A |
405 | emitTagAsBoolImmediate(regT0); |
406 | emitPutVirtualRegister(currentInstruction[1].u.operand); | |
407 | } | |
408 | ||
ba379fdc A |
409 | void JIT::emit_op_jtrue(Instruction* currentInstruction) |
410 | { | |
411 | unsigned target = currentInstruction[2].u.operand; | |
412 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); | |
413 | ||
93a37866 | 414 | Jump isZero = branch64(Equal, regT0, TrustedImm64(JSValue::encode(jsNumber(0)))); |
f9bf01c6 | 415 | addJump(emitJumpIfImmediateInteger(regT0), target); |
ba379fdc | 416 | |
93a37866 A |
417 | addJump(branch64(Equal, regT0, TrustedImm64(JSValue::encode(jsBoolean(true)))), target); |
418 | addSlowCase(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(jsBoolean(false))))); | |
ba379fdc A |
419 | |
420 | isZero.link(this); | |
ba379fdc A |
421 | } |
422 | ||
423 | void JIT::emit_op_neq(Instruction* currentInstruction) | |
424 | { | |
425 | emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); | |
426 | emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); | |
14957cd0 | 427 | compare32(NotEqual, regT1, regT0, regT0); |
ba379fdc A |
428 | emitTagAsBoolImmediate(regT0); |
429 | ||
430 | emitPutVirtualRegister(currentInstruction[1].u.operand); | |
431 | ||
432 | } | |
433 | ||
434 | void JIT::emit_op_bitxor(Instruction* currentInstruction) | |
435 | { | |
436 | emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); | |
437 | emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); | |
93a37866 | 438 | xor64(regT1, regT0); |
ba379fdc A |
439 | emitFastArithReTagImmediate(regT0, regT0); |
440 | emitPutVirtualRegister(currentInstruction[1].u.operand); | |
441 | } | |
442 | ||
ba379fdc A |
443 | void JIT::emit_op_bitor(Instruction* currentInstruction) |
444 | { | |
445 | emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); | |
446 | emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); | |
93a37866 | 447 | or64(regT1, regT0); |
ba379fdc A |
448 | emitPutVirtualRegister(currentInstruction[1].u.operand); |
449 | } | |
450 | ||
451 | void JIT::emit_op_throw(Instruction* currentInstruction) | |
452 | { | |
81345200 A |
453 | ASSERT(regT0 == returnValueGPR); |
454 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); | |
455 | callOperationNoExceptionCheck(operationThrow, regT0); | |
456 | jumpToExceptionHandler(); | |
ba379fdc A |
457 | } |
458 | ||
f9bf01c6 A |
459 | void JIT::emit_op_get_pnames(Instruction* currentInstruction) |
460 | { | |
461 | int dst = currentInstruction[1].u.operand; | |
462 | int base = currentInstruction[2].u.operand; | |
463 | int i = currentInstruction[3].u.operand; | |
464 | int size = currentInstruction[4].u.operand; | |
465 | int breakTarget = currentInstruction[5].u.operand; | |
466 | ||
467 | JumpList isNotObject; | |
468 | ||
469 | emitGetVirtualRegister(base, regT0); | |
470 | if (!m_codeBlock->isKnownNotImmediate(base)) | |
471 | isNotObject.append(emitJumpIfNotJSCell(regT0)); | |
81345200 A |
472 | if (base != m_codeBlock->thisRegister().offset() || m_codeBlock->isStrictMode()) |
473 | isNotObject.append(emitJumpIfCellNotObject(regT0)); | |
f9bf01c6 A |
474 | |
475 | // We could inline the case where you have a valid cache, but | |
476 | // this call doesn't seem to be hot. | |
477 | Label isObject(this); | |
81345200 A |
478 | callOperation(operationGetPNames, regT0); |
479 | emitStoreCell(dst, returnValueGPR); | |
f9bf01c6 | 480 | load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); |
93a37866 | 481 | store64(tagTypeNumberRegister, addressFor(i)); |
14957cd0 A |
482 | store32(TrustedImm32(Int32Tag), intTagFor(size)); |
483 | store32(regT3, intPayloadFor(size)); | |
f9bf01c6 A |
484 | Jump end = jump(); |
485 | ||
486 | isNotObject.link(this); | |
487 | move(regT0, regT1); | |
14957cd0 A |
488 | and32(TrustedImm32(~TagBitUndefined), regT1); |
489 | addJump(branch32(Equal, regT1, TrustedImm32(ValueNull)), breakTarget); | |
81345200 | 490 | callOperation(operationToObject, base, regT0); |
f9bf01c6 A |
491 | jump().linkTo(isObject, this); |
492 | ||
493 | end.link(this); | |
494 | } | |
495 | ||
ba379fdc A |
496 | void JIT::emit_op_next_pname(Instruction* currentInstruction) |
497 | { | |
f9bf01c6 A |
498 | int dst = currentInstruction[1].u.operand; |
499 | int base = currentInstruction[2].u.operand; | |
500 | int i = currentInstruction[3].u.operand; | |
501 | int size = currentInstruction[4].u.operand; | |
502 | int it = currentInstruction[5].u.operand; | |
503 | int target = currentInstruction[6].u.operand; | |
504 | ||
505 | JumpList callHasProperty; | |
506 | ||
507 | Label begin(this); | |
14957cd0 A |
508 | load32(intPayloadFor(i), regT0); |
509 | Jump end = branch32(Equal, regT0, intPayloadFor(size)); | |
f9bf01c6 A |
510 | |
511 | // Grab key @ i | |
512 | loadPtr(addressFor(it), regT1); | |
513 | loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); | |
514 | ||
93a37866 | 515 | load64(BaseIndex(regT2, regT0, TimesEight), regT2); |
f9bf01c6 A |
516 | |
517 | emitPutVirtualRegister(dst, regT2); | |
518 | ||
519 | // Increment i | |
14957cd0 A |
520 | add32(TrustedImm32(1), regT0); |
521 | store32(regT0, intPayloadFor(i)); | |
f9bf01c6 A |
522 | |
523 | // Verify that i is valid: | |
524 | emitGetVirtualRegister(base, regT0); | |
525 | ||
526 | // Test base's structure | |
81345200 | 527 | emitLoadStructure(regT0, regT2, regT3); |
f9bf01c6 A |
528 | callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); |
529 | ||
530 | // Test base's prototype chain | |
531 | loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); | |
532 | loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); | |
533 | addJump(branchTestPtr(Zero, Address(regT3)), target); | |
534 | ||
535 | Label checkPrototype(this); | |
93a37866 | 536 | load64(Address(regT2, Structure::prototypeOffset()), regT2); |
f9bf01c6 | 537 | callHasProperty.append(emitJumpIfNotJSCell(regT2)); |
81345200 | 538 | emitLoadStructure(regT2, regT2, regT1); |
f9bf01c6 | 539 | callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); |
14957cd0 | 540 | addPtr(TrustedImm32(sizeof(Structure*)), regT3); |
f9bf01c6 A |
541 | branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); |
542 | ||
543 | // Continue loop. | |
544 | addJump(jump(), target); | |
545 | ||
546 | // Slow case: Ask the object if i is valid. | |
547 | callHasProperty.link(this); | |
548 | emitGetVirtualRegister(dst, regT1); | |
81345200 | 549 | callOperation(operationHasProperty, regT0, regT1); |
f9bf01c6 A |
550 | |
551 | // Test for valid key. | |
552 | addJump(branchTest32(NonZero, regT0), target); | |
553 | jump().linkTo(begin, this); | |
554 | ||
555 | // End of loop. | |
556 | end.link(this); | |
ba379fdc A |
557 | } |
558 | ||
93a37866 | 559 | void JIT::emit_op_push_with_scope(Instruction* currentInstruction) |
ba379fdc | 560 | { |
81345200 A |
561 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); |
562 | callOperation(operationPushWithScope, regT0); | |
ba379fdc A |
563 | } |
564 | ||
565 | void JIT::emit_op_pop_scope(Instruction*) | |
566 | { | |
81345200 | 567 | callOperation(operationPopScope); |
ba379fdc A |
568 | } |
569 | ||
570 | void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) | |
571 | { | |
81345200 A |
572 | int dst = currentInstruction[1].u.operand; |
573 | int src1 = currentInstruction[2].u.operand; | |
574 | int src2 = currentInstruction[3].u.operand; | |
ba379fdc A |
575 | |
576 | emitGetVirtualRegisters(src1, regT0, src2, regT1); | |
6fe7ccc8 A |
577 | |
578 | // Jump slow if both are cells (to cover strings). | |
ba379fdc | 579 | move(regT0, regT2); |
93a37866 | 580 | or64(regT1, regT2); |
ba379fdc | 581 | addSlowCase(emitJumpIfJSCell(regT2)); |
6fe7ccc8 A |
582 | |
583 | // Jump slow if either is a double. First test if it's an integer, which is fine, and then test | |
584 | // if it's a double. | |
585 | Jump leftOK = emitJumpIfImmediateInteger(regT0); | |
586 | addSlowCase(emitJumpIfImmediateNumber(regT0)); | |
587 | leftOK.link(this); | |
588 | Jump rightOK = emitJumpIfImmediateInteger(regT1); | |
589 | addSlowCase(emitJumpIfImmediateNumber(regT1)); | |
590 | rightOK.link(this); | |
ba379fdc A |
591 | |
592 | if (type == OpStrictEq) | |
93a37866 | 593 | compare64(Equal, regT1, regT0, regT0); |
ba379fdc | 594 | else |
93a37866 | 595 | compare64(NotEqual, regT1, regT0, regT0); |
ba379fdc A |
596 | emitTagAsBoolImmediate(regT0); |
597 | ||
598 | emitPutVirtualRegister(dst); | |
599 | } | |
600 | ||
601 | void JIT::emit_op_stricteq(Instruction* currentInstruction) | |
602 | { | |
603 | compileOpStrictEq(currentInstruction, OpStrictEq); | |
604 | } | |
605 | ||
606 | void JIT::emit_op_nstricteq(Instruction* currentInstruction) | |
607 | { | |
608 | compileOpStrictEq(currentInstruction, OpNStrictEq); | |
609 | } | |
610 | ||
93a37866 | 611 | void JIT::emit_op_to_number(Instruction* currentInstruction) |
ba379fdc A |
612 | { |
613 | int srcVReg = currentInstruction[2].u.operand; | |
614 | emitGetVirtualRegister(srcVReg, regT0); | |
615 | ||
93a37866 | 616 | addSlowCase(emitJumpIfNotImmediateNumber(regT0)); |
ba379fdc A |
617 | |
618 | emitPutVirtualRegister(currentInstruction[1].u.operand); | |
619 | } | |
620 | ||
93a37866 | 621 | void JIT::emit_op_push_name_scope(Instruction* currentInstruction) |
ba379fdc | 622 | { |
81345200 A |
623 | emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); |
624 | callOperation(operationPushNameScope, &m_codeBlock->identifier(currentInstruction[1].u.operand), regT0, currentInstruction[3].u.operand); | |
ba379fdc A |
625 | } |
626 | ||
627 | void JIT::emit_op_catch(Instruction* currentInstruction) | |
628 | { | |
40a37d08 A |
629 | // Gotta restore the tag registers. We could be throwing from FTL, which may |
630 | // clobber them. | |
631 | move(TrustedImm64(TagTypeNumber), tagTypeNumberRegister); | |
632 | move(TrustedImm64(TagMask), tagMaskRegister); | |
633 | ||
81345200 A |
634 | move(TrustedImmPtr(m_vm), regT3); |
635 | load64(Address(regT3, VM::callFrameForThrowOffset()), callFrameRegister); | |
636 | ||
637 | addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister); | |
638 | ||
639 | load64(Address(regT3, VM::exceptionOffset()), regT0); | |
640 | store64(TrustedImm64(JSValue::encode(JSValue())), Address(regT3, VM::exceptionOffset())); | |
ba379fdc A |
641 | emitPutVirtualRegister(currentInstruction[1].u.operand); |
642 | } | |
643 | ||
ba379fdc A |
644 | void JIT::emit_op_switch_imm(Instruction* currentInstruction) |
645 | { | |
81345200 | 646 | size_t tableIndex = currentInstruction[1].u.operand; |
ba379fdc A |
647 | unsigned defaultOffset = currentInstruction[2].u.operand; |
648 | unsigned scrutinee = currentInstruction[3].u.operand; | |
649 | ||
650 | // create jump table for switch destinations, track this switch statement. | |
81345200 | 651 | SimpleJumpTable* jumpTable = &m_codeBlock->switchJumpTable(tableIndex); |
14957cd0 | 652 | m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate)); |
81345200 | 653 | jumpTable->ensureCTITable(); |
ba379fdc | 654 | |
81345200 A |
655 | emitGetVirtualRegister(scrutinee, regT0); |
656 | callOperation(operationSwitchImmWithUnknownKeyType, regT0, tableIndex); | |
657 | jump(returnValueGPR); | |
ba379fdc A |
658 | } |
659 | ||
660 | void JIT::emit_op_switch_char(Instruction* currentInstruction) | |
661 | { | |
81345200 | 662 | size_t tableIndex = currentInstruction[1].u.operand; |
ba379fdc A |
663 | unsigned defaultOffset = currentInstruction[2].u.operand; |
664 | unsigned scrutinee = currentInstruction[3].u.operand; | |
665 | ||
666 | // create jump table for switch destinations, track this switch statement. | |
81345200 | 667 | SimpleJumpTable* jumpTable = &m_codeBlock->switchJumpTable(tableIndex); |
14957cd0 | 668 | m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character)); |
81345200 | 669 | jumpTable->ensureCTITable(); |
ba379fdc | 670 | |
81345200 A |
671 | emitGetVirtualRegister(scrutinee, regT0); |
672 | callOperation(operationSwitchCharWithUnknownKeyType, regT0, tableIndex); | |
673 | jump(returnValueGPR); | |
ba379fdc A |
674 | } |
675 | ||
676 | void JIT::emit_op_switch_string(Instruction* currentInstruction) | |
677 | { | |
81345200 | 678 | size_t tableIndex = currentInstruction[1].u.operand; |
ba379fdc A |
679 | unsigned defaultOffset = currentInstruction[2].u.operand; |
680 | unsigned scrutinee = currentInstruction[3].u.operand; | |
681 | ||
682 | // create jump table for switch destinations, track this switch statement. | |
683 | StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); | |
14957cd0 | 684 | m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset)); |
ba379fdc | 685 | |
81345200 A |
686 | emitGetVirtualRegister(scrutinee, regT0); |
687 | callOperation(operationSwitchStringWithUnknownKeyType, regT0, tableIndex); | |
688 | jump(returnValueGPR); | |
ba379fdc A |
689 | } |
690 | ||
93a37866 | 691 | void JIT::emit_op_throw_static_error(Instruction* currentInstruction) |
ba379fdc | 692 | { |
81345200 A |
693 | move(TrustedImm64(JSValue::encode(m_codeBlock->getConstant(currentInstruction[1].u.operand))), regT0); |
694 | callOperation(operationThrowStaticError, regT0, currentInstruction[2].u.operand); | |
ba379fdc A |
695 | } |
696 | ||
697 | void JIT::emit_op_debug(Instruction* currentInstruction) | |
698 | { | |
81345200 A |
699 | load32(codeBlock()->debuggerRequestsAddress(), regT0); |
700 | Jump noDebuggerRequests = branchTest32(Zero, regT0); | |
701 | callOperation(operationDebug, currentInstruction[1].u.operand); | |
702 | noDebuggerRequests.link(this); | |
ba379fdc A |
703 | } |
704 | ||
705 | void JIT::emit_op_eq_null(Instruction* currentInstruction) | |
706 | { | |
81345200 A |
707 | int dst = currentInstruction[1].u.operand; |
708 | int src1 = currentInstruction[2].u.operand; | |
ba379fdc A |
709 | |
710 | emitGetVirtualRegister(src1, regT0); | |
711 | Jump isImmediate = emitJumpIfNotJSCell(regT0); | |
712 | ||
81345200 | 713 | Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); |
93a37866 A |
714 | move(TrustedImm32(0), regT0); |
715 | Jump wasNotMasqueradesAsUndefined = jump(); | |
716 | ||
717 | isMasqueradesAsUndefined.link(this); | |
81345200 | 718 | emitLoadStructure(regT0, regT2, regT1); |
93a37866 A |
719 | move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); |
720 | loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2); | |
721 | comparePtr(Equal, regT0, regT2, regT0); | |
ba379fdc A |
722 | Jump wasNotImmediate = jump(); |
723 | ||
724 | isImmediate.link(this); | |
725 | ||
93a37866 A |
726 | and64(TrustedImm32(~TagBitUndefined), regT0); |
727 | compare64(Equal, regT0, TrustedImm32(ValueNull), regT0); | |
ba379fdc A |
728 | |
729 | wasNotImmediate.link(this); | |
93a37866 | 730 | wasNotMasqueradesAsUndefined.link(this); |
ba379fdc A |
731 | |
732 | emitTagAsBoolImmediate(regT0); | |
733 | emitPutVirtualRegister(dst); | |
734 | ||
735 | } | |
736 | ||
737 | void JIT::emit_op_neq_null(Instruction* currentInstruction) | |
738 | { | |
81345200 A |
739 | int dst = currentInstruction[1].u.operand; |
740 | int src1 = currentInstruction[2].u.operand; | |
ba379fdc A |
741 | |
742 | emitGetVirtualRegister(src1, regT0); | |
743 | Jump isImmediate = emitJumpIfNotJSCell(regT0); | |
744 | ||
81345200 | 745 | Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); |
93a37866 A |
746 | move(TrustedImm32(1), regT0); |
747 | Jump wasNotMasqueradesAsUndefined = jump(); | |
748 | ||
749 | isMasqueradesAsUndefined.link(this); | |
81345200 | 750 | emitLoadStructure(regT0, regT2, regT1); |
93a37866 A |
751 | move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); |
752 | loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2); | |
753 | comparePtr(NotEqual, regT0, regT2, regT0); | |
ba379fdc A |
754 | Jump wasNotImmediate = jump(); |
755 | ||
756 | isImmediate.link(this); | |
757 | ||
93a37866 A |
758 | and64(TrustedImm32(~TagBitUndefined), regT0); |
759 | compare64(NotEqual, regT0, TrustedImm32(ValueNull), regT0); | |
ba379fdc A |
760 | |
761 | wasNotImmediate.link(this); | |
93a37866 | 762 | wasNotMasqueradesAsUndefined.link(this); |
ba379fdc A |
763 | |
764 | emitTagAsBoolImmediate(regT0); | |
765 | emitPutVirtualRegister(dst); | |
ba379fdc A |
766 | } |
767 | ||
768 | void JIT::emit_op_enter(Instruction*) | |
769 | { | |
770 | // Even though CTI doesn't use them, we initialize our constant | |
771 | // registers to zap stale pointers, to avoid unnecessarily prolonging | |
772 | // object lifetime and increasing GC pressure. | |
773 | size_t count = m_codeBlock->m_numVars; | |
774 | for (size_t j = 0; j < count; ++j) | |
81345200 A |
775 | emitInitRegister(virtualRegisterForLocal(j).offset()); |
776 | ||
777 | emitWriteBarrier(m_codeBlock->ownerExecutable()); | |
778 | ||
779 | emitEnterOptimizationCheck(); | |
ba379fdc A |
780 | } |
781 | ||
14957cd0 | 782 | void JIT::emit_op_create_activation(Instruction* currentInstruction) |
ba379fdc | 783 | { |
81345200 | 784 | int dst = currentInstruction[1].u.operand; |
14957cd0 | 785 | |
93a37866 | 786 | Jump activationCreated = branchTest64(NonZero, Address(callFrameRegister, sizeof(Register) * dst)); |
81345200 A |
787 | callOperation(operationCreateActivation, 0); |
788 | emitStoreCell(dst, returnValueGPR); | |
14957cd0 | 789 | activationCreated.link(this); |
ba379fdc A |
790 | } |
791 | ||
14957cd0 | 792 | void JIT::emit_op_create_arguments(Instruction* currentInstruction) |
ba379fdc | 793 | { |
81345200 | 794 | int dst = currentInstruction[1].u.operand; |
14957cd0 | 795 | |
93a37866 | 796 | Jump argsCreated = branchTest64(NonZero, Address(callFrameRegister, sizeof(Register) * dst)); |
81345200 A |
797 | |
798 | callOperation(operationCreateArguments); | |
799 | emitStoreCell(dst, returnValueGPR); | |
800 | emitStoreCell(unmodifiedArgumentsRegister(VirtualRegister(dst)), returnValueGPR); | |
801 | ||
ba379fdc A |
802 | argsCreated.link(this); |
803 | } | |
14957cd0 A |
804 | |
805 | void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) | |
ba379fdc | 806 | { |
81345200 | 807 | int dst = currentInstruction[1].u.operand; |
14957cd0 | 808 | |
93a37866 | 809 | store64(TrustedImm64((int64_t)0), Address(callFrameRegister, sizeof(Register) * dst)); |
ba379fdc A |
810 | } |
811 | ||
81345200 | 812 | void JIT::emit_op_to_this(Instruction* currentInstruction) |
ba379fdc | 813 | { |
81345200 | 814 | WriteBarrierBase<Structure>* cachedStructure = ¤tInstruction[2].u.structure; |
93a37866 | 815 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT1); |
ba379fdc | 816 | |
93a37866 | 817 | emitJumpSlowCaseIfNotJSCell(regT1); |
81345200 A |
818 | |
819 | addSlowCase(branch8(NotEqual, Address(regT1, JSCell::typeInfoTypeOffset()), TrustedImm32(FinalObjectType))); | |
820 | loadPtr(cachedStructure, regT2); | |
821 | addSlowCase(branchTestPtr(Zero, regT2)); | |
822 | load32(Address(regT2, Structure::structureIDOffset()), regT2); | |
823 | addSlowCase(branch32(NotEqual, Address(regT1, JSCell::structureIDOffset()), regT2)); | |
14957cd0 A |
824 | } |
825 | ||
826 | void JIT::emit_op_get_callee(Instruction* currentInstruction) | |
827 | { | |
81345200 A |
828 | int result = currentInstruction[1].u.operand; |
829 | WriteBarrierBase<JSCell>* cachedFunction = ¤tInstruction[2].u.jsCell; | |
93a37866 | 830 | emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0); |
81345200 A |
831 | |
832 | loadPtr(cachedFunction, regT2); | |
833 | addSlowCase(branchPtr(NotEqual, regT0, regT2)); | |
834 | ||
14957cd0 A |
835 | emitPutVirtualRegister(result); |
836 | } | |
837 | ||
81345200 A |
838 | void JIT::emitSlow_op_get_callee(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
839 | { | |
840 | linkSlowCase(iter); | |
841 | ||
842 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_callee); | |
843 | slowPathCall.call(); | |
844 | } | |
845 | ||
14957cd0 A |
846 | void JIT::emit_op_create_this(Instruction* currentInstruction) |
847 | { | |
93a37866 A |
848 | int callee = currentInstruction[2].u.operand; |
849 | RegisterID calleeReg = regT0; | |
850 | RegisterID resultReg = regT0; | |
851 | RegisterID allocatorReg = regT1; | |
852 | RegisterID structureReg = regT2; | |
853 | RegisterID scratchReg = regT3; | |
854 | ||
855 | emitGetVirtualRegister(callee, calleeReg); | |
856 | loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg); | |
857 | loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg); | |
858 | addSlowCase(branchTestPtr(Zero, allocatorReg)); | |
859 | ||
860 | emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg); | |
6fe7ccc8 A |
861 | emitPutVirtualRegister(currentInstruction[1].u.operand); |
862 | } | |
863 | ||
864 | void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
865 | { | |
93a37866 | 866 | linkSlowCase(iter); // doesn't have an allocation profile |
6fe7ccc8 | 867 | linkSlowCase(iter); // allocation failed |
93a37866 | 868 | |
81345200 A |
869 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_this); |
870 | slowPathCall.call(); | |
ba379fdc A |
871 | } |
872 | ||
873 | void JIT::emit_op_profile_will_call(Instruction* currentInstruction) | |
874 | { | |
81345200 A |
875 | Jump profilerDone = branchTestPtr(Zero, AbsoluteAddress(m_vm->enabledProfilerAddress())); |
876 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); | |
877 | callOperation(operationProfileWillCall, regT0); | |
878 | profilerDone.link(this); | |
ba379fdc A |
879 | } |
880 | ||
881 | void JIT::emit_op_profile_did_call(Instruction* currentInstruction) | |
882 | { | |
81345200 A |
883 | Jump profilerDone = branchTestPtr(Zero, AbsoluteAddress(m_vm->enabledProfilerAddress())); |
884 | emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); | |
885 | callOperation(operationProfileDidCall, regT0); | |
886 | profilerDone.link(this); | |
ba379fdc A |
887 | } |
888 | ||
889 | ||
890 | // Slow cases | |
891 | ||
81345200 | 892 | void JIT::emitSlow_op_to_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
ba379fdc A |
893 | { |
894 | linkSlowCase(iter); | |
ba379fdc | 895 | linkSlowCase(iter); |
81345200 A |
896 | linkSlowCase(iter); |
897 | linkSlowCase(iter); | |
898 | ||
899 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_this); | |
900 | slowPathCall.call(); | |
ba379fdc A |
901 | } |
902 | ||
903 | void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
904 | { | |
905 | linkSlowCase(iter); | |
906 | ||
81345200 A |
907 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_primitive); |
908 | slowPathCall.call(); | |
ba379fdc A |
909 | } |
910 | ||
ba379fdc A |
911 | void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
912 | { | |
913 | linkSlowCase(iter); | |
81345200 A |
914 | |
915 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_not); | |
916 | slowPathCall.call(); | |
ba379fdc A |
917 | } |
918 | ||
919 | void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
920 | { | |
921 | linkSlowCase(iter); | |
81345200 A |
922 | callOperation(operationConvertJSValueToBoolean, regT0); |
923 | emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), currentInstruction[2].u.operand); // inverted! | |
ba379fdc A |
924 | } |
925 | ||
ba379fdc A |
926 | void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
927 | { | |
928 | linkSlowCase(iter); | |
81345200 A |
929 | callOperation(operationConvertJSValueToBoolean, regT0); |
930 | emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), currentInstruction[2].u.operand); | |
ba379fdc A |
931 | } |
932 | ||
933 | void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
934 | { | |
935 | linkSlowCase(iter); | |
81345200 A |
936 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_bitxor); |
937 | slowPathCall.call(); | |
ba379fdc A |
938 | } |
939 | ||
940 | void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
941 | { | |
942 | linkSlowCase(iter); | |
81345200 A |
943 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_bitor); |
944 | slowPathCall.call(); | |
ba379fdc A |
945 | } |
946 | ||
947 | void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
948 | { | |
949 | linkSlowCase(iter); | |
81345200 A |
950 | callOperation(operationCompareEq, regT0, regT1); |
951 | emitTagAsBoolImmediate(returnValueGPR); | |
952 | emitPutVirtualRegister(currentInstruction[1].u.operand, returnValueGPR); | |
ba379fdc A |
953 | } |
954 | ||
955 | void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
956 | { | |
957 | linkSlowCase(iter); | |
81345200 | 958 | callOperation(operationCompareEq, regT0, regT1); |
14957cd0 | 959 | xor32(TrustedImm32(0x1), regT0); |
81345200 A |
960 | emitTagAsBoolImmediate(returnValueGPR); |
961 | emitPutVirtualRegister(currentInstruction[1].u.operand, returnValueGPR); | |
ba379fdc A |
962 | } |
963 | ||
964 | void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
965 | { | |
6fe7ccc8 | 966 | linkSlowCase(iter); |
ba379fdc A |
967 | linkSlowCase(iter); |
968 | linkSlowCase(iter); | |
81345200 A |
969 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_stricteq); |
970 | slowPathCall.call(); | |
ba379fdc A |
971 | } |
972 | ||
973 | void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
974 | { | |
6fe7ccc8 | 975 | linkSlowCase(iter); |
ba379fdc A |
976 | linkSlowCase(iter); |
977 | linkSlowCase(iter); | |
81345200 A |
978 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_nstricteq); |
979 | slowPathCall.call(); | |
ba379fdc A |
980 | } |
981 | ||
14957cd0 A |
982 | void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
983 | { | |
81345200 A |
984 | int dst = currentInstruction[1].u.operand; |
985 | int value = currentInstruction[2].u.operand; | |
986 | int baseVal = currentInstruction[3].u.operand; | |
14957cd0 A |
987 | |
988 | linkSlowCaseIfNotJSCell(iter, baseVal); | |
989 | linkSlowCase(iter); | |
81345200 A |
990 | emitGetVirtualRegister(value, regT0); |
991 | emitGetVirtualRegister(baseVal, regT1); | |
992 | callOperation(operationCheckHasInstance, dst, regT0, regT1); | |
93a37866 A |
993 | |
994 | emitJumpSlowToHot(jump(), currentInstruction[4].u.operand); | |
14957cd0 A |
995 | } |
996 | ||
ba379fdc A |
997 | void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
998 | { | |
81345200 A |
999 | int dst = currentInstruction[1].u.operand; |
1000 | int value = currentInstruction[2].u.operand; | |
1001 | int proto = currentInstruction[3].u.operand; | |
f9bf01c6 A |
1002 | |
1003 | linkSlowCaseIfNotJSCell(iter, value); | |
f9bf01c6 | 1004 | linkSlowCaseIfNotJSCell(iter, proto); |
ba379fdc | 1005 | linkSlowCase(iter); |
81345200 A |
1006 | emitGetVirtualRegister(value, regT0); |
1007 | emitGetVirtualRegister(proto, regT1); | |
1008 | callOperation(operationInstanceOf, dst, regT0, regT1); | |
ba379fdc A |
1009 | } |
1010 | ||
93a37866 | 1011 | void JIT::emitSlow_op_to_number(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
ba379fdc | 1012 | { |
ba379fdc A |
1013 | linkSlowCase(iter); |
1014 | ||
81345200 A |
1015 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_number); |
1016 | slowPathCall.call(); | |
ba379fdc A |
1017 | } |
1018 | ||
14957cd0 A |
1019 | void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) |
1020 | { | |
1021 | int dst = currentInstruction[1].u.operand; | |
1022 | int argumentsRegister = currentInstruction[2].u.operand; | |
93a37866 A |
1023 | addSlowCase(branchTest64(NonZero, addressFor(argumentsRegister))); |
1024 | emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0); | |
14957cd0 A |
1025 | sub32(TrustedImm32(1), regT0); |
1026 | emitFastArithReTagImmediate(regT0, regT0); | |
1027 | emitPutVirtualRegister(dst, regT0); | |
1028 | } | |
1029 | ||
1030 | void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
1031 | { | |
1032 | linkSlowCase(iter); | |
81345200 A |
1033 | int dst = currentInstruction[1].u.operand; |
1034 | int base = currentInstruction[2].u.operand; | |
1035 | callOperation(operationGetArgumentsLength, dst, base); | |
14957cd0 A |
1036 | } |
1037 | ||
1038 | void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction) | |
1039 | { | |
1040 | int dst = currentInstruction[1].u.operand; | |
1041 | int argumentsRegister = currentInstruction[2].u.operand; | |
1042 | int property = currentInstruction[3].u.operand; | |
93a37866 | 1043 | addSlowCase(branchTest64(NonZero, addressFor(argumentsRegister))); |
14957cd0 A |
1044 | emitGetVirtualRegister(property, regT1); |
1045 | addSlowCase(emitJumpIfNotImmediateInteger(regT1)); | |
1046 | add32(TrustedImm32(1), regT1); | |
1047 | // regT1 now contains the integer index of the argument we want, including this | |
93a37866 | 1048 | emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT2); |
14957cd0 | 1049 | addSlowCase(branch32(AboveOrEqual, regT1, regT2)); |
6fe7ccc8 | 1050 | |
6fe7ccc8 | 1051 | signExtend32ToPtr(regT1, regT1); |
93a37866 A |
1052 | load64(BaseIndex(callFrameRegister, regT1, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT0); |
1053 | emitValueProfilingSite(); | |
14957cd0 A |
1054 | emitPutVirtualRegister(dst, regT0); |
1055 | } | |
1056 | ||
1057 | void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
1058 | { | |
81345200 A |
1059 | int dst = currentInstruction[1].u.operand; |
1060 | int arguments = currentInstruction[2].u.operand; | |
1061 | int property = currentInstruction[3].u.operand; | |
14957cd0 A |
1062 | |
1063 | linkSlowCase(iter); | |
1064 | Jump skipArgumentsCreation = jump(); | |
1065 | ||
1066 | linkSlowCase(iter); | |
1067 | linkSlowCase(iter); | |
81345200 A |
1068 | callOperation(operationCreateArguments); |
1069 | emitStoreCell(arguments, returnValueGPR); | |
1070 | emitStoreCell(unmodifiedArgumentsRegister(VirtualRegister(arguments)), returnValueGPR); | |
14957cd0 A |
1071 | |
1072 | skipArgumentsCreation.link(this); | |
81345200 A |
1073 | emitGetVirtualRegister(arguments, regT0); |
1074 | emitGetVirtualRegister(property, regT1); | |
1075 | callOperation(WithProfile, operationGetByValGeneric, dst, regT0, regT1); | |
1076 | } | |
93a37866 | 1077 | |
81345200 | 1078 | #endif // USE(JSVALUE64) |
93a37866 | 1079 | |
81345200 A |
1080 | void JIT::emit_op_touch_entry(Instruction* currentInstruction) |
1081 | { | |
1082 | if (m_codeBlock->symbolTable()->m_functionEnteredOnce.hasBeenInvalidated()) | |
93a37866 | 1083 | return; |
81345200 A |
1084 | |
1085 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_touch_entry); | |
1086 | slowPathCall.call(); | |
14957cd0 A |
1087 | } |
1088 | ||
93a37866 | 1089 | void JIT::emit_op_loop_hint(Instruction*) |
4e4e5a6f | 1090 | { |
93a37866 | 1091 | // Emit the JIT optimization check: |
81345200 | 1092 | if (canBeOptimized()) { |
93a37866 A |
1093 | addSlowCase(branchAdd32(PositiveOrZero, TrustedImm32(Options::executionCounterIncrementForLoop()), |
1094 | AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter()))); | |
81345200 | 1095 | } |
93a37866 A |
1096 | |
1097 | // Emit the watchdog timer check: | |
81345200 A |
1098 | if (m_vm->watchdog && m_vm->watchdog->isEnabled()) |
1099 | addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_vm->watchdog->timerDidFireAddress()))); | |
93a37866 A |
1100 | } |
1101 | ||
1102 | void JIT::emitSlow_op_loop_hint(Instruction*, Vector<SlowCaseEntry>::iterator& iter) | |
1103 | { | |
1104 | #if ENABLE(DFG_JIT) | |
1105 | // Emit the slow path for the JIT optimization check: | |
1106 | if (canBeOptimized()) { | |
1107 | linkSlowCase(iter); | |
81345200 A |
1108 | |
1109 | callOperation(operationOptimize, m_bytecodeOffset); | |
1110 | Jump noOptimizedEntry = branchTestPtr(Zero, returnValueGPR); | |
1111 | if (!ASSERT_DISABLED) { | |
1112 | Jump ok = branchPtr(MacroAssembler::Above, regT0, TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000)))); | |
1113 | abortWithReason(JITUnreasonableLoopHintJumpTarget); | |
1114 | ok.link(this); | |
1115 | } | |
1116 | jump(returnValueGPR); | |
1117 | noOptimizedEntry.link(this); | |
93a37866 A |
1118 | |
1119 | emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_loop_hint)); | |
14957cd0 | 1120 | } |
93a37866 A |
1121 | #endif |
1122 | ||
1123 | // Emit the slow path of the watchdog timer check: | |
81345200 | 1124 | if (m_vm->watchdog && m_vm->watchdog->isEnabled()) { |
93a37866 | 1125 | linkSlowCase(iter); |
81345200 | 1126 | callOperation(operationHandleWatchdogTimer); |
93a37866 A |
1127 | |
1128 | emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_loop_hint)); | |
4e4e5a6f | 1129 | } |
93a37866 | 1130 | |
4e4e5a6f A |
1131 | } |
1132 | ||
4e4e5a6f A |
1133 | void JIT::emit_op_new_regexp(Instruction* currentInstruction) |
1134 | { | |
81345200 | 1135 | callOperation(operationNewRegexp, currentInstruction[1].u.operand, m_codeBlock->regexp(currentInstruction[2].u.operand)); |
4e4e5a6f A |
1136 | } |
1137 | ||
6fe7ccc8 | 1138 | void JIT::emit_op_new_func(Instruction* currentInstruction) |
4e4e5a6f | 1139 | { |
6fe7ccc8 A |
1140 | Jump lazyJump; |
1141 | int dst = currentInstruction[1].u.operand; | |
1142 | if (currentInstruction[3].u.operand) { | |
4e4e5a6f | 1143 | #if USE(JSVALUE32_64) |
6fe7ccc8 | 1144 | lazyJump = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag)); |
4e4e5a6f | 1145 | #else |
93a37866 | 1146 | lazyJump = branchTest64(NonZero, addressFor(dst)); |
4e4e5a6f | 1147 | #endif |
6fe7ccc8 | 1148 | } |
14957cd0 | 1149 | |
81345200 A |
1150 | FunctionExecutable* funcExec = m_codeBlock->functionDecl(currentInstruction[2].u.operand); |
1151 | callOperation(operationNewFunction, dst, funcExec); | |
6fe7ccc8 | 1152 | |
81345200 | 1153 | if (currentInstruction[3].u.operand) |
6fe7ccc8 | 1154 | lazyJump.link(this); |
81345200 A |
1155 | } |
1156 | ||
1157 | void JIT::emit_op_new_captured_func(Instruction* currentInstruction) | |
1158 | { | |
1159 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_new_captured_func); | |
1160 | slowPathCall.call(); | |
14957cd0 | 1161 | } |
4e4e5a6f | 1162 | |
6fe7ccc8 | 1163 | void JIT::emit_op_new_func_exp(Instruction* currentInstruction) |
14957cd0 | 1164 | { |
81345200 A |
1165 | int dst = currentInstruction[1].u.operand; |
1166 | FunctionExecutable* funcExpr = m_codeBlock->functionExpr(currentInstruction[2].u.operand); | |
1167 | callOperation(operationNewFunction, dst, funcExpr); | |
6fe7ccc8 A |
1168 | } |
1169 | ||
14957cd0 A |
1170 | void JIT::emit_op_new_array(Instruction* currentInstruction) |
1171 | { | |
81345200 A |
1172 | int dst = currentInstruction[1].u.operand; |
1173 | int valuesIndex = currentInstruction[2].u.operand; | |
1174 | int size = currentInstruction[3].u.operand; | |
1175 | addPtr(TrustedImm32(valuesIndex * sizeof(Register)), callFrameRegister, regT0); | |
1176 | callOperation(operationNewArrayWithProfile, dst, | |
1177 | currentInstruction[4].u.arrayAllocationProfile, regT0, size); | |
93a37866 A |
1178 | } |
1179 | ||
1180 | void JIT::emit_op_new_array_with_size(Instruction* currentInstruction) | |
1181 | { | |
81345200 A |
1182 | int dst = currentInstruction[1].u.operand; |
1183 | int sizeIndex = currentInstruction[2].u.operand; | |
93a37866 | 1184 | #if USE(JSVALUE64) |
81345200 A |
1185 | emitGetVirtualRegister(sizeIndex, regT0); |
1186 | callOperation(operationNewArrayWithSizeAndProfile, dst, | |
1187 | currentInstruction[3].u.arrayAllocationProfile, regT0); | |
93a37866 | 1188 | #else |
81345200 A |
1189 | emitLoad(sizeIndex, regT1, regT0); |
1190 | callOperation(operationNewArrayWithSizeAndProfile, dst, | |
1191 | currentInstruction[3].u.arrayAllocationProfile, regT1, regT0); | |
93a37866 | 1192 | #endif |
14957cd0 A |
1193 | } |
1194 | ||
1195 | void JIT::emit_op_new_array_buffer(Instruction* currentInstruction) | |
1196 | { | |
81345200 A |
1197 | int dst = currentInstruction[1].u.operand; |
1198 | int valuesIndex = currentInstruction[2].u.operand; | |
1199 | int size = currentInstruction[3].u.operand; | |
1200 | const JSValue* values = codeBlock()->constantBuffer(valuesIndex); | |
1201 | callOperation(operationNewArrayBufferWithProfile, dst, currentInstruction[4].u.arrayAllocationProfile, values, size); | |
1202 | } | |
1203 | ||
1204 | void JIT::emitSlow_op_captured_mov(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
1205 | { | |
1206 | VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet; | |
1207 | if (!set || set->state() == IsInvalidated) | |
1208 | return; | |
1209 | #if USE(JSVALUE32_64) | |
1210 | linkSlowCase(iter); | |
1211 | #endif | |
1212 | linkSlowCase(iter); | |
1213 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_captured_mov); | |
1214 | slowPathCall.call(); | |
14957cd0 A |
1215 | } |
1216 | ||
ba379fdc A |
1217 | } // namespace JSC |
1218 | ||
1219 | #endif // ENABLE(JIT) |