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

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

Remove FunctionCodeBlock.
https://bugs.webkit.org/show_bug.cgi?id=28502

Reviewed by Oliver Hunt.

These only exist to allow JIT code to dereference properties off the
CodeBlock for any callee, regardless of whether it is a host function.

Instead just use the FunctionExecutable. Copy the m_parameters field
from the CodeBlock into the Executable, and use this to distinguish
between host functions, functions that have been bytecompiled, and
functions that have not.

m_parameters is moved to ExecutableBase rather than FunctionExecutable
so that (as a separate change) we can move make a separate class of
executable for host code, which is not devived from FunctionExecutable
(host code does not feature any of the properties that normal executable
do and will provide, such as source, attributes, and a parsed name).

1% win on v8 tests, 0.5% on sunspider.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::derefStructures):
(JSC::CodeBlock::refStructures):
(JSC::CodeBlock::reparseForExceptionInfoIfNecessary):
(JSC::CodeBlock::handlerForBytecodeOffset):
(JSC::CodeBlock::lineNumberForBytecodeOffset):
(JSC::CodeBlock::expressionRangeForBytecodeOffset):
(JSC::CodeBlock::getByIdExceptionInfoForBytecodeOffset):
(JSC::CodeBlock::functionRegisterForBytecodeOffset):
(JSC::CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset):
(JSC::CodeBlock::hasGlobalResolveInfoAtBytecodeOffset):

  • bytecode/CodeBlock.h:

(JSC::):
(JSC::CodeBlock::source):
(JSC::CodeBlock::sourceOffset):
(JSC::CodeBlock::evalCodeCache):
(JSC::CodeBlock::createRareDataIfNecessary):

remove NativeCodeBlocks and the NativeCode code type.


  • jit/JIT.cpp:

(JSC::JIT::linkCall):

Revert to previous behaviour (as currently still commented!) that Hhost functions have a null codeblock.

  • jit/JITCall.cpp:

(JSC::JIT::compileOpCallInitializeCallFrame):
(JSC::JIT::compileOpCallSetupArgs):
(JSC::JIT::compileOpCallVarargsSetupArgs):
(JSC::JIT::compileOpConstructSetupArgs):
(JSC::JIT::compileOpCallVarargs):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):

Bring the 32_64 & non-32_64 JITs into line with each other, callee in regT0.

  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):

Rewrite call trampolines to not use the CodeBlock.

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

Make call_JSFunction & call_arityCheck return the callee, don't expect to be passed the CodeBlock.

  • runtime/Executable.cpp:

(JSC::FunctionExecutable::generateBytecode):
(JSC::FunctionExecutable::recompile):
(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/Executable.h:

(JSC::ExecutableBase::):
(JSC::ExecutableBase::ExecutableBase):
(JSC::FunctionExecutable::isHostFunction):

Add m_numParameters.

  • runtime/JSFunction.cpp:

(JSC::JSFunction::~JSFunction):

Only call generatedBytecode() on JSFunctions non-host FunctionExecutables.

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