source: webkit/trunk/JavaScriptCore/jit/JITCall.cpp@ 49328

Last change on this file since 49328 was 49293, checked in by [email protected], 16 years ago

Fix for JIT'ed op_call instructions (evals, constructs, etc.)
when !ENABLE(JIT_OPTIMIZE_CALL) && USE(JSVALUE32_64)

Patch by Zoltan Herczeg <[email protected]> on 2009-10-08
Reviewed by Gavin Barraclough.

https://bugs.webkit.org/show_bug.cgi?id=30201

  • jit/JITCall.cpp:

(JSC::JIT::compileOpCall):

File size: 27.7 KB
Line 
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
44using namespace std;
45
46namespace JSC {
47
48#if USE(JSVALUE32_64)
49
50void 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
62void 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
72void 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
86void JIT::compileOpCallVarargsSetupArgs(Instruction*)
87{
88 emitPutJITStubArg(regT1, regT0, 0);
89 emitPutJITStubArg(regT3, 1); // registerOffset
90 emitPutJITStubArg(regT2, 2); // argCount
91}
92
93void 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
124void 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
139void 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
155void 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
165void 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
176void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
177{
178 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
179}
180
181void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
182{
183 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
184}
185
186void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
187{
188 compileOpCallVarargsSlowCase(currentInstruction, iter);
189}
190
191void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
192{
193 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
194}
195
196void JIT::emit_op_call(Instruction* currentInstruction)
197{
198 compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
199}
200
201void JIT::emit_op_call_eval(Instruction* currentInstruction)
202{
203 compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
204}
205
206void 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
218void JIT::emit_op_call_varargs(Instruction* currentInstruction)
219{
220 compileOpCallVarargs(currentInstruction);
221}
222
223void 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
232void 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
280void 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
298void 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 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0));
319 addSlowCase(jumpToSlow);
320 ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
321 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
322
323 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
324
325 // The following is the fast case, only used whan a callee can be linked.
326
327 // In the case of OpConstruct, call out to a cti_ function to create the new object.
328 if (opcodeID == op_construct) {
329 int proto = instruction[5].u.operand;
330 int thisRegister = instruction[6].u.operand;
331
332 JITStubCall stubCall(this, cti_op_construct_JSConstruct);
333 stubCall.addArgument(regT1, regT0);
334 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
335 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
336 stubCall.addArgument(proto);
337 stubCall.call(thisRegister);
338
339 emitLoad(callee, regT1, regT0);
340 }
341
342 // Fast version of stack frame initialization, directly relative to edi.
343 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
344 emitStore(registerOffset + RegisterFile::OptionalCalleeArguments, JSValue());
345 emitStore(registerOffset + RegisterFile::Callee, regT1, regT0);
346
347 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
348 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
349 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
350 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
351 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
352
353 // Call to the callee
354 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
355
356 if (opcodeID == op_call_eval)
357 wasEval.link(this);
358
359 // Put the return value in dst. In the interpreter, op_ret does this.
360 emitStore(dst, regT1, regT0);
361 map(m_bytecodeIndex + opcodeLengths[opcodeID], dst, regT1, regT0);
362
363 sampleCodeBlock(m_codeBlock);
364}
365
366void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
367{
368 int dst = instruction[1].u.operand;
369 int callee = instruction[2].u.operand;
370 int argCount = instruction[3].u.operand;
371 int registerOffset = instruction[4].u.operand;
372
373 linkSlowCase(iter);
374 linkSlowCase(iter);
375
376 // The arguments have been set up on the hot path for op_call_eval
377 if (opcodeID == op_call)
378 compileOpCallSetupArgs(instruction);
379 else if (opcodeID == op_construct)
380 compileOpConstructSetupArgs(instruction);
381
382 // Fast check for JS function.
383 Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
384 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
385
386 // First, in the case of a construct, allocate the new object.
387 if (opcodeID == op_construct) {
388 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
389 emitLoad(callee, regT1, regT0);
390 }
391
392 // Speculatively roll the callframe, assuming argCount will match the arity.
393 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
394 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
395 move(Imm32(argCount), regT1);
396
397 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
398
399 // Put the return value in dst.
400 emitStore(dst, regT1, regT0);;
401 sampleCodeBlock(m_codeBlock);
402
403 // If not, we need an extra case in the if below!
404 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
405
406 // Done! - return back to the hot path.
407 if (opcodeID == op_construct)
408 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
409 else
410 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
411
412 // This handles host functions
413 callLinkFailNotObject.link(this);
414 callLinkFailNotJSFunction.link(this);
415 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
416
417 emitStore(dst, regT1, regT0);;
418 sampleCodeBlock(m_codeBlock);
419}
420
421/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
422
423#endif // !ENABLE(JIT_OPTIMIZE_CALL)
424
425#else // USE(JSVALUE32_64)
426
427void JIT::compileOpCallInitializeCallFrame()
428{
429 store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
430
431 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
432
433 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
434 storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
435 storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
436}
437
438void JIT::compileOpCallSetupArgs(Instruction* instruction)
439{
440 int argCount = instruction[3].u.operand;
441 int registerOffset = instruction[4].u.operand;
442
443 // ecx holds func
444 emitPutJITStubArg(regT0, 0);
445 emitPutJITStubArgConstant(argCount, 2);
446 emitPutJITStubArgConstant(registerOffset, 1);
447}
448
449void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
450{
451 int registerOffset = instruction[4].u.operand;
452
453 // ecx holds func
454 emitPutJITStubArg(regT0, 0);
455 emitPutJITStubArg(regT1, 2);
456 addPtr(Imm32(registerOffset), regT1, regT2);
457 emitPutJITStubArg(regT2, 1);
458}
459
460void JIT::compileOpConstructSetupArgs(Instruction* instruction)
461{
462 int argCount = instruction[3].u.operand;
463 int registerOffset = instruction[4].u.operand;
464 int proto = instruction[5].u.operand;
465 int thisRegister = instruction[6].u.operand;
466
467 // ecx holds func
468 emitPutJITStubArg(regT0, 0);
469 emitPutJITStubArgConstant(registerOffset, 1);
470 emitPutJITStubArgConstant(argCount, 2);
471 emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
472 emitPutJITStubArgConstant(thisRegister, 4);
473}
474
475void JIT::compileOpCallVarargs(Instruction* instruction)
476{
477 int dst = instruction[1].u.operand;
478 int callee = instruction[2].u.operand;
479 int argCountRegister = instruction[3].u.operand;
480
481 emitGetVirtualRegister(argCountRegister, regT1);
482 emitGetVirtualRegister(callee, regT0);
483 compileOpCallVarargsSetupArgs(instruction);
484
485 // Check for JSFunctions.
486 emitJumpSlowCaseIfNotJSCell(regT0);
487 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
488
489 // Speculatively roll the callframe, assuming argCount will match the arity.
490 mul32(Imm32(sizeof(Register)), regT2, regT2);
491 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
492 addPtr(Imm32((int32_t)offset), regT2, regT3);
493 addPtr(callFrameRegister, regT3);
494 storePtr(callFrameRegister, regT3);
495 addPtr(regT2, callFrameRegister);
496 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
497
498 // Put the return value in dst. In the interpreter, op_ret does this.
499 emitPutVirtualRegister(dst);
500
501 sampleCodeBlock(m_codeBlock);
502}
503
504void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
505{
506 int dst = instruction[1].u.operand;
507
508 linkSlowCase(iter);
509 linkSlowCase(iter);
510 JITStubCall stubCall(this, cti_op_call_NotJSFunction);
511 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
512
513 sampleCodeBlock(m_codeBlock);
514}
515
516#if !ENABLE(JIT_OPTIMIZE_CALL)
517
518/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
519
520void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
521{
522 int dst = instruction[1].u.operand;
523 int callee = instruction[2].u.operand;
524 int argCount = instruction[3].u.operand;
525 int registerOffset = instruction[4].u.operand;
526
527 // Handle eval
528 Jump wasEval;
529 if (opcodeID == op_call_eval) {
530 JITStubCall stubCall(this, cti_op_call_eval);
531 stubCall.addArgument(callee, regT0);
532 stubCall.addArgument(JIT::Imm32(registerOffset));
533 stubCall.addArgument(JIT::Imm32(argCount));
534 stubCall.call();
535 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
536 }
537
538 emitGetVirtualRegister(callee, regT0);
539 // The arguments have been set up on the hot path for op_call_eval
540 if (opcodeID == op_call)
541 compileOpCallSetupArgs(instruction);
542 else if (opcodeID == op_construct)
543 compileOpConstructSetupArgs(instruction);
544
545 // Check for JSFunctions.
546 emitJumpSlowCaseIfNotJSCell(regT0);
547 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
548
549 // First, in the case of a construct, allocate the new object.
550 if (opcodeID == op_construct) {
551 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
552 emitGetVirtualRegister(callee, regT0);
553 }
554
555 // Speculatively roll the callframe, assuming argCount will match the arity.
556 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
557 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
558 move(Imm32(argCount), regT1);
559
560 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
561
562 if (opcodeID == op_call_eval)
563 wasEval.link(this);
564
565 // Put the return value in dst. In the interpreter, op_ret does this.
566 emitPutVirtualRegister(dst);
567
568 sampleCodeBlock(m_codeBlock);
569}
570
571void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
572{
573 int dst = instruction[1].u.operand;
574
575 linkSlowCase(iter);
576 linkSlowCase(iter);
577 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
578 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
579
580 sampleCodeBlock(m_codeBlock);
581}
582
583#else // !ENABLE(JIT_OPTIMIZE_CALL)
584
585/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
586
587void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
588{
589 int dst = instruction[1].u.operand;
590 int callee = instruction[2].u.operand;
591 int argCount = instruction[3].u.operand;
592 int registerOffset = instruction[4].u.operand;
593
594 // Handle eval
595 Jump wasEval;
596 if (opcodeID == op_call_eval) {
597 JITStubCall stubCall(this, cti_op_call_eval);
598 stubCall.addArgument(callee, regT0);
599 stubCall.addArgument(JIT::Imm32(registerOffset));
600 stubCall.addArgument(JIT::Imm32(argCount));
601 stubCall.call();
602 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
603 }
604
605 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
606 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
607 emitGetVirtualRegister(callee, regT0);
608 DataLabelPtr addressOfLinkedFunctionCheck;
609
610 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
611
612 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
613
614 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
615
616 addSlowCase(jumpToSlow);
617 ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
618 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
619
620 // The following is the fast case, only used whan a callee can be linked.
621
622 // In the case of OpConstruct, call out to a cti_ function to create the new object.
623 if (opcodeID == op_construct) {
624 int proto = instruction[5].u.operand;
625 int thisRegister = instruction[6].u.operand;
626
627 emitPutJITStubArg(regT0, 0);
628 emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
629 JITStubCall stubCall(this, cti_op_construct_JSConstruct);
630 stubCall.call(thisRegister);
631 emitGetVirtualRegister(callee, regT0);
632 }
633
634 // Fast version of stack frame initialization, directly relative to edi.
635 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
636 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
637 storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
638 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
639 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
640 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
641 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
642 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
643
644 // Call to the callee
645 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
646
647 if (opcodeID == op_call_eval)
648 wasEval.link(this);
649
650 // Put the return value in dst. In the interpreter, op_ret does this.
651 emitPutVirtualRegister(dst);
652
653 sampleCodeBlock(m_codeBlock);
654}
655
656void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
657{
658 int dst = instruction[1].u.operand;
659 int callee = instruction[2].u.operand;
660 int argCount = instruction[3].u.operand;
661 int registerOffset = instruction[4].u.operand;
662
663 linkSlowCase(iter);
664
665 // The arguments have been set up on the hot path for op_call_eval
666 if (opcodeID == op_call)
667 compileOpCallSetupArgs(instruction);
668 else if (opcodeID == op_construct)
669 compileOpConstructSetupArgs(instruction);
670
671 // Fast check for JS function.
672 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
673 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
674
675 // First, in the case of a construct, allocate the new object.
676 if (opcodeID == op_construct) {
677 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
678 emitGetVirtualRegister(callee, regT0);
679 }
680
681 // Speculatively roll the callframe, assuming argCount will match the arity.
682 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
683 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
684 move(Imm32(argCount), regT1);
685
686 move(regT0, regT2);
687
688 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
689
690 // Put the return value in dst.
691 emitPutVirtualRegister(dst);
692 sampleCodeBlock(m_codeBlock);
693
694 // If not, we need an extra case in the if below!
695 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
696
697 // Done! - return back to the hot path.
698 if (opcodeID == op_construct)
699 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
700 else
701 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
702
703 // This handles host functions
704 callLinkFailNotObject.link(this);
705 callLinkFailNotJSFunction.link(this);
706 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
707
708 emitPutVirtualRegister(dst);
709 sampleCodeBlock(m_codeBlock);
710}
711
712/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
713
714#endif // !ENABLE(JIT_OPTIMIZE_CALL)
715
716#endif // USE(JSVALUE32_64)
717
718} // namespace JSC
719
720#endif // ENABLE(JIT)
Note: See TracBrowser for help on using the repository browser.