1 /*
2 * Copyright (C) 2008 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 #include "config.h"
27 #include "JIT.h"
28
29 #if ENABLE(JIT)
30
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
33 #include "JITStubCall.h"
34 #include "JSArray.h"
35 #include "JSFunction.h"
36 #include "Interpreter.h"
37 #include "ResultType.h"
38 #include "SamplingTool.h"
39
40 #ifndef NDEBUG
41 #include <stdio.h>
42 #endif
43
44 using namespace std;
45
46 namespace JSC {
47
48 #if USE(JSVALUE32_64)
49
compileOpCallInitializeCallFrame()50 void JIT::compileOpCallInitializeCallFrame()
51 {
52 // regT0 holds callee, regT1 holds argCount
53 store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
54
55 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // scopeChain
56
57 emitStore(static_cast<unsigned>(RegisterFile::OptionalCalleeArguments), JSValue());
58 storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); // callee
59 storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain
60 }
61
compileOpCallSetupArgs(Instruction * instruction)62 void JIT::compileOpCallSetupArgs(Instruction* instruction)
63 {
64 int argCount = instruction[3].u.operand;
65 int registerOffset = instruction[4].u.operand;
66
67 emitPutJITStubArg(regT1, regT0, 0);
68 emitPutJITStubArgConstant(registerOffset, 1);
69 emitPutJITStubArgConstant(argCount, 2);
70 }
71
compileOpConstructSetupArgs(Instruction * instruction)72 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
73 {
74 int argCount = instruction[3].u.operand;
75 int registerOffset = instruction[4].u.operand;
76 int proto = instruction[5].u.operand;
77 int thisRegister = instruction[6].u.operand;
78
79 emitPutJITStubArg(regT1, regT0, 0);
80 emitPutJITStubArgConstant(registerOffset, 1);
81 emitPutJITStubArgConstant(argCount, 2);
82 emitPutJITStubArgFromVirtualRegister(proto, 3, regT2, regT3);
83 emitPutJITStubArgConstant(thisRegister, 4);
84 }
85
compileOpCallVarargsSetupArgs(Instruction *)86 void JIT::compileOpCallVarargsSetupArgs(Instruction*)
87 {
88 emitPutJITStubArg(regT1, regT0, 0);
89 emitPutJITStubArg(regT3, 1); // registerOffset
90 emitPutJITStubArg(regT2, 2); // argCount
91 }
92
compileOpCallVarargs(Instruction * instruction)93 void JIT::compileOpCallVarargs(Instruction* instruction)
94 {
95 int dst = instruction[1].u.operand;
96 int callee = instruction[2].u.operand;
97 int argCountRegister = instruction[3].u.operand;
98 int registerOffset = instruction[4].u.operand;
99
100 emitLoad(callee, regT1, regT0);
101 emitLoadPayload(argCountRegister, regT2); // argCount
102 addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
103
104 compileOpCallVarargsSetupArgs(instruction);
105
106 emitJumpSlowCaseIfNotJSCell(callee, regT1);
107 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
108
109 // Speculatively roll the callframe, assuming argCount will match the arity.
110 mul32(Imm32(sizeof(Register)), regT3, regT3);
111 addPtr(callFrameRegister, regT3);
112 storePtr(callFrameRegister, Address(regT3, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register))));
113 move(regT3, callFrameRegister);
114
115 move(regT2, regT1); // argCount
116
117 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
118
119 emitStore(dst, regT1, regT0);
120
121 sampleCodeBlock(m_codeBlock);
122 }
123
compileOpCallVarargsSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter)124 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
125 {
126 int dst = instruction[1].u.operand;
127 int callee = instruction[2].u.operand;
128
129 linkSlowCaseIfNotJSCell(iter, callee);
130 linkSlowCase(iter);
131
132 JITStubCall stubCall(this, cti_op_call_NotJSFunction);
133 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
134
135 map(m_bytecodeIndex + OPCODE_LENGTH(op_call_varargs), dst, regT1, regT0);
136 sampleCodeBlock(m_codeBlock);
137 }
138
emit_op_ret(Instruction * currentInstruction)139 void JIT::emit_op_ret(Instruction* currentInstruction)
140 {
141 unsigned dst = currentInstruction[1].u.operand;
142
143 // We could JIT generate the deref, only calling out to C when the refcount hits zero.
144 if (m_codeBlock->needsFullScopeChain())
145 JITStubCall(this, cti_op_ret_scopeChain).call();
146
147 emitLoad(dst, regT1, regT0);
148 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
149 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
150
151 restoreReturnAddressBeforeReturn(regT2);
152 ret();
153 }
154
emit_op_construct_verify(Instruction * currentInstruction)155 void JIT::emit_op_construct_verify(Instruction* currentInstruction)
156 {
157 unsigned dst = currentInstruction[1].u.operand;
158
159 emitLoad(dst, regT1, regT0);
160 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
161 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
162 addSlowCase(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType)));
163 }
164
emitSlow_op_construct_verify(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)165 void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
166 {
167 unsigned dst = currentInstruction[1].u.operand;
168 unsigned src = currentInstruction[2].u.operand;
169
170 linkSlowCase(iter);
171 linkSlowCase(iter);
172 emitLoad(src, regT1, regT0);
173 emitStore(dst, regT1, regT0);
174 }
175
emitSlow_op_call(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)176 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
177 {
178 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
179 }
180
emitSlow_op_call_eval(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)181 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
182 {
183 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
184 }
185
emitSlow_op_call_varargs(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)186 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
187 {
188 compileOpCallVarargsSlowCase(currentInstruction, iter);
189 }
190
emitSlow_op_construct(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)191 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
192 {
193 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
194 }
195
emit_op_call(Instruction * currentInstruction)196 void JIT::emit_op_call(Instruction* currentInstruction)
197 {
198 compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
199 }
200
emit_op_call_eval(Instruction * currentInstruction)201 void JIT::emit_op_call_eval(Instruction* currentInstruction)
202 {
203 compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
204 }
205
emit_op_load_varargs(Instruction * currentInstruction)206 void JIT::emit_op_load_varargs(Instruction* currentInstruction)
207 {
208 int argCountDst = currentInstruction[1].u.operand;
209 int argsOffset = currentInstruction[2].u.operand;
210
211 JITStubCall stubCall(this, cti_op_load_varargs);
212 stubCall.addArgument(Imm32(argsOffset));
213 stubCall.call();
214 // Stores a naked int32 in the register file.
215 store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
216 }
217
emit_op_call_varargs(Instruction * currentInstruction)218 void JIT::emit_op_call_varargs(Instruction* currentInstruction)
219 {
220 compileOpCallVarargs(currentInstruction);
221 }
222
emit_op_construct(Instruction * currentInstruction)223 void JIT::emit_op_construct(Instruction* currentInstruction)
224 {
225 compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
226 }
227
228 #if !ENABLE(JIT_OPTIMIZE_CALL)
229
230 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
231
compileOpCall(OpcodeID opcodeID,Instruction * instruction,unsigned)232 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
233 {
234 int dst = instruction[1].u.operand;
235 int callee = instruction[2].u.operand;
236 int argCount = instruction[3].u.operand;
237 int registerOffset = instruction[4].u.operand;
238
239 Jump wasEval;
240 if (opcodeID == op_call_eval) {
241 JITStubCall stubCall(this, cti_op_call_eval);
242 stubCall.addArgument(callee);
243 stubCall.addArgument(JIT::Imm32(registerOffset));
244 stubCall.addArgument(JIT::Imm32(argCount));
245 stubCall.call();
246 wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
247 }
248
249 emitLoad(callee, regT1, regT0);
250
251 if (opcodeID == op_call)
252 compileOpCallSetupArgs(instruction);
253 else if (opcodeID == op_construct)
254 compileOpConstructSetupArgs(instruction);
255
256 emitJumpSlowCaseIfNotJSCell(callee, regT1);
257 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
258
259 // First, in the case of a construct, allocate the new object.
260 if (opcodeID == op_construct) {
261 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
262 emitLoad(callee, regT1, regT0);
263 }
264
265 // Speculatively roll the callframe, assuming argCount will match the arity.
266 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
267 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
268 move(Imm32(argCount), regT1);
269
270 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
271
272 if (opcodeID == op_call_eval)
273 wasEval.link(this);
274
275 emitStore(dst, regT1, regT0);
276
277 sampleCodeBlock(m_codeBlock);
278 }
279
compileOpCallSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter,unsigned,OpcodeID opcodeID)280 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
281 {
282 int dst = instruction[1].u.operand;
283 int callee = instruction[2].u.operand;
284
285 linkSlowCaseIfNotJSCell(iter, callee);
286 linkSlowCase(iter);
287
288 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
289 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
290
291 sampleCodeBlock(m_codeBlock);
292 }
293
294 #else // !ENABLE(JIT_OPTIMIZE_CALL)
295
296 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
297
compileOpCall(OpcodeID opcodeID,Instruction * instruction,unsigned callLinkInfoIndex)298 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
299 {
300 int dst = instruction[1].u.operand;
301 int callee = instruction[2].u.operand;
302 int argCount = instruction[3].u.operand;
303 int registerOffset = instruction[4].u.operand;
304
305 Jump wasEval;
306 if (opcodeID == op_call_eval) {
307 JITStubCall stubCall(this, cti_op_call_eval);
308 stubCall.addArgument(callee);
309 stubCall.addArgument(JIT::Imm32(registerOffset));
310 stubCall.addArgument(JIT::Imm32(argCount));
311 stubCall.call();
312 wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
313 }
314
315 emitLoad(callee, regT1, regT0);
316
317 DataLabelPtr addressOfLinkedFunctionCheck;
318
319 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
320
321 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0));
322
323 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
324
325 addSlowCase(jumpToSlow);
326 ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
327 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
328
329 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
330
331 // The following is the fast case, only used whan a callee can be linked.
332
333 // In the case of OpConstruct, call out to a cti_ function to create the new object.
334 if (opcodeID == op_construct) {
335 int proto = instruction[5].u.operand;
336 int thisRegister = instruction[6].u.operand;
337
338 JITStubCall stubCall(this, cti_op_construct_JSConstruct);
339 stubCall.addArgument(regT1, regT0);
340 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
341 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
342 stubCall.addArgument(proto);
343 stubCall.call(thisRegister);
344
345 emitLoad(callee, regT1, regT0);
346 }
347
348 // Fast version of stack frame initialization, directly relative to edi.
349 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
350 emitStore(registerOffset + RegisterFile::OptionalCalleeArguments, JSValue());
351 emitStore(registerOffset + RegisterFile::Callee, regT1, regT0);
352
353 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
354 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
355 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
356 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
357 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
358
359 // Call to the callee
360 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
361
362 if (opcodeID == op_call_eval)
363 wasEval.link(this);
364
365 // Put the return value in dst. In the interpreter, op_ret does this.
366 emitStore(dst, regT1, regT0);
367 map(m_bytecodeIndex + opcodeLengths[opcodeID], dst, regT1, regT0);
368
369 sampleCodeBlock(m_codeBlock);
370 }
371
compileOpCallSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter,unsigned callLinkInfoIndex,OpcodeID opcodeID)372 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
373 {
374 int dst = instruction[1].u.operand;
375 int callee = instruction[2].u.operand;
376 int argCount = instruction[3].u.operand;
377 int registerOffset = instruction[4].u.operand;
378
379 linkSlowCase(iter);
380 linkSlowCase(iter);
381
382 // The arguments have been set up on the hot path for op_call_eval
383 if (opcodeID == op_call)
384 compileOpCallSetupArgs(instruction);
385 else if (opcodeID == op_construct)
386 compileOpConstructSetupArgs(instruction);
387
388 // Fast check for JS function.
389 Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
390 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
391
392 // First, in the case of a construct, allocate the new object.
393 if (opcodeID == op_construct) {
394 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
395 emitLoad(callee, regT1, regT0);
396 }
397
398 // Speculatively roll the callframe, assuming argCount will match the arity.
399 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
400 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
401 move(Imm32(argCount), regT1);
402
403 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
404
405 // Put the return value in dst.
406 emitStore(dst, regT1, regT0);;
407 sampleCodeBlock(m_codeBlock);
408
409 // If not, we need an extra case in the if below!
410 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
411
412 // Done! - return back to the hot path.
413 if (opcodeID == op_construct)
414 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
415 else
416 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
417
418 // This handles host functions
419 callLinkFailNotObject.link(this);
420 callLinkFailNotJSFunction.link(this);
421 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
422
423 emitStore(dst, regT1, regT0);;
424 sampleCodeBlock(m_codeBlock);
425 }
426
427 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
428
429 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
430
431 #else // USE(JSVALUE32_64)
432
433 void JIT::compileOpCallInitializeCallFrame()
434 {
435 store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
436
437 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
438
439 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
440 storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
441 storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
442 }
443
444 void JIT::compileOpCallSetupArgs(Instruction* instruction)
445 {
446 int argCount = instruction[3].u.operand;
447 int registerOffset = instruction[4].u.operand;
448
449 // ecx holds func
450 emitPutJITStubArg(regT0, 0);
451 emitPutJITStubArgConstant(argCount, 2);
452 emitPutJITStubArgConstant(registerOffset, 1);
453 }
454
455 void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
456 {
457 int registerOffset = instruction[4].u.operand;
458
459 // ecx holds func
460 emitPutJITStubArg(regT0, 0);
461 emitPutJITStubArg(regT1, 2);
462 addPtr(Imm32(registerOffset), regT1, regT2);
463 emitPutJITStubArg(regT2, 1);
464 }
465
466 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
467 {
468 int argCount = instruction[3].u.operand;
469 int registerOffset = instruction[4].u.operand;
470 int proto = instruction[5].u.operand;
471 int thisRegister = instruction[6].u.operand;
472
473 // ecx holds func
474 emitPutJITStubArg(regT0, 0);
475 emitPutJITStubArgConstant(registerOffset, 1);
476 emitPutJITStubArgConstant(argCount, 2);
477 emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
478 emitPutJITStubArgConstant(thisRegister, 4);
479 }
480
481 void JIT::compileOpCallVarargs(Instruction* instruction)
482 {
483 int dst = instruction[1].u.operand;
484 int callee = instruction[2].u.operand;
485 int argCountRegister = instruction[3].u.operand;
486
487 emitGetVirtualRegister(argCountRegister, regT1);
488 emitGetVirtualRegister(callee, regT0);
489 compileOpCallVarargsSetupArgs(instruction);
490
491 // Check for JSFunctions.
492 emitJumpSlowCaseIfNotJSCell(regT0);
493 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
494
495 // Speculatively roll the callframe, assuming argCount will match the arity.
496 mul32(Imm32(sizeof(Register)), regT2, regT2);
497 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
498 addPtr(Imm32((int32_t)offset), regT2, regT3);
499 addPtr(callFrameRegister, regT3);
500 storePtr(callFrameRegister, regT3);
501 addPtr(regT2, callFrameRegister);
502 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
503
504 // Put the return value in dst. In the interpreter, op_ret does this.
505 emitPutVirtualRegister(dst);
506
507 sampleCodeBlock(m_codeBlock);
508 }
509
510 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
511 {
512 int dst = instruction[1].u.operand;
513
514 linkSlowCase(iter);
515 linkSlowCase(iter);
516 JITStubCall stubCall(this, cti_op_call_NotJSFunction);
517 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
518
519 sampleCodeBlock(m_codeBlock);
520 }
521
522 #if !ENABLE(JIT_OPTIMIZE_CALL)
523
524 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
525
526 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
527 {
528 int dst = instruction[1].u.operand;
529 int callee = instruction[2].u.operand;
530 int argCount = instruction[3].u.operand;
531 int registerOffset = instruction[4].u.operand;
532
533 // Handle eval
534 Jump wasEval;
535 if (opcodeID == op_call_eval) {
536 JITStubCall stubCall(this, cti_op_call_eval);
537 stubCall.addArgument(callee, regT0);
538 stubCall.addArgument(JIT::Imm32(registerOffset));
539 stubCall.addArgument(JIT::Imm32(argCount));
540 stubCall.call();
541 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
542 }
543
544 emitGetVirtualRegister(callee, regT0);
545 // The arguments have been set up on the hot path for op_call_eval
546 if (opcodeID == op_call)
547 compileOpCallSetupArgs(instruction);
548 else if (opcodeID == op_construct)
549 compileOpConstructSetupArgs(instruction);
550
551 // Check for JSFunctions.
552 emitJumpSlowCaseIfNotJSCell(regT0);
553 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
554
555 // First, in the case of a construct, allocate the new object.
556 if (opcodeID == op_construct) {
557 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
558 emitGetVirtualRegister(callee, regT0);
559 }
560
561 // Speculatively roll the callframe, assuming argCount will match the arity.
562 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
563 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
564 move(Imm32(argCount), regT1);
565
566 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
567
568 if (opcodeID == op_call_eval)
569 wasEval.link(this);
570
571 // Put the return value in dst. In the interpreter, op_ret does this.
572 emitPutVirtualRegister(dst);
573
574 sampleCodeBlock(m_codeBlock);
575 }
576
577 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
578 {
579 int dst = instruction[1].u.operand;
580
581 linkSlowCase(iter);
582 linkSlowCase(iter);
583 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
584 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
585
586 sampleCodeBlock(m_codeBlock);
587 }
588
589 #else // !ENABLE(JIT_OPTIMIZE_CALL)
590
591 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
592
593 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
594 {
595 int dst = instruction[1].u.operand;
596 int callee = instruction[2].u.operand;
597 int argCount = instruction[3].u.operand;
598 int registerOffset = instruction[4].u.operand;
599
600 // Handle eval
601 Jump wasEval;
602 if (opcodeID == op_call_eval) {
603 JITStubCall stubCall(this, cti_op_call_eval);
604 stubCall.addArgument(callee, regT0);
605 stubCall.addArgument(JIT::Imm32(registerOffset));
606 stubCall.addArgument(JIT::Imm32(argCount));
607 stubCall.call();
608 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
609 }
610
611 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
612 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
613 emitGetVirtualRegister(callee, regT0);
614 DataLabelPtr addressOfLinkedFunctionCheck;
615
616 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
617
618 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
619
620 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
621
622 addSlowCase(jumpToSlow);
623 ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
624 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
625
626 // The following is the fast case, only used whan a callee can be linked.
627
628 // In the case of OpConstruct, call out to a cti_ function to create the new object.
629 if (opcodeID == op_construct) {
630 int proto = instruction[5].u.operand;
631 int thisRegister = instruction[6].u.operand;
632
633 emitPutJITStubArg(regT0, 0);
634 emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
635 JITStubCall stubCall(this, cti_op_construct_JSConstruct);
636 stubCall.call(thisRegister);
637 emitGetVirtualRegister(callee, regT0);
638 }
639
640 // Fast version of stack frame initialization, directly relative to edi.
641 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
642 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
643 storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
644 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
645 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
646 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
647 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
648 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
649
650 // Call to the callee
651 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
652
653 if (opcodeID == op_call_eval)
654 wasEval.link(this);
655
656 // Put the return value in dst. In the interpreter, op_ret does this.
657 emitPutVirtualRegister(dst);
658
659 sampleCodeBlock(m_codeBlock);
660 }
661
662 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
663 {
664 int dst = instruction[1].u.operand;
665 int callee = instruction[2].u.operand;
666 int argCount = instruction[3].u.operand;
667 int registerOffset = instruction[4].u.operand;
668
669 linkSlowCase(iter);
670
671 // The arguments have been set up on the hot path for op_call_eval
672 if (opcodeID == op_call)
673 compileOpCallSetupArgs(instruction);
674 else if (opcodeID == op_construct)
675 compileOpConstructSetupArgs(instruction);
676
677 // Fast check for JS function.
678 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
679 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
680
681 // First, in the case of a construct, allocate the new object.
682 if (opcodeID == op_construct) {
683 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
684 emitGetVirtualRegister(callee, regT0);
685 }
686
687 // Speculatively roll the callframe, assuming argCount will match the arity.
688 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
689 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
690 move(Imm32(argCount), regT1);
691
692 move(regT0, regT2);
693
694 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
695
696 // Put the return value in dst.
697 emitPutVirtualRegister(dst);
698 sampleCodeBlock(m_codeBlock);
699
700 // If not, we need an extra case in the if below!
701 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
702
703 // Done! - return back to the hot path.
704 if (opcodeID == op_construct)
705 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
706 else
707 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
708
709 // This handles host functions
710 callLinkFailNotObject.link(this);
711 callLinkFailNotJSFunction.link(this);
712 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
713
714 emitPutVirtualRegister(dst);
715 sampleCodeBlock(m_codeBlock);
716 }
717
718 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
719
720 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
721
722 #endif // USE(JSVALUE32_64)
723
724 } // namespace JSC
725
726 #endif // ENABLE(JIT)
727