2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
31 #include "CodeBlock.h"
34 #include "wrec/WREC.h"
40 #if COMPILER(GCC) && PLATFORM(X86)
42 ".globl _ctiTrampoline" "\n"
43 "_ctiTrampoline:" "\n"
46 "subl $0x24, %esp" "\n"
47 "movl $512, %esi" "\n"
48 "call *0x30(%esp)" "\n" //Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code
49 "addl $0x24, %esp" "\n"
56 ".globl _ctiVMThrowTrampoline" "\n"
57 "_ctiVMThrowTrampoline:" "\n"
59 "movl 0x34(%esp), %ecx" "\n" //Ox34 = 0x0D * 4, 0x0D = CTI_ARGS_exec
60 "cmpl $0, 8(%ecx)" "\n"
65 "call __ZN3JSC7Machine12cti_vm_throwEPv" "\n"
66 "addl $0x24, %esp" "\n"
76 __declspec(naked) JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**)
92 __declspec(naked) void ctiVMThrowTrampoline()
96 call JSC::Machine::cti_vm_throw;
109 // get arg puts an arg from the SF register array into a h/w register
110 ALWAYS_INLINE void CTI::emitGetArg(unsigned src, X86Assembler::RegisterID dst)
112 // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
113 if (src < m_codeBlock->constantRegisters.size()) {
114 JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
115 m_jit.movl_i32r(reinterpret_cast<unsigned>(js), dst);
117 m_jit.movl_mr(src * sizeof(Register), X86::edi, dst);
120 // get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
121 ALWAYS_INLINE void CTI::emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch)
123 if (src < m_codeBlock->constantRegisters.size()) {
124 JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
125 m_jit.movl_i32m(reinterpret_cast<unsigned>(js), offset + sizeof(void*), X86::esp);
127 m_jit.movl_mr(src * sizeof(Register), X86::edi, scratch);
128 m_jit.movl_rm(scratch, offset + sizeof(void*), X86::esp);
132 // puts an arg onto the stack, as an arg to a context threaded function.
133 ALWAYS_INLINE void CTI::emitPutArg(X86Assembler::RegisterID src, unsigned offset)
135 m_jit.movl_rm(src, offset + sizeof(void*), X86::esp);
138 ALWAYS_INLINE void CTI::emitPutArgConstant(unsigned value, unsigned offset)
140 m_jit.movl_i32m(value, offset + sizeof(void*), X86::esp);
143 ALWAYS_INLINE JSValue* CTI::getConstantImmediateNumericArg(unsigned src)
145 if (src < m_codeBlock->constantRegisters.size()) {
146 JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
147 return JSImmediate::isNumber(js) ? js : 0;
152 ALWAYS_INLINE void CTI::emitPutCTIParam(X86Assembler::RegisterID from, unsigned name)
154 m_jit.movl_rm(from, name * sizeof(void*), X86::esp);
157 ALWAYS_INLINE void CTI::emitGetCTIParam(unsigned name, X86Assembler::RegisterID to)
159 m_jit.movl_mr(name * sizeof(void*), X86::esp, to);
162 ALWAYS_INLINE void CTI::emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
164 m_jit.movl_rm(from, -((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), X86::edi);
167 ALWAYS_INLINE void CTI::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to)
169 m_jit.movl_mr(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), X86::edi, to);
172 ALWAYS_INLINE void CTI::emitPutResult(unsigned dst, X86Assembler::RegisterID from)
174 m_jit.movl_rm(from, dst * sizeof(Register), X86::edi);
175 // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
178 #if ENABLE(SAMPLING_TOOL)
182 void ctiSetReturnAddress(void** where, void* what)
187 void ctiRepatchCallByReturnAddress(void* where, void* what)
189 (static_cast<void**>(where))[-1] = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(what) - reinterpret_cast<uintptr_t>(where));
194 ALWAYS_INLINE void CTI::emitDebugExceptionCheck()
200 ALWAYS_INLINE void CTI::emitDebugExceptionCheck()
202 emitGetCTIParam(CTI_ARGS_exec, X86::ecx);
203 m_jit.cmpl_i32m(0, OBJECT_OFFSET(ExecState, m_exception), X86::ecx);
204 X86Assembler::JmpSrc noException = m_jit.emitUnlinkedJe();
206 m_jit.link(noException, m_jit.label());
209 void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
212 if (src1 < m_codeBlock->constantRegisters.size()) {
213 JSValue* js = m_codeBlock->constantRegisters[src1].jsValue(m_exec);
215 JSImmediate::isImmediate(js) ?
216 (JSImmediate::isNumber(js) ? 'i' :
217 JSImmediate::isBoolean(js) ? 'b' :
218 js->isUndefined() ? 'u' :
219 js->isNull() ? 'n' : '?')
221 (js->isString() ? 's' :
222 js->isObject() ? 'o' :
226 if (src2 < m_codeBlock->constantRegisters.size()) {
227 JSValue* js = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
229 JSImmediate::isImmediate(js) ?
230 (JSImmediate::isNumber(js) ? 'i' :
231 JSImmediate::isBoolean(js) ? 'b' :
232 js->isUndefined() ? 'u' :
233 js->isNull() ? 'n' : '?')
235 (js->isString() ? 's' :
236 js->isObject() ? 'o' :
239 if ((which1 != '*') | (which2 != '*'))
240 fprintf(stderr, "Types %c %c\n", which1, which2);
245 ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_j helper)
247 #if ENABLE(SAMPLING_TOOL)
248 m_jit.movl_i32m(1, &incall);
250 m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
251 emitDebugExceptionCheck();
252 #if ENABLE(SAMPLING_TOOL)
253 m_jit.movl_i32m(0, &incall);
257 ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_p helper)
259 #if ENABLE(SAMPLING_TOOL)
260 m_jit.movl_i32m(1, &incall);
262 m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
263 emitDebugExceptionCheck();
264 #if ENABLE(SAMPLING_TOOL)
265 m_jit.movl_i32m(0, &incall);
269 ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_b helper)
271 #if ENABLE(SAMPLING_TOOL)
272 m_jit.movl_i32m(1, &incall);
274 m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
275 emitDebugExceptionCheck();
276 #if ENABLE(SAMPLING_TOOL)
277 m_jit.movl_i32m(0, &incall);
281 ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_v helper)
283 #if ENABLE(SAMPLING_TOOL)
284 m_jit.movl_i32m(1, &incall);
286 m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
287 emitDebugExceptionCheck();
288 #if ENABLE(SAMPLING_TOOL)
289 m_jit.movl_i32m(0, &incall);
293 ALWAYS_INLINE void CTI::emitCall(unsigned opcodeIndex, CTIHelper_s helper)
295 #if ENABLE(SAMPLING_TOOL)
296 m_jit.movl_i32m(1, &incall);
298 m_calls.append(CallRecord(m_jit.emitCall(), helper, opcodeIndex));
299 emitDebugExceptionCheck();
300 #if ENABLE(SAMPLING_TOOL)
301 m_jit.movl_i32m(0, &incall);
305 ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID reg, unsigned opcodeIndex)
307 m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, reg);
308 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), opcodeIndex));
311 ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID reg1, X86Assembler::RegisterID reg2, unsigned opcodeIndex)
313 m_jit.movl_rr(reg1, X86::ecx);
314 m_jit.andl_rr(reg2, X86::ecx);
315 emitJumpSlowCaseIfNotImm(X86::ecx, opcodeIndex);
318 ALWAYS_INLINE unsigned CTI::getDeTaggedConstantImmediate(JSValue* imm)
320 ASSERT(JSImmediate::isNumber(imm));
321 return reinterpret_cast<unsigned>(imm) & ~JSImmediate::TagBitTypeInteger;
324 ALWAYS_INLINE void CTI::emitFastArithDeTagImmediate(X86Assembler::RegisterID reg)
326 // op_mod relies on this being a sub - setting zf if result is 0.
327 m_jit.subl_i8r(JSImmediate::TagBitTypeInteger, reg);
330 ALWAYS_INLINE void CTI::emitFastArithReTagImmediate(X86Assembler::RegisterID reg)
332 m_jit.addl_i8r(JSImmediate::TagBitTypeInteger, reg);
335 ALWAYS_INLINE void CTI::emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID reg)
337 m_jit.orl_rr(JSImmediate::TagBitTypeInteger, reg);
340 ALWAYS_INLINE void CTI::emitFastArithImmToInt(X86Assembler::RegisterID reg)
342 m_jit.sarl_i8r(1, reg);
345 ALWAYS_INLINE void CTI::emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID reg, unsigned opcodeIndex)
347 m_jit.addl_rr(reg, reg);
348 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), opcodeIndex));
349 emitFastArithReTagImmediate(reg);
352 ALWAYS_INLINE void CTI::emitFastArithIntToImmNoCheck(X86Assembler::RegisterID reg)
354 m_jit.addl_rr(reg, reg);
355 emitFastArithReTagImmediate(reg);
358 CTI::CTI(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
359 : m_jit(machine->jitCodeBuffer())
362 , m_codeBlock(codeBlock)
363 , m_labels(codeBlock ? codeBlock->instructions.size() : 0)
367 #define CTI_COMPILE_BINARY_OP(name) \
369 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
370 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx); \
371 emitCall(i, Machine::cti_##name); \
372 emitPutResult(instruction[i + 1].u.operand); \
377 #if ENABLE(SAMPLING_TOOL)
378 OpcodeID what = (OpcodeID)-1;
381 void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type)
383 if (type == OpConstruct) {
384 emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 12);
385 emitPutArgConstant(instruction[i + 4].u.operand, 8);
386 emitPutArgConstant(instruction[i + 3].u.operand, 4);
388 emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 16);
389 emitPutArgConstant(instruction[i + 5].u.operand, 12);
390 emitPutArgConstant(instruction[i + 4].u.operand, 8);
391 // FIXME: should this be loaded dynamically off m_exec?
392 int thisVal = instruction[i + 3].u.operand;
393 if (thisVal == missingThisObjectMarker()) {
394 emitPutArgConstant(reinterpret_cast<unsigned>(m_exec->globalThisValue()), 4);
396 emitGetPutArg(thisVal, 4, X86::ecx);
399 X86Assembler::JmpSrc wasEval;
400 if (type == OpCallEval) {
401 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
402 emitCall(i, Machine::cti_op_call_eval);
403 m_jit.emitRestoreArgumentReference();
405 emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
407 m_jit.cmpl_i32r(reinterpret_cast<unsigned>(JSImmediate::impossibleValue()), X86::eax);
408 wasEval = m_jit.emitUnlinkedJne();
410 // this reloads the first arg into ecx (checked just below).
411 emitGetArg(instruction[i + 2].u.operand, X86::ecx);
413 // this sets up the first arg, and explicitly leaves the value in ecx (checked just below).
414 emitGetArg(instruction[i + 2].u.operand, X86::ecx);
415 emitPutArg(X86::ecx, 0);
418 // Fast check for JS function.
419 m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
420 X86Assembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
421 m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
422 X86Assembler::JmpSrc isJSFunction = m_jit.emitUnlinkedJe();
423 m_jit.link(isNotObject, m_jit.label());
425 // This handles host functions
426 emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
427 emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
429 X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
430 m_jit.link(isJSFunction, m_jit.label());
432 // This handles JSFunctions
433 emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction));
434 m_jit.call_r(X86::eax);
435 emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
437 X86Assembler::JmpDst end = m_jit.label();
438 m_jit.link(wasNotJSFunction, end);
439 if (type == OpCallEval)
440 m_jit.link(wasEval, end);
442 emitPutResult(instruction[i + 1].u.operand);
445 void CTI::emitSlowScriptCheck(unsigned opcodeIndex)
447 m_jit.subl_i8r(1, X86::esi);
448 X86Assembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
449 emitCall(opcodeIndex, Machine::cti_timeout_check);
451 emitGetCTIParam(CTI_ARGS_exec, X86::ecx);
452 m_jit.movl_mr(OBJECT_OFFSET(ExecState, m_globalData), X86::ecx, X86::ecx);
453 m_jit.movl_mr(OBJECT_OFFSET(JSGlobalData, machine), X86::ecx, X86::ecx);
454 m_jit.movl_mr(OBJECT_OFFSET(Machine, m_ticksUntilNextTimeoutCheck), X86::ecx, X86::esi);
455 m_jit.link(skipTimeout, m_jit.label());
458 void CTI::privateCompileMainPass()
460 Instruction* instruction = m_codeBlock->instructions.begin();
461 unsigned instructionCount = m_codeBlock->instructions.size();
463 for (unsigned i = 0; i < instructionCount; ) {
464 m_labels[i] = m_jit.label();
466 #if ENABLE(SAMPLING_TOOL)
467 m_jit.movl_i32m(m_machine->getOpcodeID(instruction[i].u.opcode), &what);
470 ASSERT_WITH_MESSAGE(m_machine->isOpcode(instruction[i].u.opcode), "privateCompileMainPass gone bad @ %d", i);
471 m_jit.emitRestoreArgumentReference();
472 switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
474 unsigned src = instruction[i + 2].u.operand;
475 if (src < m_codeBlock->constantRegisters.size())
476 m_jit.movl_i32r(reinterpret_cast<unsigned>(m_codeBlock->constantRegisters[src].jsValue(m_exec)), X86::edx);
478 emitGetArg(src, X86::edx);
479 emitPutResult(instruction[i + 1].u.operand, X86::edx);
484 unsigned dst = instruction[i + 1].u.operand;
485 unsigned src1 = instruction[i + 2].u.operand;
486 unsigned src2 = instruction[i + 3].u.operand;
487 if (src2 < m_codeBlock->constantRegisters.size()) {
488 JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
489 if (JSImmediate::isNumber(value)) {
490 emitGetArg(src1, X86::eax);
491 emitJumpSlowCaseIfNotImm(X86::eax, i);
492 m_jit.addl_i32r(getDeTaggedConstantImmediate(value), X86::eax);
493 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
498 } else if (!(src1 < m_codeBlock->constantRegisters.size())) {
499 emitGetArg(src1, X86::eax);
500 emitGetArg(src2, X86::edx);
501 emitJumpSlowCaseIfNotImms(X86::eax, X86::edx, i);
502 emitFastArithDeTagImmediate(X86::eax);
503 m_jit.addl_rr(X86::edx, X86::eax);
504 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
509 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
510 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
511 emitCall(i, Machine::cti_op_add);
512 emitPutResult(instruction[i + 1].u.operand);
517 if (m_codeBlock->needsFullScopeChain)
518 emitCall(i, Machine::cti_op_end);
519 emitGetArg(instruction[i + 1].u.operand, X86::eax);
520 #if ENABLE(SAMPLING_TOOL)
521 m_jit.movl_i32m(-1, &what);
523 m_jit.pushl_m(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - RegisterFile::CTIReturnEIP) * sizeof(Register), X86::edi);
529 unsigned target = instruction[i + 1].u.operand;
530 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
535 int srcDst = instruction[i + 1].u.operand;
536 emitGetArg(srcDst, X86::eax);
537 emitJumpSlowCaseIfNotImm(X86::eax, i);
538 m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
539 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
540 emitPutResult(srcDst, X86::eax);
545 emitSlowScriptCheck(i);
547 unsigned target = instruction[i + 1].u.operand;
548 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
552 case op_loop_if_less: {
553 emitSlowScriptCheck(i);
555 unsigned target = instruction[i + 3].u.operand;
556 JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
558 emitGetArg(instruction[i + 1].u.operand, X86::edx);
559 emitJumpSlowCaseIfNotImm(X86::edx, i);
560 m_jit.cmpl_i32r(reinterpret_cast<unsigned>(src2imm), X86::edx);
561 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
563 emitGetArg(instruction[i + 1].u.operand, X86::eax);
564 emitGetArg(instruction[i + 2].u.operand, X86::edx);
565 emitJumpSlowCaseIfNotImm(X86::eax, i);
566 emitJumpSlowCaseIfNotImm(X86::edx, i);
567 m_jit.cmpl_rr(X86::edx, X86::eax);
568 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
573 case op_new_object: {
574 emitCall(i, Machine::cti_op_new_object);
575 emitPutResult(instruction[i + 1].u.operand);
580 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
581 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
582 emitGetArg(instruction[i + 1].u.operand, X86::eax);
583 emitGetArg(instruction[i + 3].u.operand, X86::edx);
584 emitPutArg(X86::eax, 0); // leave the base in eax
585 emitPutArg(X86::edx, 8); // leave the base in edx
586 emitCall(i, Machine::cti_op_put_by_id);
591 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
592 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
593 emitGetArg(instruction[i + 2].u.operand, X86::eax);
594 emitPutArg(X86::eax, 0); // leave the base in eax
595 emitCall(i, Machine::cti_op_get_by_id);
596 emitPutResult(instruction[i + 1].u.operand);
600 case op_instanceof: {
601 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
602 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
603 emitCall(i, Machine::cti_op_instanceof);
604 emitPutResult(instruction[i + 1].u.operand);
609 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
610 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
611 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
612 emitCall(i, Machine::cti_op_del_by_id);
613 emitPutResult(instruction[i + 1].u.operand);
617 CTI_COMPILE_BINARY_OP(op_mul);
619 FuncDeclNode* func = (m_codeBlock->functions[instruction[i + 2].u.operand]).get();
620 emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
621 emitCall(i, Machine::cti_op_new_func);
622 emitPutResult(instruction[i + 1].u.operand);
627 compileOpCall(instruction, i);
631 case op_get_global_var: {
632 JSVariableObject* globalObject = static_cast<JSVariableObject*>(instruction[i + 2].u.jsCell);
633 m_jit.movl_i32r(reinterpret_cast<unsigned>(globalObject), X86::eax);
634 emitGetVariableObjectRegister(X86::eax, instruction[i + 3].u.operand, X86::eax);
635 emitPutResult(instruction[i + 1].u.operand, X86::eax);
639 case op_put_global_var: {
640 JSVariableObject* globalObject = static_cast<JSVariableObject*>(instruction[i + 1].u.jsCell);
641 m_jit.movl_i32r(reinterpret_cast<unsigned>(globalObject), X86::eax);
642 emitGetArg(instruction[i + 3].u.operand, X86::edx);
643 emitPutVariableObjectRegister(X86::edx, X86::eax, instruction[i + 2].u.operand);
647 case op_get_scoped_var: {
648 int skip = instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain;
650 emitGetCTIParam(CTI_ARGS_scopeChain, X86::eax);
652 m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, next), X86::eax, X86::eax);
654 m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, object), X86::eax, X86::eax);
655 emitGetVariableObjectRegister(X86::eax, instruction[i + 2].u.operand, X86::eax);
656 emitPutResult(instruction[i + 1].u.operand);
660 case op_put_scoped_var: {
661 int skip = instruction[i + 2].u.operand + m_codeBlock->needsFullScopeChain;
663 emitGetCTIParam(CTI_ARGS_scopeChain, X86::edx);
664 emitGetArg(instruction[i + 3].u.operand, X86::eax);
666 m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, next), X86::edx, X86::edx);
668 m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, object), X86::edx, X86::edx);
669 emitPutVariableObjectRegister(X86::eax, X86::edx, instruction[i + 1].u.operand);
674 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
675 emitCall(i, Machine::cti_op_ret);
677 m_jit.pushl_m(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - RegisterFile::CTIReturnEIP) * sizeof(Register), X86::edi);
683 m_jit.leal_mr(sizeof(Register) * instruction[i + 2].u.operand, X86::edi, X86::edx);
684 emitPutArg(X86::edx, 0);
685 emitPutArgConstant(instruction[i + 3].u.operand, 4);
686 emitCall(i, Machine::cti_op_new_array);
687 emitPutResult(instruction[i + 1].u.operand);
692 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
693 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
694 emitCall(i, Machine::cti_op_resolve);
695 emitPutResult(instruction[i + 1].u.operand);
700 compileOpCall(instruction, i, OpConstruct);
704 case op_get_by_val: {
705 emitGetArg(instruction[i + 2].u.operand, X86::eax);
706 emitGetArg(instruction[i + 3].u.operand, X86::edx);
707 emitJumpSlowCaseIfNotImm(X86::edx, i);
708 emitFastArithImmToInt(X86::edx);
709 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
710 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
711 m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
712 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
713 m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), X86::eax);
714 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
716 m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::eax);
717 m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::eax, X86::edx, sizeof(JSValue*), X86::eax);
718 emitPutResult(instruction[i + 1].u.operand);
722 case op_resolve_func: {
723 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
724 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
725 emitCall(i, Machine::cti_op_resolve_func);
726 emitPutResult(instruction[i + 1].u.operand);
727 emitGetCTIParam(CTI_ARGS_2ndResult, X86::eax);
728 emitPutResult(instruction[i + 2].u.operand);
733 emitGetArg(instruction[i + 2].u.operand, X86::eax);
734 emitGetArg(instruction[i + 3].u.operand, X86::edx);
735 emitJumpSlowCaseIfNotImms(X86::eax, X86::edx, i);
736 m_jit.subl_rr(X86::edx, X86::eax);
737 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
738 emitFastArithReTagImmediate(X86::eax);
739 emitPutResult(instruction[i + 1].u.operand);
743 case op_put_by_val: {
744 emitGetArg(instruction[i + 1].u.operand, X86::eax);
745 emitGetArg(instruction[i + 2].u.operand, X86::edx);
746 emitGetArg(instruction[i + 3].u.operand, X86::ecx);
747 emitJumpSlowCaseIfNotImm(X86::edx, i);
748 emitFastArithImmToInt(X86::edx);
749 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
750 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
751 m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
752 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
753 m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), X86::eax);
754 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
756 m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::eax);
757 m_jit.movl_rm(X86::ecx, OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::eax, X86::edx, sizeof(JSValue*));
761 CTI_COMPILE_BINARY_OP(op_lesseq)
762 case op_loop_if_true: {
763 emitSlowScriptCheck(i);
765 unsigned target = instruction[i + 2].u.operand;
766 emitGetArg(instruction[i + 1].u.operand, X86::eax);
768 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::eax);
769 X86Assembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
770 m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
771 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
773 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
774 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
775 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
776 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
778 m_jit.link(isZero, m_jit.label());
782 case op_resolve_base: {
783 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
784 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
785 emitCall(i, Machine::cti_op_resolve_base);
786 emitPutResult(instruction[i + 1].u.operand);
791 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
792 emitCall(i, Machine::cti_op_negate);
793 emitPutResult(instruction[i + 1].u.operand);
797 case op_resolve_skip: {
798 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
799 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
800 emitPutArgConstant(instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain, 4);
801 emitCall(i, Machine::cti_op_resolve_skip);
802 emitPutResult(instruction[i + 1].u.operand);
806 CTI_COMPILE_BINARY_OP(op_div)
808 int srcDst = instruction[i + 1].u.operand;
809 emitGetArg(srcDst, X86::eax);
810 emitJumpSlowCaseIfNotImm(X86::eax, i);
811 m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
812 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
813 emitPutResult(srcDst, X86::eax);
818 unsigned target = instruction[i + 3].u.operand;
819 JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
821 emitGetArg(instruction[i + 1].u.operand, X86::edx);
822 emitJumpSlowCaseIfNotImm(X86::edx, i);
823 m_jit.cmpl_i32r(reinterpret_cast<unsigned>(src2imm), X86::edx);
824 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
826 emitGetArg(instruction[i + 1].u.operand, X86::eax);
827 emitGetArg(instruction[i + 2].u.operand, X86::edx);
828 emitJumpSlowCaseIfNotImm(X86::eax, i);
829 emitJumpSlowCaseIfNotImm(X86::edx, i);
830 m_jit.cmpl_rr(X86::edx, X86::eax);
831 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
837 emitGetArg(instruction[i + 2].u.operand, X86::eax);
838 m_jit.xorl_i8r(JSImmediate::FullTagTypeBool, X86::eax);
839 m_jit.testl_i32r(JSImmediate::FullTagTypeMask, X86::eax); // i8?
840 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
841 m_jit.xorl_i8r((JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue), X86::eax);
842 emitPutResult(instruction[i + 1].u.operand);
847 unsigned target = instruction[i + 2].u.operand;
848 emitGetArg(instruction[i + 1].u.operand, X86::eax);
850 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::eax);
851 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
852 m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
853 X86Assembler::JmpSrc isNonZero = m_jit.emitUnlinkedJne();
855 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
856 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
857 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
858 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
860 m_jit.link(isNonZero, m_jit.label());
865 int srcDst = instruction[i + 2].u.operand;
866 emitGetArg(srcDst, X86::eax);
867 m_jit.movl_rr(X86::eax, X86::edx);
868 emitJumpSlowCaseIfNotImm(X86::eax, i);
869 m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::edx);
870 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
871 emitPutResult(srcDst, X86::edx);
872 emitPutResult(instruction[i + 1].u.operand);
876 case op_unexpected_load: {
877 JSValue* v = m_codeBlock->unexpectedConstants[instruction[i + 2].u.operand];
878 m_jit.movl_i32r(reinterpret_cast<unsigned>(v), X86::eax);
879 emitPutResult(instruction[i + 1].u.operand);
884 int retAddrDst = instruction[i + 1].u.operand;
885 int target = instruction[i + 2].u.operand;
886 m_jit.movl_i32m(0, sizeof(Register) * retAddrDst, X86::edi);
887 X86Assembler::JmpDst addrPosition = m_jit.label();
888 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
889 X86Assembler::JmpDst sretTarget = m_jit.label();
890 m_jsrSites.append(JSRInfo(addrPosition, sretTarget));
895 m_jit.jmp_m(sizeof(Register) * instruction[i + 1].u.operand, X86::edi);
899 CTI_COMPILE_BINARY_OP(op_eq)
901 emitGetArg(instruction[i + 2].u.operand, X86::eax);
902 emitGetArg(instruction[i + 3].u.operand, X86::ecx);
903 emitJumpSlowCaseIfNotImm(X86::eax, i);
904 emitJumpSlowCaseIfNotImm(X86::ecx, i);
905 emitFastArithImmToInt(X86::eax);
906 emitFastArithImmToInt(X86::ecx);
907 m_jit.shll_CLr(X86::eax);
908 emitFastArithIntToImmOrSlowCase(X86::eax, i);
909 emitPutResult(instruction[i + 1].u.operand);
914 unsigned src1 = instruction[i + 2].u.operand;
915 unsigned src2 = instruction[i + 3].u.operand;
916 unsigned dst = instruction[i + 1].u.operand;
917 if (JSValue* value = getConstantImmediateNumericArg(src1)) {
918 emitGetArg(src2, X86::eax);
919 emitJumpSlowCaseIfNotImm(X86::eax, i);
920 m_jit.andl_i32r(reinterpret_cast<unsigned>(value), X86::eax); // FIXME: make it more obvious this is relying on the format of JSImmediate
922 } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
923 emitGetArg(src1, X86::eax);
924 emitJumpSlowCaseIfNotImm(X86::eax, i);
925 m_jit.andl_i32r(reinterpret_cast<unsigned>(value), X86::eax);
928 emitGetArg(src1, X86::eax);
929 emitGetArg(src2, X86::edx);
930 m_jit.andl_rr(X86::edx, X86::eax);
931 emitJumpSlowCaseIfNotImm(X86::eax, i);
938 emitGetArg(instruction[i + 2].u.operand, X86::eax);
939 emitGetArg(instruction[i + 3].u.operand, X86::ecx);
940 emitJumpSlowCaseIfNotImm(X86::eax, i);
941 emitJumpSlowCaseIfNotImm(X86::ecx, i);
942 emitFastArithImmToInt(X86::ecx);
943 m_jit.sarl_CLr(X86::eax);
944 emitFastArithPotentiallyReTagImmediate(X86::eax);
945 emitPutResult(instruction[i + 1].u.operand);
950 emitGetArg(instruction[i + 2].u.operand, X86::eax);
951 emitJumpSlowCaseIfNotImm(X86::eax, i);
952 m_jit.xorl_i8r(~JSImmediate::TagBitTypeInteger, X86::eax);
953 emitPutResult(instruction[i + 1].u.operand);
957 case op_resolve_with_base: {
958 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
959 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
960 emitCall(i, Machine::cti_op_resolve_with_base);
961 emitPutResult(instruction[i + 1].u.operand);
962 emitGetCTIParam(CTI_ARGS_2ndResult, X86::eax);
963 emitPutResult(instruction[i + 2].u.operand);
967 case op_new_func_exp: {
968 FuncExprNode* func = (m_codeBlock->functionExpressions[instruction[i + 2].u.operand]).get();
969 emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
970 emitCall(i, Machine::cti_op_new_func_exp);
971 emitPutResult(instruction[i + 1].u.operand);
976 emitGetArg(instruction[i + 2].u.operand, X86::eax);
977 emitGetArg(instruction[i + 3].u.operand, X86::ecx);
978 emitJumpSlowCaseIfNotImm(X86::eax, i);
979 emitJumpSlowCaseIfNotImm(X86::ecx, i);
980 emitFastArithDeTagImmediate(X86::eax);
981 emitFastArithDeTagImmediate(X86::ecx);
982 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i)); // This is checking if the last detag resulted in a value 0.
984 m_jit.idivl_r(X86::ecx);
985 emitFastArithReTagImmediate(X86::edx);
986 m_jit.movl_rr(X86::edx, X86::eax);
987 emitPutResult(instruction[i + 1].u.operand);
992 unsigned target = instruction[i + 2].u.operand;
993 emitGetArg(instruction[i + 1].u.operand, X86::eax);
995 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::eax);
996 X86Assembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
997 m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
998 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
1000 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
1001 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
1002 m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
1003 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
1005 m_jit.link(isZero, m_jit.label());
1009 CTI_COMPILE_BINARY_OP(op_less)
1010 CTI_COMPILE_BINARY_OP(op_neq)
1012 int srcDst = instruction[i + 2].u.operand;
1013 emitGetArg(srcDst, X86::eax);
1014 m_jit.movl_rr(X86::eax, X86::edx);
1015 emitJumpSlowCaseIfNotImm(X86::eax, i);
1016 m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::edx);
1017 m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
1018 emitPutResult(srcDst, X86::edx);
1019 emitPutResult(instruction[i + 1].u.operand);
1023 CTI_COMPILE_BINARY_OP(op_urshift)
1025 emitGetArg(instruction[i + 2].u.operand, X86::eax);
1026 emitGetArg(instruction[i + 3].u.operand, X86::edx);
1027 emitJumpSlowCaseIfNotImms(X86::eax, X86::edx, i);
1028 m_jit.xorl_rr(X86::edx, X86::eax);
1029 emitFastArithReTagImmediate(X86::eax);
1030 emitPutResult(instruction[i + 1].u.operand);
1034 case op_new_regexp: {
1035 RegExp* regExp = m_codeBlock->regexps[instruction[i + 2].u.operand].get();
1036 emitPutArgConstant(reinterpret_cast<unsigned>(regExp), 0);
1037 emitCall(i, Machine::cti_op_new_regexp);
1038 emitPutResult(instruction[i + 1].u.operand);
1043 emitGetArg(instruction[i + 2].u.operand, X86::eax);
1044 emitGetArg(instruction[i + 3].u.operand, X86::edx);
1045 emitJumpSlowCaseIfNotImms(X86::eax, X86::edx, i);
1046 m_jit.orl_rr(X86::edx, X86::eax);
1047 emitPutResult(instruction[i + 1].u.operand);
1051 case op_call_eval: {
1052 compileOpCall(instruction, i, OpCallEval);
1057 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
1058 emitCall(i, Machine::cti_op_throw);
1059 m_jit.addl_i8r(0x24, X86::esp);
1060 m_jit.popl_r(X86::edi);
1061 m_jit.popl_r(X86::esi);
1066 case op_get_pnames: {
1067 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1068 emitCall(i, Machine::cti_op_get_pnames);
1069 emitPutResult(instruction[i + 1].u.operand);
1073 case op_next_pname: {
1074 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1075 unsigned target = instruction[i + 3].u.operand;
1076 emitCall(i, Machine::cti_op_next_pname);
1077 m_jit.testl_rr(X86::eax, X86::eax);
1078 X86Assembler::JmpSrc endOfIter = m_jit.emitUnlinkedJe();
1079 emitPutResult(instruction[i + 1].u.operand);
1080 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 3 + target));
1081 m_jit.link(endOfIter, m_jit.label());
1085 case op_push_scope: {
1086 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
1087 emitCall(i, Machine::cti_op_push_scope);
1091 case op_pop_scope: {
1092 emitCall(i, Machine::cti_op_pop_scope);
1097 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1098 emitCall(i, Machine::cti_op_typeof);
1099 emitPutResult(instruction[i + 1].u.operand);
1103 CTI_COMPILE_BINARY_OP(op_stricteq)
1104 CTI_COMPILE_BINARY_OP(op_nstricteq)
1105 case op_to_jsnumber: {
1106 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1107 emitCall(i, Machine::cti_op_to_jsnumber);
1108 emitPutResult(instruction[i + 1].u.operand);
1113 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1114 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
1115 emitCall(i, Machine::cti_op_in);
1116 emitPutResult(instruction[i + 1].u.operand);
1120 case op_push_new_scope: {
1121 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
1122 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
1123 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
1124 emitCall(i, Machine::cti_op_push_new_scope);
1125 emitPutResult(instruction[i + 1].u.operand);
1130 emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
1131 emitGetCTIParam(CTI_ARGS_exec, X86::ecx);
1132 m_jit.movl_mr(OBJECT_OFFSET(ExecState, m_exception), X86::ecx, X86::eax);
1133 m_jit.movl_i32m(0, OBJECT_OFFSET(ExecState, m_exception), X86::ecx);
1134 emitPutResult(instruction[i + 1].u.operand);
1138 case op_jmp_scopes: {
1139 unsigned count = instruction[i + 1].u.operand;
1140 emitPutArgConstant(count, 0);
1141 emitCall(i, Machine::cti_op_jmp_scopes);
1142 unsigned target = instruction[i + 2].u.operand;
1143 m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
1147 case op_put_by_index: {
1148 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
1149 emitPutArgConstant(instruction[i + 2].u.operand, 4);
1150 emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
1151 emitCall(i, Machine::cti_op_put_by_index);
1155 case op_switch_imm: {
1156 unsigned tableIndex = instruction[i + 1].u.operand;
1157 unsigned defaultOffset = instruction[i + 2].u.operand;
1158 unsigned scrutinee = instruction[i + 3].u.operand;
1160 // create jump table for switch destinations, track this switch statement.
1161 SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTables[tableIndex];
1162 m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Immediate));
1163 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1165 emitGetPutArg(scrutinee, 0, X86::ecx);
1166 emitPutArgConstant(tableIndex, 4);
1167 emitCall(i, Machine::cti_op_switch_imm);
1168 m_jit.jmp_r(X86::eax);
1172 case op_switch_char: {
1173 unsigned tableIndex = instruction[i + 1].u.operand;
1174 unsigned defaultOffset = instruction[i + 2].u.operand;
1175 unsigned scrutinee = instruction[i + 3].u.operand;
1177 // create jump table for switch destinations, track this switch statement.
1178 SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTables[tableIndex];
1179 m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Character));
1180 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1182 emitGetPutArg(scrutinee, 0, X86::ecx);
1183 emitPutArgConstant(tableIndex, 4);
1184 emitCall(i, Machine::cti_op_switch_char);
1185 m_jit.jmp_r(X86::eax);
1189 case op_switch_string: {
1190 unsigned tableIndex = instruction[i + 1].u.operand;
1191 unsigned defaultOffset = instruction[i + 2].u.operand;
1192 unsigned scrutinee = instruction[i + 3].u.operand;
1194 // create jump table for switch destinations, track this switch statement.
1195 StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTables[tableIndex];
1196 m_switches.append(SwitchRecord(jumpTable, i, defaultOffset));
1198 emitGetPutArg(scrutinee, 0, X86::ecx);
1199 emitPutArgConstant(tableIndex, 4);
1200 emitCall(i, Machine::cti_op_switch_string);
1201 m_jit.jmp_r(X86::eax);
1205 case op_del_by_val: {
1206 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1207 emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
1208 emitCall(i, Machine::cti_op_del_by_val);
1209 emitPutResult(instruction[i + 1].u.operand);
1213 case op_put_getter: {
1214 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
1215 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
1216 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
1217 emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
1218 emitCall(i, Machine::cti_op_put_getter);
1222 case op_put_setter: {
1223 emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
1224 Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
1225 emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
1226 emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
1227 emitCall(i, Machine::cti_op_put_setter);
1231 case op_new_error: {
1232 JSValue* message = m_codeBlock->unexpectedConstants[instruction[i + 3].u.operand];
1233 emitPutArgConstant(instruction[i + 2].u.operand, 0);
1234 emitPutArgConstant(reinterpret_cast<unsigned>(message), 4);
1235 emitPutArgConstant(m_codeBlock->lineNumberForVPC(&instruction[i]), 8);
1236 emitCall(i, Machine::cti_op_new_error);
1237 emitPutResult(instruction[i + 1].u.operand);
1242 emitPutArgConstant(instruction[i + 1].u.operand, 0);
1243 emitPutArgConstant(instruction[i + 2].u.operand, 4);
1244 emitPutArgConstant(instruction[i + 3].u.operand, 8);
1245 emitCall(i, Machine::cti_op_debug);
1250 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1251 emitCall(i, Machine::cti_op_eq_null);
1252 emitPutResult(instruction[i + 1].u.operand);
1257 emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
1258 emitCall(i, Machine::cti_op_neq_null);
1259 emitPutResult(instruction[i + 1].u.operand);
1263 case op_get_array_length:
1264 case op_get_by_id_chain:
1265 case op_get_by_id_generic:
1266 case op_get_by_id_proto:
1267 case op_get_by_id_self:
1268 case op_get_string_length:
1269 case op_put_by_id_generic:
1270 case op_put_by_id_replace:
1271 ASSERT_NOT_REACHED();
1277 void CTI::privateCompileLinkPass()
1279 unsigned jmpTableCount = m_jmpTable.size();
1280 for (unsigned i = 0; i < jmpTableCount; ++i)
1281 m_jit.link(m_jmpTable[i].from, m_labels[m_jmpTable[i].to]);
1285 void CTI::privateCompileSlowCases()
1287 Instruction* instruction = m_codeBlock->instructions.begin();
1288 for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end(); ++iter) {
1290 m_jit.emitRestoreArgumentReference();
1291 switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
1293 unsigned dst = instruction[i + 1].u.operand;
1294 unsigned src2 = instruction[i + 3].u.operand;
1295 if (src2 < m_codeBlock->constantRegisters.size()) {
1296 JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
1297 if (JSImmediate::isNumber(value)) {
1298 X86Assembler::JmpSrc notImm = iter->from;
1299 m_jit.link((++iter)->from, m_jit.label());
1300 m_jit.subl_i32r(getDeTaggedConstantImmediate(value), X86::eax);
1301 m_jit.link(notImm, m_jit.label());
1302 emitPutArg(X86::eax, 0);
1303 emitGetPutArg(src2, 4, X86::ecx);
1304 emitCall(i, Machine::cti_op_add);
1311 ASSERT(!(static_cast<unsigned>(instruction[i + 2].u.operand) < m_codeBlock->constantRegisters.size()));
1313 X86Assembler::JmpSrc notImm = iter->from;
1314 m_jit.link((++iter)->from, m_jit.label());
1315 m_jit.subl_rr(X86::edx, X86::eax);
1316 emitFastArithReTagImmediate(X86::eax);
1317 m_jit.link(notImm, m_jit.label());
1318 emitPutArg(X86::eax, 0);
1319 emitPutArg(X86::edx, 4);
1320 emitCall(i, Machine::cti_op_add);
1325 case op_get_by_val: {
1326 X86Assembler::JmpSrc notImm = iter->from;
1327 m_jit.link((++iter)->from, m_jit.label());
1328 m_jit.link((++iter)->from, m_jit.label());
1329 m_jit.link((++iter)->from, m_jit.label());
1330 emitFastArithIntToImmNoCheck(X86::edx);
1331 m_jit.link(notImm, m_jit.label());
1332 emitPutArg(X86::eax, 0);
1333 emitPutArg(X86::edx, 4);
1334 emitCall(i, Machine::cti_op_get_by_val);
1335 emitPutResult(instruction[i + 1].u.operand);
1340 X86Assembler::JmpSrc notImm = iter->from;
1341 m_jit.link((++iter)->from, m_jit.label());
1342 m_jit.addl_rr(X86::edx, X86::eax);
1343 m_jit.link(notImm, m_jit.label());
1344 emitPutArg(X86::eax, 0);
1345 emitPutArg(X86::edx, 4);
1346 emitCall(i, Machine::cti_op_sub);
1347 emitPutResult(instruction[i + 1].u.operand);
1352 m_jit.link(iter->from, m_jit.label());
1353 m_jit.link((++iter)->from, m_jit.label());
1354 emitPutArg(X86::eax, 0);
1355 emitPutArg(X86::ecx, 4);
1356 emitCall(i, Machine::cti_op_rshift);
1357 emitPutResult(instruction[i + 1].u.operand);
1362 X86Assembler::JmpSrc notImm1 = iter->from;
1363 X86Assembler::JmpSrc notImm2 = (++iter)->from;
1364 m_jit.link((++iter)->from, m_jit.label());
1365 emitGetArg(instruction[i + 2].u.operand, X86::eax);
1366 emitGetArg(instruction[i + 3].u.operand, X86::ecx);
1367 m_jit.link(notImm1, m_jit.label());
1368 m_jit.link(notImm2, m_jit.label());
1369 emitPutArg(X86::eax, 0);
1370 emitPutArg(X86::ecx, 4);
1371 emitCall(i, Machine::cti_op_lshift);
1372 emitPutResult(instruction[i + 1].u.operand);
1376 case op_loop_if_less: {
1377 emitSlowScriptCheck(i);
1379 unsigned target = instruction[i + 3].u.operand;
1380 JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
1382 m_jit.link(iter->from, m_jit.label());
1383 emitPutArg(X86::edx, 0);
1384 emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
1385 emitCall(i, Machine::cti_op_loop_if_less);
1386 m_jit.testl_rr(X86::eax, X86::eax);
1387 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
1389 m_jit.link(iter->from, m_jit.label());
1390 m_jit.link((++iter)->from, m_jit.label());
1391 emitPutArg(X86::eax, 0);
1392 emitPutArg(X86::edx, 4);
1393 emitCall(i, Machine::cti_op_loop_if_less);
1394 m_jit.testl_rr(X86::eax, X86::eax);
1395 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
1401 unsigned srcDst = instruction[i + 1].u.operand;
1402 X86Assembler::JmpSrc notImm = iter->from;
1403 m_jit.link((++iter)->from, m_jit.label());
1404 m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
1405 m_jit.link(notImm, m_jit.label());
1406 emitPutArg(X86::eax, 0);
1407 emitCall(i, Machine::cti_op_pre_inc);
1408 emitPutResult(srcDst);
1412 case op_put_by_val: {
1413 X86Assembler::JmpSrc notImm = iter->from;
1414 m_jit.link((++iter)->from, m_jit.label());
1415 m_jit.link((++iter)->from, m_jit.label());
1416 m_jit.link((++iter)->from, m_jit.label());
1417 emitFastArithIntToImmNoCheck(X86::edx);
1418 m_jit.link(notImm, m_jit.label());
1419 emitPutArg(X86::eax, 0);
1420 emitPutArg(X86::edx, 4);
1421 emitPutArg(X86::ecx, 8);
1422 emitCall(i, Machine::cti_op_put_by_val);
1426 case op_loop_if_true: {
1427 emitSlowScriptCheck(i);
1429 m_jit.link(iter->from, m_jit.label());
1430 emitPutArg(X86::eax, 0);
1431 emitCall(i, Machine::cti_op_jtrue);
1432 m_jit.testl_rr(X86::eax, X86::eax);
1433 unsigned target = instruction[i + 2].u.operand;
1434 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
1439 unsigned srcDst = instruction[i + 1].u.operand;
1440 X86Assembler::JmpSrc notImm = iter->from;
1441 m_jit.link((++iter)->from, m_jit.label());
1442 m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
1443 m_jit.link(notImm, m_jit.label());
1444 emitPutArg(X86::eax, 0);
1445 emitCall(i, Machine::cti_op_pre_dec);
1446 emitPutResult(srcDst);
1451 unsigned target = instruction[i + 3].u.operand;
1452 JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
1454 m_jit.link(iter->from, m_jit.label());
1455 emitPutArg(X86::edx, 0);
1456 emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
1457 emitCall(i, Machine::cti_op_jless);
1458 m_jit.testl_rr(X86::eax, X86::eax);
1459 m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
1461 m_jit.link(iter->from, m_jit.label());
1462 m_jit.link((++iter)->from, m_jit.label());
1463 emitPutArg(X86::eax, 0);
1464 emitPutArg(X86::edx, 4);
1465 emitCall(i, Machine::cti_op_jless);
1466 m_jit.testl_rr(X86::eax, X86::eax);
1467 m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
1473 m_jit.link(iter->from, m_jit.label());
1474 m_jit.xorl_i8r(JSImmediate::FullTagTypeBool, X86::eax);
1475 emitPutArg(X86::eax, 0);
1476 emitCall(i, Machine::cti_op_not);
1477 emitPutResult(instruction[i + 1].u.operand);
1482 m_jit.link(iter->from, m_jit.label());
1483 emitPutArg(X86::eax, 0);
1484 emitCall(i, Machine::cti_op_jtrue);
1485 m_jit.testl_rr(X86::eax, X86::eax);
1486 unsigned target = instruction[i + 2].u.operand;
1487 m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 2 + target]); // inverted!
1492 unsigned srcDst = instruction[i + 2].u.operand;
1493 m_jit.link(iter->from, m_jit.label());
1494 m_jit.link((++iter)->from, m_jit.label());
1495 emitPutArg(X86::eax, 0);
1496 emitCall(i, Machine::cti_op_post_inc);
1497 emitPutResult(instruction[i + 1].u.operand);
1498 emitGetCTIParam(CTI_ARGS_2ndResult, X86::eax);
1499 emitPutResult(srcDst);
1504 m_jit.link(iter->from, m_jit.label());
1505 emitPutArg(X86::eax, 0);
1506 emitCall(i, Machine::cti_op_bitnot);
1507 emitPutResult(instruction[i + 1].u.operand);
1512 unsigned src1 = instruction[i + 2].u.operand;
1513 unsigned src2 = instruction[i + 3].u.operand;
1514 unsigned dst = instruction[i + 1].u.operand;
1515 if (getConstantImmediateNumericArg(src1)) {
1516 m_jit.link(iter->from, m_jit.label());
1517 emitGetPutArg(src1, 0, X86::ecx);
1518 emitPutArg(X86::eax, 4);
1519 emitCall(i, Machine::cti_op_bitand);
1521 } else if (getConstantImmediateNumericArg(src2)) {
1522 m_jit.link(iter->from, m_jit.label());
1523 emitPutArg(X86::eax, 0);
1524 emitGetPutArg(src2, 4, X86::ecx);
1525 emitCall(i, Machine::cti_op_bitand);
1528 m_jit.link(iter->from, m_jit.label());
1529 emitGetPutArg(src1, 0, X86::ecx);
1530 emitPutArg(X86::edx, 4);
1531 emitCall(i, Machine::cti_op_bitand);
1538 m_jit.link(iter->from, m_jit.label());
1539 emitPutArg(X86::eax, 0);
1540 emitCall(i, Machine::cti_op_jtrue);
1541 m_jit.testl_rr(X86::eax, X86::eax);
1542 unsigned target = instruction[i + 2].u.operand;
1543 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
1548 unsigned srcDst = instruction[i + 2].u.operand;
1549 m_jit.link(iter->from, m_jit.label());
1550 m_jit.link((++iter)->from, m_jit.label());
1551 emitPutArg(X86::eax, 0);
1552 emitCall(i, Machine::cti_op_post_dec);
1553 emitPutResult(instruction[i + 1].u.operand);
1554 emitGetCTIParam(CTI_ARGS_2ndResult, X86::eax);
1555 emitPutResult(srcDst);
1560 m_jit.link(iter->from, m_jit.label());
1561 emitPutArg(X86::eax, 0);
1562 emitPutArg(X86::edx, 4);
1563 emitCall(i, Machine::cti_op_bitxor);
1564 emitPutResult(instruction[i + 1].u.operand);
1569 m_jit.link(iter->from, m_jit.label());
1570 emitPutArg(X86::eax, 0);
1571 emitPutArg(X86::edx, 4);
1572 emitCall(i, Machine::cti_op_bitor);
1573 emitPutResult(instruction[i + 1].u.operand);
1578 X86Assembler::JmpSrc notImm1 = iter->from;
1579 X86Assembler::JmpSrc notImm2 = (++iter)->from;
1580 m_jit.link((++iter)->from, m_jit.label());
1581 emitFastArithReTagImmediate(X86::eax);
1582 emitFastArithReTagImmediate(X86::ecx);
1583 m_jit.link(notImm1, m_jit.label());
1584 m_jit.link(notImm2, m_jit.label());
1585 emitPutArg(X86::eax, 0);
1586 emitPutArg(X86::ecx, 4);
1587 emitCall(i, Machine::cti_op_mod);
1588 emitPutResult(instruction[i + 1].u.operand);
1593 ASSERT_NOT_REACHED();
1597 m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i]);
1601 void CTI::privateCompile()
1603 // Could use a popl_m, but would need to offset the following instruction if so.
1604 m_jit.popl_r(X86::ecx);
1605 emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
1606 emitPutToCallFrameHeader(X86::ecx, RegisterFile::CTIReturnEIP);
1608 privateCompileMainPass();
1609 privateCompileLinkPass();
1610 privateCompileSlowCases();
1612 ASSERT(m_jmpTable.isEmpty());
1614 void* code = m_jit.copy();
1617 // Translate vPC offsets into addresses in JIT generated code, for switch tables.
1618 for (unsigned i = 0; i < m_switches.size(); ++i) {
1619 SwitchRecord record = m_switches[i];
1620 unsigned opcodeIndex = record.m_opcodeIndex;
1622 if (record.m_type != SwitchRecord::String) {
1623 ASSERT(record.m_type == SwitchRecord::Immediate || record.m_type == SwitchRecord::Character);
1624 ASSERT(record.m_jumpTable.m_simpleJumpTable->branchOffsets.size() == record.m_jumpTable.m_simpleJumpTable->ctiOffsets.size());
1626 record.m_jumpTable.m_simpleJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
1628 for (unsigned j = 0; j < record.m_jumpTable.m_simpleJumpTable->branchOffsets.size(); ++j) {
1629 unsigned offset = record.m_jumpTable.m_simpleJumpTable->branchOffsets[j];
1630 record.m_jumpTable.m_simpleJumpTable->ctiOffsets[j] = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_simpleJumpTable->ctiDefault;
1633 ASSERT(record.m_type == SwitchRecord::String);
1635 record.m_jumpTable.m_stringJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
1637 StringJumpTable::StringOffsetTable::iterator end = record.m_jumpTable.m_stringJumpTable->offsetTable.end();
1638 for (StringJumpTable::StringOffsetTable::iterator it = record.m_jumpTable.m_stringJumpTable->offsetTable.begin(); it != end; ++it) {
1639 unsigned offset = it->second.branchOffset;
1640 it->second.ctiOffset = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_stringJumpTable->ctiDefault;
1645 for (Vector<HandlerInfo>::iterator iter = m_codeBlock->exceptionHandlers.begin(); iter != m_codeBlock->exceptionHandlers.end(); ++iter)
1646 iter->nativeCode = m_jit.getRelocatedAddress(code, m_labels[iter->target]);
1648 // FIXME: There doesn't seem to be a way to hint to a hashmap that it should make a certain capacity available;
1649 // could be faster if we could do something like this:
1650 // m_codeBlock->ctiReturnAddressVPCMap.grow(m_calls.size());
1651 for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
1652 X86Assembler::link(code, iter->from, iter->to);
1653 m_codeBlock->ctiReturnAddressVPCMap.add(m_jit.getRelocatedAddress(code, iter->from), iter->opcodeIndex);
1656 // Link absolute addresses for jsr
1657 for (Vector<JSRInfo>::iterator iter = m_jsrSites.begin(); iter != m_jsrSites.end(); ++iter)
1658 X86Assembler::linkAbsoluteAddress(code, iter->addrPosition, iter->target);
1660 m_codeBlock->ctiCode = code;
1663 void* CTI::privateCompileGetByIdSelf(StructureID* structureID, size_t cachedOffset)
1665 // Check eax is an object of the right StructureID.
1666 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1667 X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
1668 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
1669 X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
1671 // Checks out okay! - getDirectOffset
1672 m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
1673 m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
1676 void* code = m_jit.copy();
1679 X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1680 X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1682 m_codeBlock->structureIDAccessStubs.append(code);
1687 void* CTI::privateCompileGetByIdProto(ExecState* exec, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
1689 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is
1690 // referencing the prototype object - let's speculatively load it's table nice and early!)
1691 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
1692 OwnArrayPtr<JSValue*>* protoPropertyStorage = &protoObject->m_propertyStorage;
1693 m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
1695 // check eax is an object of the right StructureID.
1696 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1697 X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
1698 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
1699 X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
1701 // Check the prototype object's StructureID had not changed.
1702 StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
1703 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructureID), static_cast<void*>(protoStructureIDAddress));
1704 X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJne();
1706 // Checks out okay! - getDirectOffset
1707 m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
1711 void* code = m_jit.copy();
1714 X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1715 X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1716 X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1718 m_codeBlock->structureIDAccessStubs.append(code);
1723 void* CTI::privateCompileGetByIdChain(ExecState* exec, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
1727 Vector<X86Assembler::JmpSrc> bucketsOfFail;
1729 // Check eax is an object of the right StructureID.
1730 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1731 bucketsOfFail.append(m_jit.emitUnlinkedJne());
1732 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
1733 bucketsOfFail.append(m_jit.emitUnlinkedJne());
1735 StructureID* currStructureID = structureID;
1736 RefPtr<StructureID>* chainEntries = chain->head();
1737 JSCell* protoObject = 0;
1738 for (unsigned i = 0; i<count; ++i) {
1739 protoObject = static_cast<JSCell*>(currStructureID->prototypeForLookup(exec));
1740 currStructureID = chainEntries[i].get();
1742 // Check the prototype object's StructureID had not changed.
1743 StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
1744 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(currStructureID), static_cast<void*>(protoStructureIDAddress));
1745 bucketsOfFail.append(m_jit.emitUnlinkedJne());
1747 ASSERT(protoObject);
1749 OwnArrayPtr<JSValue*>* protoPropertyStorage = &static_cast<JSObject*>(protoObject)->m_propertyStorage;
1750 m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
1751 m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
1754 bucketsOfFail.append(m_jit.emitUnlinkedJmp());
1756 void* code = m_jit.copy();
1759 for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
1760 X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1761 m_codeBlock->structureIDAccessStubs.append(code);
1765 void* CTI::privateCompilePutByIdReplace(StructureID* structureID, size_t cachedOffset)
1767 // check eax is an object of the right StructureID.
1768 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1769 X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
1770 m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
1771 X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
1773 // checks out okay! - putDirectOffset
1774 m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
1775 m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
1778 void* code = m_jit.copy();
1781 X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
1782 X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
1784 m_codeBlock->structureIDAccessStubs.append(code);
1789 void* CTI::privateArrayLengthTrampoline()
1791 // Check eax is an array
1792 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1793 X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
1794 m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
1795 X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
1797 // Checks out okay! - get the length from the storage
1798 m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::eax);
1799 m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_length), X86::eax, X86::eax);
1801 m_jit.addl_rr(X86::eax, X86::eax);
1802 X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
1803 m_jit.addl_i8r(1, X86::eax);
1807 void* code = m_jit.copy();
1810 X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1811 X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1812 X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1817 void* CTI::privateStringLengthTrampoline()
1819 // Check eax is a string
1820 m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
1821 X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
1822 m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringVptr), X86::eax);
1823 X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
1825 // Checks out okay! - get the length from the Ustring.
1826 m_jit.movl_mr(OBJECT_OFFSET(JSString, m_value) + OBJECT_OFFSET(UString, m_rep), X86::eax, X86::eax);
1827 m_jit.movl_mr(OBJECT_OFFSET(UString::Rep, len), X86::eax, X86::eax);
1829 m_jit.addl_rr(X86::eax, X86::eax);
1830 X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
1831 m_jit.addl_i8r(1, X86::eax);
1835 void* code = m_jit.copy();
1838 X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1839 X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1840 X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
1845 void CTI::emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst)
1847 m_jit.movl_mr(JSVariableObject::offsetOf_d(), variableObject, dst);
1848 m_jit.movl_mr(JSVariableObject::offsetOf_Data_registers(), dst, dst);
1849 m_jit.movl_mr(index * sizeof(Register), dst, dst);
1852 void CTI::emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index)
1854 m_jit.movl_mr(JSVariableObject::offsetOf_d(), variableObject, variableObject);
1855 m_jit.movl_mr(JSVariableObject::offsetOf_Data_registers(), variableObject, variableObject);
1856 m_jit.movl_rm(src, index * sizeof(Register), variableObject);
1861 void* CTI::compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase, bool multiline)
1863 // TODO: better error messages
1864 if (pattern.size() > MaxPatternSize) {
1865 *error_ptr = "regular expression too large";
1869 X86Assembler jit(exec->machine()->jitCodeBuffer());
1870 WRECParser parser(pattern, ignoreCase, multiline, jit);
1872 jit.emitConvertToFastCall();
1874 // Preserve regs & initialize outputRegister.
1875 jit.pushl_r(WRECGenerator::outputRegister);
1876 jit.pushl_r(WRECGenerator::currentValueRegister);
1877 // push pos onto the stack, both to preserve and as a parameter available to parseDisjunction
1878 jit.pushl_r(WRECGenerator::currentPositionRegister);
1879 // load output pointer
1884 , X86::esp, WRECGenerator::outputRegister);
1886 // restart point on match fail.
1887 WRECGenerator::JmpDst nextLabel = jit.label();
1889 // (1) Parse Disjunction:
1891 // Parsing the disjunction should fully consume the pattern.
1892 JmpSrcVector failures;
1893 parser.parseDisjunction(failures);
1894 if (parser.isEndOfPattern()) {
1895 parser.m_err = WRECParser::Error_malformedPattern;
1898 // TODO: better error messages
1899 *error_ptr = "TODO: better error messages";
1904 // Set return value & pop registers from the stack.
1906 jit.testl_rr(WRECGenerator::outputRegister, WRECGenerator::outputRegister);
1907 WRECGenerator::JmpSrc noOutput = jit.emitUnlinkedJe();
1909 jit.movl_rm(WRECGenerator::currentPositionRegister, 4, WRECGenerator::outputRegister);
1910 jit.popl_r(X86::eax);
1911 jit.movl_rm(X86::eax, WRECGenerator::outputRegister);
1912 jit.popl_r(WRECGenerator::currentValueRegister);
1913 jit.popl_r(WRECGenerator::outputRegister);
1916 jit.link(noOutput, jit.label());
1918 jit.popl_r(X86::eax);
1919 jit.movl_rm(X86::eax, WRECGenerator::outputRegister);
1920 jit.popl_r(WRECGenerator::currentValueRegister);
1921 jit.popl_r(WRECGenerator::outputRegister);
1925 // All fails link to here. Progress the start point & if it is within scope, loop.
1926 // Otherwise, return fail value.
1927 WRECGenerator::JmpDst here = jit.label();
1928 for (unsigned i = 0; i < failures.size(); ++i)
1929 jit.link(failures[i], here);
1932 jit.movl_mr(X86::esp, WRECGenerator::currentPositionRegister);
1933 jit.addl_i8r(1, WRECGenerator::currentPositionRegister);
1934 jit.movl_rm(WRECGenerator::currentPositionRegister, X86::esp);
1935 jit.cmpl_rr(WRECGenerator::lengthRegister, WRECGenerator::currentPositionRegister);
1936 jit.link(jit.emitUnlinkedJle(), nextLabel);
1938 jit.addl_i8r(4, X86::esp);
1940 jit.movl_i32r(-1, X86::eax);
1941 jit.popl_r(WRECGenerator::currentValueRegister);
1942 jit.popl_r(WRECGenerator::outputRegister);
1945 *numSubpatterns_ptr = parser.m_numSubpatterns;
1947 void* code = jit.copy();
1952 #endif // ENABLE(WREC)
1956 #endif // ENABLE(CTI)