summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/VM/CTI.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:41 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:41 -0800
commit648161bb0edfc3d43db63caed5cc5213bc6cb78f (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /JavaScriptCore/VM/CTI.cpp
parenta65af38181ac7d34544586bdb5cd004de93897ad (diff)
downloadexternal_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.zip
external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.gz
external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'JavaScriptCore/VM/CTI.cpp')
-rw-r--r--JavaScriptCore/VM/CTI.cpp3532
1 files changed, 0 insertions, 3532 deletions
diff --git a/JavaScriptCore/VM/CTI.cpp b/JavaScriptCore/VM/CTI.cpp
deleted file mode 100644
index 1ece843..0000000
--- a/JavaScriptCore/VM/CTI.cpp
+++ /dev/null
@@ -1,3532 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "CTI.h"
-
-#if ENABLE(CTI)
-
-#include "CodeBlock.h"
-#include "JSArray.h"
-#include "JSFunction.h"
-#include "Machine.h"
-#include "wrec/WREC.h"
-#include "ResultType.h"
-#include "SamplingTool.h"
-
-#ifndef NDEBUG
-#include <stdio.h>
-#endif
-
-using namespace std;
-
-namespace JSC {
-
-#if PLATFORM(MAC)
-
-static inline bool isSSE2Present()
-{
- return true; // All X86 Macs are guaranteed to support at least SSE2
-}
-
-#else
-
-static bool isSSE2Present()
-{
- static const int SSE2FeatureBit = 1 << 26;
- struct SSE2Check {
- SSE2Check()
- {
- int flags;
-#if COMPILER(MSVC)
- _asm {
- mov eax, 1 // cpuid function 1 gives us the standard feature set
- cpuid;
- mov flags, edx;
- }
-#else
- flags = 0;
- // FIXME: Add GCC code to do above asm
-#endif
- present = (flags & SSE2FeatureBit) != 0;
- }
- bool present;
- };
- static SSE2Check check;
- return check.present;
-}
-
-#endif
-
-COMPILE_ASSERT(CTI_ARGS_code == 0xC, CTI_ARGS_code_is_C);
-COMPILE_ASSERT(CTI_ARGS_callFrame == 0xE, CTI_ARGS_callFrame_is_E);
-
-#if COMPILER(GCC) && PLATFORM(X86)
-
-#if PLATFORM(DARWIN)
-#define SYMBOL_STRING(name) "_" #name
-#else
-#define SYMBOL_STRING(name) #name
-#endif
-
-asm(
-".globl " SYMBOL_STRING(ctiTrampoline) "\n"
-SYMBOL_STRING(ctiTrampoline) ":" "\n"
- "pushl %esi" "\n"
- "pushl %edi" "\n"
- "pushl %ebx" "\n"
- "subl $0x20, %esp" "\n"
- "movl $512, %esi" "\n"
- "movl 0x38(%esp), %edi" "\n" // Ox38 = 0x0E * 4, 0x0E = CTI_ARGS_callFrame (see assertion above)
- "call *0x30(%esp)" "\n" // Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code (see assertion above)
- "addl $0x20, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "ret" "\n"
-);
-
-asm(
-".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
-SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
-#if USE(CTI_ARGUMENT)
-#if USE(FAST_CALL_CTI_ARGUMENT)
- "movl %esp, %ecx" "\n"
-#else
- "movl %esp, 0(%esp)" "\n"
-#endif
- "call " SYMBOL_STRING(_ZN3JSC7Machine12cti_vm_throwEPPv) "\n"
-#else
- "call " SYMBOL_STRING(_ZN3JSC7Machine12cti_vm_throwEPvz) "\n"
-#endif
- "addl $0x20, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "ret" "\n"
-);
-
-#elif COMPILER(MSVC)
-
-extern "C" {
-
- __declspec(naked) JSValue* ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue** exception, Profiler**, JSGlobalData*)
- {
- __asm {
- push esi;
- push edi;
- push ebx;
- sub esp, 0x20;
- mov esi, 512;
- mov ecx, esp;
- mov edi, [esp + 0x38];
- call [esp + 0x30]; // Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code (see assertion above)
- add esp, 0x20;
- pop ebx;
- pop edi;
- pop esi;
- ret;
- }
- }
-
- __declspec(naked) void ctiVMThrowTrampoline()
- {
- __asm {
- mov ecx, esp;
- call JSC::Machine::cti_vm_throw;
- add esp, 0x20;
- pop ebx;
- pop edi;
- pop esi;
- ret;
- }
- }
-
-}
-
-#endif
-
-ALWAYS_INLINE bool CTI::isConstant(int src)
-{
- return src >= m_codeBlock->numVars && src < m_codeBlock->numVars + m_codeBlock->numConstants;
-}
-
-ALWAYS_INLINE JSValue* CTI::getConstant(CallFrame* callFrame, int src)
-{
- return m_codeBlock->constantRegisters[src - m_codeBlock->numVars].jsValue(callFrame);
-}
-
-inline uintptr_t CTI::asInteger(JSValue* value)
-{
- return reinterpret_cast<uintptr_t>(value);
-}
-
-// get arg puts an arg from the SF register array into a h/w register
-ALWAYS_INLINE void CTI::emitGetArg(int src, X86Assembler::RegisterID dst)
-{
- // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
- if (isConstant(src)) {
- JSValue* js = getConstant(m_callFrame, src);
- m_jit.movl_i32r(asInteger(js), dst);
- } else
- m_jit.movl_mr(src * sizeof(Register), X86::edi, dst);
-}
-
-// get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void CTI::emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch)
-{
- if (isConstant(src)) {
- JSValue* js = getConstant(m_callFrame, src);
- m_jit.movl_i32m(asInteger(js), offset + sizeof(void*), X86::esp);
- } else {
- m_jit.movl_mr(src * sizeof(Register), X86::edi, scratch);
- m_jit.movl_rm(scratch, offset + sizeof(void*), X86::esp);
- }
-}
-
-// puts an arg onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void CTI::emitPutArg(X86Assembler::RegisterID src, unsigned offset)
-{
- m_jit.movl_rm(src, offset + sizeof(void*), X86::esp);
-}
-
-ALWAYS_INLINE void CTI::emitPutArgConstant(unsigned value, unsigned offset)
-{
- m_jit.movl_i32m(value, offset + sizeof(void*), X86::esp);
-}
-
-ALWAYS_INLINE JSValue* CTI::getConstantImmediateNumericArg(unsigned src)
-{
- if (isConstant(src)) {
- JSValue* js = getConstant(m_callFrame, src);
- return JSImmediate::isNumber(js) ? js : noValue();
- }
- return noValue();
-}
-
-ALWAYS_INLINE void CTI::emitPutCTIParam(void* value, unsigned name)
-{
- m_jit.movl_i32m(reinterpret_cast<intptr_t>(value), name * sizeof(void*), X86::esp);
-}
-
-ALWAYS_INLINE void CTI::emitPutCTIParam(X86Assembler::RegisterID from, unsigned name)
-{
- m_jit.movl_rm(from, name * sizeof(void*), X86::esp);
-}
-
-ALWAYS_INLINE void CTI::emitGetCTIParam(unsigned name, X86Assembler::RegisterID to)
-{
- m_jit.movl_mr(name * sizeof(void*), X86::esp, to);
-}
-
-ALWAYS_INLINE void CTI::emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
-{
- m_jit.movl_rm(from, entry * sizeof(Register), X86::edi);
-}
-
-ALWAYS_INLINE void CTI::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to)
-{
- m_jit.movl_mr(entry * sizeof(Register), X86::edi, to);
-}
-
-ALWAYS_INLINE void CTI::emitPutResult(unsigned dst, X86Assembler::RegisterID from)
-{
- m_jit.movl_rm(from, dst * sizeof(Register), X86::edi);
- // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
-}
-
-ALWAYS_INLINE void CTI::emitInitRegister(unsigned dst)
-{
- m_jit.movl_i32m(asInteger(jsUndefined()), dst * sizeof(Register), X86::edi);
- // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
-}
-
-void ctiSetReturnAddress(void** where, void* what)
-{
- *where = what;
-}
-
-void ctiRepatchCallByReturnAddress(void* where, void* what)
-{
- (static_cast<void**>(where))[-1] = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(what) - reinterpret_cast<uintptr_t>(where));
-}
-
-#ifndef NDEBUG
-
-void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
-{
- char which1 = '*';
- if (isConstant(src1)) {
- JSValue* js = getConstant(m_callFrame, src1);
- which1 =
- JSImmediate::isImmediate(js) ?
- (JSImmediate::isNumber(js) ? 'i' :
- JSImmediate::isBoolean(js) ? 'b' :
- js->isUndefined() ? 'u' :
- js->isNull() ? 'n' : '?')
- :
- (js->isString() ? 's' :
- js->isObject() ? 'o' :
- 'k');
- }
- char which2 = '*';
- if (isConstant(src2)) {
- JSValue* js = getConstant(m_callFrame, src2);
- which2 =
- JSImmediate::isImmediate(js) ?
- (JSImmediate::isNumber(js) ? 'i' :
- JSImmediate::isBoolean(js) ? 'b' :
- js->isUndefined() ? 'u' :
- js->isNull() ? 'n' : '?')
- :
- (js->isString() ? 's' :
- js->isObject() ? 'o' :
- 'k');
- }
- if ((which1 != '*') | (which2 != '*'))
- fprintf(stderr, "Types %c %c\n", which1, which2);
-}
-
-#endif
-
-extern "C" {
- static JSValue* FASTCALL allocateNumber(JSGlobalData* globalData) {
- JSValue* result = new (globalData) JSNumberCell(globalData);
- ASSERT(result);
- return result;
- }
-}
-
-ALWAYS_INLINE void CTI::emitAllocateNumber(JSGlobalData* globalData, unsigned opcodeIndex)
-{
- m_jit.movl_i32r(reinterpret_cast<intptr_t>(globalData), X86::ecx);
- emitNakedFastCall(opcodeIndex, (void*)allocateNumber);
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, X86::RegisterID r)
-{
- X86Assembler::JmpSrc call = m_jit.emitCall(r);
- m_calls.append(CallRecord(call, opcodeIndex));
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, void(*function)())
-{
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, reinterpret_cast<CTIHelper_v>(function), opcodeIndex));
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitNakedFastCall(unsigned opcodeIndex, void* function)
-{
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, reinterpret_cast<CTIHelper_v>(function), opcodeIndex));
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_j helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_o helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_p helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_b helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_v helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_s helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_2 helper)
-{
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
-#else
- UNUSED_PARAM(vPC);
-#endif
- m_jit.emitRestoreArgumentReference();
- emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
- X86Assembler::JmpSrc call = m_jit.emitCall();
- m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
-#endif
-
- return call;
-}
-
-ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex)
-{
- m_jit.testl_i32r(JSImmediate::TagMask, reg);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), opcodeIndex));
-}
-
-ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImmNum(X86Assembler::RegisterID reg, unsigned opcodeIndex)
-{
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, reg);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), opcodeIndex));
-}
-
-ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotImmNums(X86Assembler::RegisterID reg1, X86Assembler::RegisterID reg2, unsigned opcodeIndex)
-{
- m_jit.movl_rr(reg1, X86::ecx);
- m_jit.andl_rr(reg2, X86::ecx);
- emitJumpSlowCaseIfNotImmNum(X86::ecx, opcodeIndex);
-}
-
-ALWAYS_INLINE unsigned CTI::getDeTaggedConstantImmediate(JSValue* imm)
-{
- ASSERT(JSImmediate::isNumber(imm));
- return asInteger(imm) & ~JSImmediate::TagBitTypeInteger;
-}
-
-ALWAYS_INLINE void CTI::emitFastArithDeTagImmediate(X86Assembler::RegisterID reg)
-{
- m_jit.subl_i8r(JSImmediate::TagBitTypeInteger, reg);
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitFastArithDeTagImmediateJumpIfZero(X86Assembler::RegisterID reg)
-{
- m_jit.subl_i8r(JSImmediate::TagBitTypeInteger, reg);
- return m_jit.emitUnlinkedJe();
-}
-
-ALWAYS_INLINE void CTI::emitFastArithReTagImmediate(X86Assembler::RegisterID reg)
-{
- m_jit.addl_i8r(JSImmediate::TagBitTypeInteger, reg);
-}
-
-ALWAYS_INLINE void CTI::emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID reg)
-{
- m_jit.orl_i32r(JSImmediate::TagBitTypeInteger, reg);
-}
-
-ALWAYS_INLINE void CTI::emitFastArithImmToInt(X86Assembler::RegisterID reg)
-{
- m_jit.sarl_i8r(1, reg);
-}
-
-ALWAYS_INLINE void CTI::emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID reg, unsigned opcodeIndex)
-{
- m_jit.addl_rr(reg, reg);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), opcodeIndex));
- emitFastArithReTagImmediate(reg);
-}
-
-ALWAYS_INLINE void CTI::emitFastArithIntToImmNoCheck(X86Assembler::RegisterID reg)
-{
- m_jit.addl_rr(reg, reg);
- emitFastArithReTagImmediate(reg);
-}
-
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitArithIntToImmWithJump(X86Assembler::RegisterID reg)
-{
- m_jit.addl_rr(reg, reg);
- X86Assembler::JmpSrc jmp = m_jit.emitUnlinkedJo();
- emitFastArithReTagImmediate(reg);
- return jmp;
-}
-
-ALWAYS_INLINE void CTI::emitTagAsBoolImmediate(X86Assembler::RegisterID reg)
-{
- m_jit.shl_i8r(JSImmediate::ExtendedPayloadShift, reg);
- m_jit.orl_i32r(JSImmediate::FullTagTypeBool, reg);
-}
-
-CTI::CTI(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock)
- : m_jit(machine->jitCodeBuffer())
- , m_machine(machine)
- , m_callFrame(callFrame)
- , m_codeBlock(codeBlock)
- , m_labels(codeBlock ? codeBlock->instructions.size() : 0)
- , m_propertyAccessCompilationInfo(codeBlock ? codeBlock->propertyAccessInstructions.size() : 0)
- , m_callStructureStubCompilationInfo(codeBlock ? codeBlock->callLinkInfos.size() : 0)
-{
-}
-
-#define CTI_COMPILE_BINARY_OP(name) \
- case name: { \
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx); \
- emitCTICall(instruction + i, i, Machine::cti_##name); \
- emitPutResult(instruction[i + 1].u.operand); \
- i += 4; \
- break; \
- }
-
-#define CTI_COMPILE_UNARY_OP(name) \
- case name: { \
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
- emitCTICall(instruction + i, i, Machine::cti_##name); \
- emitPutResult(instruction[i + 1].u.operand); \
- i += 3; \
- break; \
- }
-
-static void unreachable()
-{
- ASSERT_NOT_REACHED();
- exit(1);
-}
-
-void CTI::compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount)
-{
- emitGetArg(callee, X86::ecx); // Load callee JSFunction into ecx
- m_jit.movl_rm(X86::eax, RegisterFile::CodeBlock * static_cast<int>(sizeof(Register)), X86::edx); // callee CodeBlock was returned in eax
- m_jit.movl_i32m(asInteger(noValue()), RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edx);
- m_jit.movl_rm(X86::ecx, RegisterFile::Callee * static_cast<int>(sizeof(Register)), X86::edx);
-
- m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::ebx); // newScopeChain
- m_jit.movl_i32m(argCount, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)), X86::edx);
- m_jit.movl_rm(X86::edi, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register)), X86::edx);
- m_jit.movl_rm(X86::ebx, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)), X86::edx);
-}
-
-void CTI::compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval)
-{
- int firstArg = instruction[4].u.operand;
- int argCount = instruction[5].u.operand;
- int registerOffset = instruction[6].u.operand;
-
- emitPutArg(X86::ecx, 0);
- emitPutArgConstant(registerOffset, 4);
- emitPutArgConstant(argCount, 8);
- emitPutArgConstant(reinterpret_cast<unsigned>(instruction), 12);
- if (isConstruct) {
- emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
- emitPutArgConstant(firstArg, 20);
- } else if (isEval)
- emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
-}
-
-void CTI::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int firstArg = instruction[4].u.operand;
- int argCount = instruction[5].u.operand;
- int registerOffset = instruction[6].u.operand;
-
- // Setup this value as the first argument (does not apply to constructors)
- if (opcodeID != op_construct) {
- int thisVal = instruction[3].u.operand;
- if (thisVal == missingThisObjectMarker()) {
- // FIXME: should this be loaded dynamically off m_callFrame?
- m_jit.movl_i32m(asInteger(m_callFrame->globalThisValue()), firstArg * sizeof(Register), X86::edi);
- } else {
- emitGetArg(thisVal, X86::eax);
- emitPutResult(firstArg);
- }
- }
-
- // Handle eval
- X86Assembler::JmpSrc wasEval;
- if (opcodeID == op_call_eval) {
- emitGetArg(callee, X86::ecx);
- compileOpCallSetupArgs(instruction, false, true);
-
- emitCTICall(instruction, i, Machine::cti_op_call_eval);
- m_jit.cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::eax);
- wasEval = m_jit.emitUnlinkedJne();
- }
-
- // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
- // This deliberately leaves the callee in ecx, used when setting up the stack frame below
- emitGetArg(callee, X86::ecx);
- m_jit.cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::ecx);
- X86Assembler::JmpDst addressOfLinkedFunctionCheck = m_jit.label();
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- ASSERT(X86Assembler::getDifferenceBetweenLabels(addressOfLinkedFunctionCheck, m_jit.label()) == repatchOffsetOpCallCall);
- m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
-
- // The following is the fast case, only used whan a callee can be linked.
-
- // In the case of OpConstruct, call oout to a cti_ function to create the new object.
- if (opcodeID == op_construct) {
- emitPutArg(X86::ecx, 0);
- emitGetPutArg(instruction[3].u.operand, 4, X86::eax);
- emitCTICall(instruction, i, Machine::cti_op_construct_JSConstructFast);
- emitPutResult(instruction[4].u.operand);
- emitGetArg(callee, X86::ecx);
- }
-
- // Fast version of stack frame initialization, directly relative to edi.
- // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
- m_jit.movl_i32m(asInteger(noValue()), (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.movl_rm(X86::ecx, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::edx); // newScopeChain
- m_jit.movl_i32m(argCount, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.movl_rm(X86::edi, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.movl_rm(X86::edx, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.addl_i32r(registerOffset * sizeof(Register), X86::edi);
-
- // Call to the callee
- m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(i, unreachable);
-
- if (opcodeID == op_call_eval)
- m_jit.link(wasEval, m_jit.label());
-
- // Put the return value in dst. In the interpreter, op_ret does this.
- emitPutResult(dst);
-
-#if ENABLE(CODEBLOCK_SAMPLING)
- m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
-#endif
-}
-
-void CTI::compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type)
-{
- bool negated = (type == OpNStrictEq);
-
- unsigned dst = instruction[1].u.operand;
- unsigned src1 = instruction[2].u.operand;
- unsigned src2 = instruction[3].u.operand;
-
- emitGetArg(src1, X86::eax);
- emitGetArg(src2, X86::edx);
-
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc firstNotImmediate = m_jit.emitUnlinkedJe();
- m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
- X86Assembler::JmpSrc secondNotImmediate = m_jit.emitUnlinkedJe();
-
- m_jit.cmpl_rr(X86::edx, X86::eax);
- if (negated)
- m_jit.setne_r(X86::eax);
- else
- m_jit.sete_r(X86::eax);
- m_jit.movzbl_rr(X86::eax, X86::eax);
- emitTagAsBoolImmediate(X86::eax);
-
- X86Assembler::JmpSrc bothWereImmediates = m_jit.emitUnlinkedJmp();
-
- m_jit.link(firstNotImmediate, m_jit.label());
-
- // check that edx is immediate but not the zero immediate
- m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
- m_jit.setz_r(X86::ecx);
- m_jit.movzbl_rr(X86::ecx, X86::ecx); // ecx is now 1 if edx was nonimmediate
- m_jit.cmpl_i32r(asInteger(JSImmediate::zeroImmediate()), X86::edx);
- m_jit.sete_r(X86::edx);
- m_jit.movzbl_rr(X86::edx, X86::edx); // edx is now 1 if edx was the 0 immediate
- m_jit.orl_rr(X86::ecx, X86::edx);
-
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
-
- m_jit.movl_i32r(asInteger(jsBoolean(negated)), X86::eax);
-
- X86Assembler::JmpSrc firstWasNotImmediate = m_jit.emitUnlinkedJmp();
-
- m_jit.link(secondNotImmediate, m_jit.label());
- // check that eax is not the zero immediate (we know it must be immediate)
- m_jit.cmpl_i32r(asInteger(JSImmediate::zeroImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
-
- m_jit.movl_i32r(asInteger(jsBoolean(negated)), X86::eax);
-
- m_jit.link(bothWereImmediates, m_jit.label());
- m_jit.link(firstWasNotImmediate, m_jit.label());
-
- emitPutResult(dst);
-}
-
-void CTI::emitSlowScriptCheck(Instruction* vPC, unsigned opcodeIndex)
-{
- m_jit.subl_i8r(1, X86::esi);
- X86Assembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
- emitCTICall(vPC, opcodeIndex, Machine::cti_timeout_check);
-
- emitGetCTIParam(CTI_ARGS_globalData, X86::ecx);
- m_jit.movl_mr(OBJECT_OFFSET(JSGlobalData, machine), X86::ecx, X86::ecx);
- m_jit.movl_mr(OBJECT_OFFSET(Machine, m_ticksUntilNextTimeoutCheck), X86::ecx, X86::esi);
- m_jit.link(skipTimeout, m_jit.label());
-}
-
-/*
- This is required since number representation is canonical - values representable as a JSImmediate should not be stored in a JSNumberCell.
-
- In the common case, the double value from 'xmmSource' is written to the reusable JSNumberCell pointed to by 'jsNumberCell', then 'jsNumberCell'
- is written to the output SF Register 'dst', and then a jump is planted (stored into *wroteJSNumberCell).
-
- However if the value from xmmSource is representable as a JSImmediate, then the JSImmediate value will be written to the output, and flow
- control will fall through from the code planted.
-*/
-void CTI::putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell, X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2)
-{
- // convert (double -> JSImmediate -> double), and check if the value is unchanged - in which case the value is representable as a JSImmediate.
- m_jit.cvttsd2si_rr(xmmSource, tempReg1);
- m_jit.addl_rr(tempReg1, tempReg1);
- m_jit.sarl_i8r(1, tempReg1);
- m_jit.cvtsi2sd_rr(tempReg1, tempXmm);
- // Compare & branch if immediate.
- m_jit.ucomis_rr(tempXmm, xmmSource);
- X86Assembler::JmpSrc resultIsImm = m_jit.emitUnlinkedJe();
- X86Assembler::JmpDst resultLookedLikeImmButActuallyIsnt = m_jit.label();
-
- // Store the result to the JSNumberCell and jump.
- m_jit.movsd_rm(xmmSource, OBJECT_OFFSET(JSNumberCell, m_value), jsNumberCell);
- emitPutResult(dst, jsNumberCell);
- *wroteJSNumberCell = m_jit.emitUnlinkedJmp();
-
- m_jit.link(resultIsImm, m_jit.label());
- // value == (double)(JSImmediate)value... or at least, it looks that way...
- // ucomi will report that (0 == -0), and will report true if either input in NaN (result is unordered).
- m_jit.link(m_jit.emitUnlinkedJp(), resultLookedLikeImmButActuallyIsnt); // Actually was a NaN
- m_jit.pextrw_irr(3, xmmSource, tempReg2);
- m_jit.cmpl_i32r(0x8000, tempReg2);
- m_jit.link(m_jit.emitUnlinkedJe(), resultLookedLikeImmButActuallyIsnt); // Actually was -0
- // Yes it really really really is representable as a JSImmediate.
- emitFastArithIntToImmNoCheck(tempReg1);
- emitPutResult(dst, tempReg1);
-}
-
-void CTI::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
-{
- StructureID* numberStructureID = m_callFrame->globalData().numberStructureID.get();
- X86Assembler::JmpSrc wasJSNumberCell1, wasJSNumberCell1b, wasJSNumberCell2, wasJSNumberCell2b;
-
- emitGetArg(src1, X86::eax);
- emitGetArg(src2, X86::edx);
-
- if (types.second().isReusable() && isSSE2Present()) {
- ASSERT(types.second().mightBeNumber());
-
- // Check op2 is a number
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::edx);
- X86Assembler::JmpSrc op2imm = m_jit.emitUnlinkedJne();
- if (!types.second().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(X86::edx, i);
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- }
-
- // (1) In this case src2 is a reusable number cell.
- // Slow case if src1 is not a number type.
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc op1imm = m_jit.emitUnlinkedJne();
- if (!types.first().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- }
-
- // (1a) if we get here, src1 is also a number cell
- m_jit.movsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
- X86Assembler::JmpSrc loadedDouble = m_jit.emitUnlinkedJmp();
- // (1b) if we get here, src1 is an immediate
- m_jit.link(op1imm, m_jit.label());
- emitFastArithImmToInt(X86::eax);
- m_jit.cvtsi2sd_rr(X86::eax, X86::xmm0);
- // (1c)
- m_jit.link(loadedDouble, m_jit.label());
- if (opcodeID == op_add)
- m_jit.addsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
- else if (opcodeID == op_sub)
- m_jit.subsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
- else {
- ASSERT(opcodeID == op_mul);
- m_jit.mulsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
- }
-
- putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::edx, dst, &wasJSNumberCell2, X86::xmm1, X86::ecx, X86::eax);
- wasJSNumberCell2b = m_jit.emitUnlinkedJmp();
-
- // (2) This handles cases where src2 is an immediate number.
- // Two slow cases - either src1 isn't an immediate, or the subtract overflows.
- m_jit.link(op2imm, m_jit.label());
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- } else if (types.first().isReusable() && isSSE2Present()) {
- ASSERT(types.first().mightBeNumber());
-
- // Check op1 is a number
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc op1imm = m_jit.emitUnlinkedJne();
- if (!types.first().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- }
-
- // (1) In this case src1 is a reusable number cell.
- // Slow case if src2 is not a number type.
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::edx);
- X86Assembler::JmpSrc op2imm = m_jit.emitUnlinkedJne();
- if (!types.second().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(X86::edx, i);
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- }
-
- // (1a) if we get here, src2 is also a number cell
- m_jit.movsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm1);
- X86Assembler::JmpSrc loadedDouble = m_jit.emitUnlinkedJmp();
- // (1b) if we get here, src2 is an immediate
- m_jit.link(op2imm, m_jit.label());
- emitFastArithImmToInt(X86::edx);
- m_jit.cvtsi2sd_rr(X86::edx, X86::xmm1);
- // (1c)
- m_jit.link(loadedDouble, m_jit.label());
- m_jit.movsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
- if (opcodeID == op_add)
- m_jit.addsd_rr(X86::xmm1, X86::xmm0);
- else if (opcodeID == op_sub)
- m_jit.subsd_rr(X86::xmm1, X86::xmm0);
- else {
- ASSERT(opcodeID == op_mul);
- m_jit.mulsd_rr(X86::xmm1, X86::xmm0);
- }
- m_jit.movsd_rm(X86::xmm0, OBJECT_OFFSET(JSNumberCell, m_value), X86::eax);
- emitPutResult(dst);
-
- putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::eax, dst, &wasJSNumberCell1, X86::xmm1, X86::ecx, X86::edx);
- wasJSNumberCell1b = m_jit.emitUnlinkedJmp();
-
- // (2) This handles cases where src1 is an immediate number.
- // Two slow cases - either src2 isn't an immediate, or the subtract overflows.
- m_jit.link(op1imm, m_jit.label());
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- } else
- emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
-
- if (opcodeID == op_add) {
- emitFastArithDeTagImmediate(X86::eax);
- m_jit.addl_rr(X86::edx, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- } else if (opcodeID == op_sub) {
- m_jit.subl_rr(X86::edx, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitFastArithReTagImmediate(X86::eax);
- } else {
- ASSERT(opcodeID == op_mul);
- // convert eax & edx from JSImmediates to ints, and check if either are zero
- emitFastArithImmToInt(X86::edx);
- X86Assembler::JmpSrc op1Zero = emitFastArithDeTagImmediateJumpIfZero(X86::eax);
- m_jit.testl_rr(X86::edx, X86::edx);
- X86Assembler::JmpSrc op2NonZero = m_jit.emitUnlinkedJne();
- m_jit.link(op1Zero, m_jit.label());
- // if either input is zero, add the two together, and check if the result is < 0.
- // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate.
- m_jit.movl_rr(X86::eax, X86::ecx);
- m_jit.addl_rr(X86::edx, X86::ecx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJs(), i));
- // Skip the above check if neither input is zero
- m_jit.link(op2NonZero, m_jit.label());
- m_jit.imull_rr(X86::edx, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitFastArithReTagImmediate(X86::eax);
- }
- emitPutResult(dst);
-
- if (types.second().isReusable() && isSSE2Present()) {
- m_jit.link(wasJSNumberCell2, m_jit.label());
- m_jit.link(wasJSNumberCell2b, m_jit.label());
- }
- else if (types.first().isReusable() && isSSE2Present()) {
- m_jit.link(wasJSNumberCell1, m_jit.label());
- m_jit.link(wasJSNumberCell1b, m_jit.label());
- }
-}
-
-void CTI::compileBinaryArithOpSlowCase(Instruction* vPC, OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
-{
- X86Assembler::JmpDst here = m_jit.label();
- m_jit.link(iter->from, here);
- if (types.second().isReusable() && isSSE2Present()) {
- if (!types.first().definitelyIsNumber()) {
- m_jit.link((++iter)->from, here);
- m_jit.link((++iter)->from, here);
- }
- if (!types.second().definitelyIsNumber()) {
- m_jit.link((++iter)->from, here);
- m_jit.link((++iter)->from, here);
- }
- m_jit.link((++iter)->from, here);
- } else if (types.first().isReusable() && isSSE2Present()) {
- if (!types.first().definitelyIsNumber()) {
- m_jit.link((++iter)->from, here);
- m_jit.link((++iter)->from, here);
- }
- if (!types.second().definitelyIsNumber()) {
- m_jit.link((++iter)->from, here);
- m_jit.link((++iter)->from, here);
- }
- m_jit.link((++iter)->from, here);
- } else
- m_jit.link((++iter)->from, here);
-
- // additional entry point to handle -0 cases.
- if (opcodeID == op_mul)
- m_jit.link((++iter)->from, here);
-
- emitGetPutArg(src1, 0, X86::ecx);
- emitGetPutArg(src2, 4, X86::ecx);
- if (opcodeID == op_add)
- emitCTICall(vPC, i, Machine::cti_op_add);
- else if (opcodeID == op_sub)
- emitCTICall(vPC, i, Machine::cti_op_sub);
- else {
- ASSERT(opcodeID == op_mul);
- emitCTICall(vPC, i, Machine::cti_op_mul);
- }
- emitPutResult(dst);
-}
-
-void CTI::privateCompileMainPass()
-{
- Instruction* instruction = m_codeBlock->instructions.begin();
- unsigned instructionCount = m_codeBlock->instructions.size();
-
- unsigned propertyAccessInstructionIndex = 0;
- unsigned callLinkInfoIndex = 0;
-
- for (unsigned i = 0; i < instructionCount; ) {
- ASSERT_WITH_MESSAGE(m_machine->isOpcode(instruction[i].u.opcode), "privateCompileMainPass gone bad @ %d", i);
-
-#if ENABLE(OPCODE_SAMPLING)
- if (i > 0) // Avoid the overhead of sampling op_enter twice.
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(instruction + i), m_machine->sampler()->sampleSlot());
-#endif
-
- m_labels[i] = m_jit.label();
- OpcodeID opcodeID = m_machine->getOpcodeID(instruction[i].u.opcode);
- switch (opcodeID) {
- case op_mov: {
- unsigned src = instruction[i + 2].u.operand;
- if (isConstant(src))
- m_jit.movl_i32r(asInteger(getConstant(m_callFrame, src)), X86::eax);
- else
- emitGetArg(src, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_add: {
- unsigned dst = instruction[i + 1].u.operand;
- unsigned src1 = instruction[i + 2].u.operand;
- unsigned src2 = instruction[i + 3].u.operand;
-
- if (JSValue* value = getConstantImmediateNumericArg(src1)) {
- emitGetArg(src2, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.addl_i32r(getDeTaggedConstantImmediate(value), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(dst, X86::edx);
- } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
- emitGetArg(src1, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.addl_i32r(getDeTaggedConstantImmediate(value), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(dst);
- } else {
- OperandTypes types = OperandTypes::fromInt(instruction[i + 4].u.operand);
- if (types.first().mightBeNumber() && types.second().mightBeNumber())
- compileBinaryArithOp(op_add, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
- else {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_add);
- emitPutResult(instruction[i + 1].u.operand);
- }
- }
-
- i += 5;
- break;
- }
- case op_end: {
- if (m_codeBlock->needsFullScopeChain)
- emitCTICall(instruction + i, i, Machine::cti_op_end);
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- m_jit.pushl_m(RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)), X86::edi);
- m_jit.ret();
- i += 2;
- break;
- }
- case op_jmp: {
- unsigned target = instruction[i + 1].u.operand;
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
- i += 2;
- break;
- }
- case op_pre_inc: {
- int srcDst = instruction[i + 1].u.operand;
- emitGetArg(srcDst, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(srcDst);
- i += 2;
- break;
- }
- case op_loop: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 1].u.operand;
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
- i += 2;
- break;
- }
- case op_loop_if_less: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- emitGetArg(instruction[i + 1].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_i32r(asInteger(src2imm), X86::edx);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
- } else {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- emitGetArg(instruction[i + 2].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_rr(X86::edx, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJl(), i + 3 + target));
- }
- i += 4;
- break;
- }
- case op_loop_if_lesseq: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- emitGetArg(instruction[i + 1].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_i32r(asInteger(src2imm), X86::edx);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
- } else {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- emitGetArg(instruction[i + 2].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_rr(X86::edx, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
- }
- i += 4;
- break;
- }
- case op_new_object: {
- emitCTICall(instruction + i, i, Machine::cti_op_new_object);
- emitPutResult(instruction[i + 1].u.operand);
- i += 2;
- break;
- }
- case op_put_by_id: {
- // In order to be able to repatch both the StructureID, and the object offset, we store one pointer,
- // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
- // such that the StructureID & offset are always at the same distance from this.
-
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
-
- ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
- X86Assembler::JmpDst hotPathBegin = m_jit.label();
- m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
- ++propertyAccessInstructionIndex;
-
- // Jump to a slow case if either the base object is an immediate, or if the StructureID does not match.
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over.
- m_jit.cmpl_i32m(repatchGetByIdDefaultStructureID, OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, m_jit.label()) == repatchOffsetPutByIdStructureID);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_rm(X86::edx, repatchGetByIdDefaultOffset, X86::eax);
- ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, m_jit.label()) == repatchOffsetPutByIdPropertyMapOffset);
-
- i += 8;
- break;
- }
- case op_get_by_id: {
- // As for put_by_id, get_by_id requires the offset of the StructureID and the offset of the access to be repatched.
- // Additionally, for get_by_id we need repatch the offset of the branch to the slow case (we repatch this to jump
- // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
- // to jump back to if one of these trampolies finds a match.
-
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
-
- ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
-
- X86Assembler::JmpDst hotPathBegin = m_jit.label();
- m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
- ++propertyAccessInstructionIndex;
-
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- m_jit.cmpl_i32m(repatchGetByIdDefaultStructureID, OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, m_jit.label()) == repatchOffsetGetByIdStructureID);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, m_jit.label()) == repatchOffsetGetByIdBranchToSlowCase);
-
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_mr(repatchGetByIdDefaultOffset, X86::eax, X86::ecx);
- ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, m_jit.label()) == repatchOffsetGetByIdPropertyMapOffset);
- emitPutResult(instruction[i + 1].u.operand, X86::ecx);
-
- i += 8;
- break;
- }
- case op_instanceof: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax); // value
- emitGetArg(instruction[i + 3].u.operand, X86::ecx); // baseVal
- emitGetArg(instruction[i + 4].u.operand, X86::edx); // proto
-
- // check if any are immediates
- m_jit.orl_rr(X86::eax, X86::ecx);
- m_jit.orl_rr(X86::edx, X86::ecx);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
-
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
-
- // check that all are object type - this is a bit of a bithack to avoid excess branching;
- // we check that the sum of the three type codes from StructureIDs is exactly 3 * ObjectType,
- // this works because NumberType and StringType are smaller
- m_jit.movl_i32r(3 * ObjectType, X86::ecx);
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::eax);
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::edx, X86::edx);
- m_jit.subl_mr(OBJECT_OFFSET(StructureID, m_typeInfo.m_type), X86::eax, X86::ecx);
- m_jit.subl_mr(OBJECT_OFFSET(StructureID, m_typeInfo.m_type), X86::edx, X86::ecx);
- emitGetArg(instruction[i + 3].u.operand, X86::edx); // reload baseVal
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::edx, X86::edx);
- m_jit.cmpl_rm(X86::ecx, OBJECT_OFFSET(StructureID, m_typeInfo.m_type), X86::edx);
-
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- // check that baseVal's flags include ImplementsHasInstance but not OverridesHasInstance
- m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::edx, X86::ecx);
- m_jit.andl_i32r(ImplementsHasInstance | OverridesHasInstance, X86::ecx);
- m_jit.cmpl_i32r(ImplementsHasInstance, X86::ecx);
-
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- emitGetArg(instruction[i + 2].u.operand, X86::ecx); // reload value
- emitGetArg(instruction[i + 4].u.operand, X86::edx); // reload proto
-
- // optimistically load true result
- m_jit.movl_i32r(asInteger(jsBoolean(true)), X86::eax);
-
- X86Assembler::JmpDst loop = m_jit.label();
-
- // load value's prototype
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::ecx, X86::ecx);
- m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_prototype), X86::ecx, X86::ecx);
-
- m_jit.cmpl_rr(X86::ecx, X86::edx);
- X86Assembler::JmpSrc exit = m_jit.emitUnlinkedJe();
-
- m_jit.cmpl_i32r(asInteger(jsNull()), X86::ecx);
- X86Assembler::JmpSrc goToLoop = m_jit.emitUnlinkedJne();
- m_jit.link(goToLoop, loop);
-
- m_jit.movl_i32r(asInteger(jsBoolean(false)), X86::eax);
-
- m_jit.link(exit, m_jit.label());
-
- emitPutResult(instruction[i + 1].u.operand);
-
- i += 5;
- break;
- }
- case op_del_by_id: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- emitCTICall(instruction + i, i, Machine::cti_op_del_by_id);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_mul: {
- unsigned dst = instruction[i + 1].u.operand;
- unsigned src1 = instruction[i + 2].u.operand;
- unsigned src2 = instruction[i + 3].u.operand;
-
- // For now, only plant a fast int case if the constant operand is greater than zero.
- JSValue* src1Value = getConstantImmediateNumericArg(src1);
- JSValue* src2Value = getConstantImmediateNumericArg(src2);
- int32_t value;
- if (src1Value && ((value = JSImmediate::intValue(src1Value)) > 0)) {
- emitGetArg(src2, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitFastArithDeTagImmediate(X86::eax);
- m_jit.imull_i32r(X86::eax, value, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitFastArithReTagImmediate(X86::eax);
- emitPutResult(dst);
- } else if (src2Value && ((value = JSImmediate::intValue(src2Value)) > 0)) {
- emitGetArg(src1, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitFastArithDeTagImmediate(X86::eax);
- m_jit.imull_i32r(X86::eax, value, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitFastArithReTagImmediate(X86::eax);
- emitPutResult(dst);
- } else
- compileBinaryArithOp(op_mul, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
-
- i += 5;
- break;
- }
- case op_new_func: {
- FuncDeclNode* func = (m_codeBlock->functions[instruction[i + 2].u.operand]).get();
- emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_new_func);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_call: {
- compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
- i += 7;
- break;
- }
- case op_get_global_var: {
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(instruction[i + 2].u.jsCell);
- m_jit.movl_i32r(asInteger(globalObject), X86::eax);
- emitGetVariableObjectRegister(X86::eax, instruction[i + 3].u.operand, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_put_global_var: {
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(instruction[i + 1].u.jsCell);
- m_jit.movl_i32r(asInteger(globalObject), X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitPutVariableObjectRegister(X86::edx, X86::eax, instruction[i + 2].u.operand);
- i += 4;
- break;
- }
- case op_get_scoped_var: {
- int skip = instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain;
-
- emitGetArg(RegisterFile::ScopeChain, X86::eax);
- while (skip--)
- m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, next), X86::eax, X86::eax);
-
- m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, object), X86::eax, X86::eax);
- emitGetVariableObjectRegister(X86::eax, instruction[i + 2].u.operand, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_put_scoped_var: {
- int skip = instruction[i + 2].u.operand + m_codeBlock->needsFullScopeChain;
-
- emitGetArg(RegisterFile::ScopeChain, X86::edx);
- emitGetArg(instruction[i + 3].u.operand, X86::eax);
- while (skip--)
- m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, next), X86::edx, X86::edx);
-
- m_jit.movl_mr(OBJECT_OFFSET(ScopeChainNode, object), X86::edx, X86::edx);
- emitPutVariableObjectRegister(X86::eax, X86::edx, instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_tear_off_activation: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_tear_off_activation);
- i += 2;
- break;
- }
- case op_tear_off_arguments: {
- emitCTICall(instruction + i, i, Machine::cti_op_tear_off_arguments);
- i += 1;
- break;
- }
- case op_ret: {
- // We could JIT generate the deref, only calling out to C when the refcount hits zero.
- if (m_codeBlock->needsFullScopeChain)
- emitCTICall(instruction + i, i, Machine::cti_op_ret_scopeChain);
-
- // Return the result in %eax.
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- // Grab the return address.
- emitGetArg(RegisterFile::ReturnPC, X86::edx);
-
- // Restore our caller's "r".
- emitGetArg(RegisterFile::CallerFrame, X86::edi);
-
- // Return.
- m_jit.pushl_r(X86::edx);
- m_jit.ret();
-
- i += 2;
- break;
- }
- case op_new_array: {
- m_jit.leal_mr(sizeof(Register) * instruction[i + 2].u.operand, X86::edi, X86::edx);
- emitPutArg(X86::edx, 0);
- emitPutArgConstant(instruction[i + 3].u.operand, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_new_array);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_resolve: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_construct: {
- compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
- i += 7;
- break;
- }
- case op_construct_verify: {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc isImmediate = m_jit.emitUnlinkedJne();
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.cmpl_i32m(ObjectType, OBJECT_OFFSET(StructureID, m_typeInfo) + OBJECT_OFFSET(TypeInfo, m_type), X86::ecx);
- X86Assembler::JmpSrc isObject = m_jit.emitUnlinkedJe();
-
- m_jit.link(isImmediate, m_jit.label());
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- m_jit.link(isObject, m_jit.label());
-
- i += 3;
- break;
- }
- case op_get_by_val: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- emitFastArithImmToInt(X86::edx);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
- m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::ecx);
- m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
-
- // Get the value from the vector
- m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::ecx, X86::edx, sizeof(JSValue*), X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_resolve_func: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve_func);
- emitPutResult(instruction[i + 1].u.operand);
- emitPutResult(instruction[i + 2].u.operand, X86::edx);
- i += 4;
- break;
- }
- case op_sub: {
- compileBinaryArithOp(op_sub, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
- i += 5;
- break;
- }
- case op_put_by_val: {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- emitGetArg(instruction[i + 2].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- emitFastArithImmToInt(X86::edx);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
- m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::ecx);
- m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSArray, m_fastAccessCutoff), X86::eax);
- X86Assembler::JmpSrc inFastVector = m_jit.emitUnlinkedJa();
- // No; oh well, check if the access if within the vector - if so, we may still be okay.
- m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(ArrayStorage, m_vectorLength), X86::ecx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJbe(), i));
-
- // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location.
- // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff.
- m_jit.cmpl_i8m(0, OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::ecx, X86::edx, sizeof(JSValue*));
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
-
- // All good - put the value into the array.
- m_jit.link(inFastVector, m_jit.label());
- emitGetArg(instruction[i + 3].u.operand, X86::eax);
- m_jit.movl_rm(X86::eax, OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::ecx, X86::edx, sizeof(JSValue*));
- i += 4;
- break;
- }
- CTI_COMPILE_BINARY_OP(op_lesseq)
- case op_loop_if_true: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 2].u.operand;
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::zeroImmediate()), X86::eax);
- X86Assembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::trueImmediate()), X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
- m_jit.cmpl_i32r(asInteger(JSImmediate::falseImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- m_jit.link(isZero, m_jit.label());
- i += 3;
- break;
- };
- case op_resolve_base: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve_base);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_negate: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc notImmediate = m_jit.emitUnlinkedJe();
-
- m_jit.cmpl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc zeroImmediate = m_jit.emitUnlinkedJe();
- emitFastArithImmToInt(X86::eax);
- m_jit.negl_r(X86::eax); // This can't overflow as we only have a 31bit int at this point
- X86Assembler::JmpSrc overflow = emitArithIntToImmWithJump(X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- X86Assembler::JmpSrc immediateNegateSuccess = m_jit.emitUnlinkedJmp();
-
- if (!isSSE2Present()) {
- m_jit.link(zeroImmediate, m_jit.label());
- m_jit.link(overflow, m_jit.label());
- m_jit.link(notImmediate, m_jit.label());
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_negate);
- emitPutResult(instruction[i + 1].u.operand);
- } else {
- // Slow case immediates
- m_slowCases.append(SlowCaseEntry(zeroImmediate, i));
- m_slowCases.append(SlowCaseEntry(overflow, i));
- m_jit.link(notImmediate, m_jit.label());
- ResultType resultType(instruction[i + 3].u.resultType);
- if (!resultType.definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- StructureID* numberStructureID = m_callFrame->globalData().numberStructureID.get();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- }
- m_jit.movsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
- // We need 3 copies of the sign bit mask so we can assure alignment and pad for the 128bit load
- static double doubleSignBit[] = { -0.0, -0.0, -0.0 };
- m_jit.xorpd_mr((void*)((((uintptr_t)doubleSignBit)+15)&~15), X86::xmm0);
- X86Assembler::JmpSrc wasCell;
- if (!resultType.isReusableNumber())
- emitAllocateNumber(&m_callFrame->globalData(), i);
-
- putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::eax, instruction[i + 1].u.operand, &wasCell,
- X86::xmm1, X86::ecx, X86::edx);
- m_jit.link(wasCell, m_jit.label());
- }
- m_jit.link(immediateNegateSuccess, m_jit.label());
- i += 4;
- break;
- }
- case op_resolve_skip: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitPutArgConstant(instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve_skip);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_resolve_global: {
- // Fast case
- unsigned globalObject = asInteger(instruction[i + 2].u.jsCell);
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
- void* structureIDAddr = reinterpret_cast<void*>(instruction + i + 4);
- void* offsetAddr = reinterpret_cast<void*>(instruction + i + 5);
-
- // Check StructureID of global object
- m_jit.movl_i32r(globalObject, X86::eax);
- m_jit.movl_mr(structureIDAddr, X86::edx);
- m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- X86Assembler::JmpSrc noMatch = m_jit.emitUnlinkedJne(); // StructureIDs don't match
-
- // Load cached property
- m_jit.movl_mr(OBJECT_OFFSET(JSGlobalObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_mr(offsetAddr, X86::edx);
- m_jit.movl_mr(0, X86::eax, X86::edx, sizeof(JSValue*), X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- X86Assembler::JmpSrc end = m_jit.emitUnlinkedJmp();
-
- // Slow case
- m_jit.link(noMatch, m_jit.label());
- emitPutArgConstant(globalObject, 0);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 8);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve_global);
- emitPutResult(instruction[i + 1].u.operand);
- m_jit.link(end, m_jit.label());
- i += 6;
- break;
- }
- CTI_COMPILE_BINARY_OP(op_div)
- case op_pre_dec: {
- int srcDst = instruction[i + 1].u.operand;
- emitGetArg(srcDst, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(srcDst);
- i += 2;
- break;
- }
- case op_jnless: {
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- emitGetArg(instruction[i + 1].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_i32r(asInteger(src2imm), X86::edx);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
- } else {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
- emitGetArg(instruction[i + 2].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::edx, i);
- m_jit.cmpl_rr(X86::edx, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJge(), i + 3 + target));
- }
- i += 4;
- break;
- }
- case op_not: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- m_jit.xorl_i8r(JSImmediate::FullTagTypeBool, X86::eax);
- m_jit.testl_i32r(JSImmediate::FullTagTypeMask, X86::eax); // i8?
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
- m_jit.xorl_i8r((JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue), X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_jfalse: {
- unsigned target = instruction[i + 2].u.operand;
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::zeroImmediate()), X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc isNonZero = m_jit.emitUnlinkedJne();
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::falseImmediate()), X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
- m_jit.cmpl_i32r(asInteger(JSImmediate::trueImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- m_jit.link(isNonZero, m_jit.label());
- i += 3;
- break;
- };
- case op_jeq_null: {
- unsigned src = instruction[i + 1].u.operand;
- unsigned target = instruction[i + 2].u.operand;
-
- emitGetArg(src, X86::eax);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc isImmediate = m_jit.emitUnlinkedJnz();
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.testl_i32m(MasqueradesAsUndefined, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::ecx);
- m_jit.setnz_r(X86::eax);
-
- X86Assembler::JmpSrc wasNotImmediate = m_jit.emitUnlinkedJmp();
-
- m_jit.link(isImmediate, m_jit.label());
-
- m_jit.movl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::ecx);
- m_jit.andl_rr(X86::eax, X86::ecx);
- m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::ecx);
- m_jit.sete_r(X86::eax);
-
- m_jit.link(wasNotImmediate, m_jit.label());
-
- m_jit.movzbl_rr(X86::eax, X86::eax);
- m_jit.cmpl_i32r(0, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJnz(), i + 2 + target));
-
- i += 3;
- break;
- };
- case op_jneq_null: {
- unsigned src = instruction[i + 1].u.operand;
- unsigned target = instruction[i + 2].u.operand;
-
- emitGetArg(src, X86::eax);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc isImmediate = m_jit.emitUnlinkedJnz();
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.testl_i32m(MasqueradesAsUndefined, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::ecx);
- m_jit.setz_r(X86::eax);
-
- X86Assembler::JmpSrc wasNotImmediate = m_jit.emitUnlinkedJmp();
-
- m_jit.link(isImmediate, m_jit.label());
-
- m_jit.movl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::ecx);
- m_jit.andl_rr(X86::eax, X86::ecx);
- m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::ecx);
- m_jit.setne_r(X86::eax);
-
- m_jit.link(wasNotImmediate, m_jit.label());
-
- m_jit.movzbl_rr(X86::eax, X86::eax);
- m_jit.cmpl_i32r(0, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJnz(), i + 2 + target));
-
- i += 3;
- break;
- }
- case op_post_inc: {
- int srcDst = instruction[i + 2].u.operand;
- emitGetArg(srcDst, X86::eax);
- m_jit.movl_rr(X86::eax, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(srcDst, X86::edx);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_unexpected_load: {
- JSValue* v = m_codeBlock->unexpectedConstants[instruction[i + 2].u.operand];
- m_jit.movl_i32r(asInteger(v), X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_jsr: {
- int retAddrDst = instruction[i + 1].u.operand;
- int target = instruction[i + 2].u.operand;
- m_jit.movl_i32m(0, sizeof(Register) * retAddrDst, X86::edi);
- X86Assembler::JmpDst addrPosition = m_jit.label();
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
- X86Assembler::JmpDst sretTarget = m_jit.label();
- m_jsrSites.append(JSRInfo(addrPosition, sretTarget));
- i += 3;
- break;
- }
- case op_sret: {
- m_jit.jmp_m(sizeof(Register) * instruction[i + 1].u.operand, X86::edi);
- i += 2;
- break;
- }
- case op_eq: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
- m_jit.cmpl_rr(X86::edx, X86::eax);
- m_jit.sete_r(X86::eax);
- m_jit.movzbl_rr(X86::eax, X86::eax);
- emitTagAsBoolImmediate(X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_lshift: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::ecx, i);
- emitFastArithImmToInt(X86::eax);
- emitFastArithImmToInt(X86::ecx);
- m_jit.shll_CLr(X86::eax);
- emitFastArithIntToImmOrSlowCase(X86::eax, i);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_bitand: {
- unsigned src1 = instruction[i + 2].u.operand;
- unsigned src2 = instruction[i + 3].u.operand;
- unsigned dst = instruction[i + 1].u.operand;
- if (JSValue* value = getConstantImmediateNumericArg(src1)) {
- emitGetArg(src2, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.andl_i32r(asInteger(value), X86::eax); // FIXME: make it more obvious this is relying on the format of JSImmediate
- emitPutResult(dst);
- } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
- emitGetArg(src1, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.andl_i32r(asInteger(value), X86::eax);
- emitPutResult(dst);
- } else {
- emitGetArg(src1, X86::eax);
- emitGetArg(src2, X86::edx);
- m_jit.andl_rr(X86::edx, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitPutResult(dst);
- }
- i += 5;
- break;
- }
- case op_rshift: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::ecx, i);
- emitFastArithImmToInt(X86::ecx);
- m_jit.sarl_CLr(X86::eax);
- emitFastArithPotentiallyReTagImmediate(X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_bitnot: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.xorl_i8r(~JSImmediate::TagBitTypeInteger, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_resolve_with_base: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_resolve_with_base);
- emitPutResult(instruction[i + 1].u.operand);
- emitPutResult(instruction[i + 2].u.operand, X86::edx);
- i += 4;
- break;
- }
- case op_new_func_exp: {
- FuncExprNode* func = (m_codeBlock->functionExpressions[instruction[i + 2].u.operand]).get();
- emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_new_func_exp);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_mod: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- emitJumpSlowCaseIfNotImmNum(X86::ecx, i);
- emitFastArithDeTagImmediate(X86::eax);
- m_slowCases.append(SlowCaseEntry(emitFastArithDeTagImmediateJumpIfZero(X86::ecx), i));
- m_jit.cdq();
- m_jit.idivl_r(X86::ecx);
- emitFastArithReTagImmediate(X86::edx);
- m_jit.movl_rr(X86::edx, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_jtrue: {
- unsigned target = instruction[i + 2].u.operand;
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::zeroImmediate()), X86::eax);
- X86Assembler::JmpSrc isZero = m_jit.emitUnlinkedJe();
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJne(), i + 2 + target));
-
- m_jit.cmpl_i32r(asInteger(JSImmediate::trueImmediate()), X86::eax);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJe(), i + 2 + target));
- m_jit.cmpl_i32r(asInteger(JSImmediate::falseImmediate()), X86::eax);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- m_jit.link(isZero, m_jit.label());
- i += 3;
- break;
- }
- CTI_COMPILE_BINARY_OP(op_less)
- case op_neq: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
- m_jit.cmpl_rr(X86::eax, X86::edx);
-
- m_jit.setne_r(X86::eax);
- m_jit.movzbl_rr(X86::eax, X86::eax);
- emitTagAsBoolImmediate(X86::eax);
-
- emitPutResult(instruction[i + 1].u.operand);
-
- i += 4;
- break;
- }
- case op_post_dec: {
- int srcDst = instruction[i + 2].u.operand;
- emitGetArg(srcDst, X86::eax);
- m_jit.movl_rr(X86::eax, X86::edx);
- emitJumpSlowCaseIfNotImmNum(X86::eax, i);
- m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
- emitPutResult(srcDst, X86::edx);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- CTI_COMPILE_BINARY_OP(op_urshift)
- case op_bitxor: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
- m_jit.xorl_rr(X86::edx, X86::eax);
- emitFastArithReTagImmediate(X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 5;
- break;
- }
- case op_new_regexp: {
- RegExp* regExp = m_codeBlock->regexps[instruction[i + 2].u.operand].get();
- emitPutArgConstant(reinterpret_cast<unsigned>(regExp), 0);
- emitCTICall(instruction + i, i, Machine::cti_op_new_regexp);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_bitor: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::edx);
- emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
- m_jit.orl_rr(X86::edx, X86::eax);
- emitPutResult(instruction[i + 1].u.operand);
- i += 5;
- break;
- }
- case op_call_eval: {
- compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
- i += 7;
- break;
- }
- case op_throw: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_throw);
- m_jit.addl_i8r(0x20, X86::esp);
- m_jit.popl_r(X86::ebx);
- m_jit.popl_r(X86::edi);
- m_jit.popl_r(X86::esi);
- m_jit.ret();
- i += 2;
- break;
- }
- case op_get_pnames: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_get_pnames);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_next_pname: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- unsigned target = instruction[i + 3].u.operand;
- emitCTICall(instruction + i, i, Machine::cti_op_next_pname);
- m_jit.testl_rr(X86::eax, X86::eax);
- X86Assembler::JmpSrc endOfIter = m_jit.emitUnlinkedJe();
- emitPutResult(instruction[i + 1].u.operand);
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 3 + target));
- m_jit.link(endOfIter, m_jit.label());
- i += 4;
- break;
- }
- case op_push_scope: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_push_scope);
- i += 2;
- break;
- }
- case op_pop_scope: {
- emitCTICall(instruction + i, i, Machine::cti_op_pop_scope);
- i += 1;
- break;
- }
- CTI_COMPILE_UNARY_OP(op_typeof)
- CTI_COMPILE_UNARY_OP(op_is_undefined)
- CTI_COMPILE_UNARY_OP(op_is_boolean)
- CTI_COMPILE_UNARY_OP(op_is_number)
- CTI_COMPILE_UNARY_OP(op_is_string)
- CTI_COMPILE_UNARY_OP(op_is_object)
- CTI_COMPILE_UNARY_OP(op_is_function)
- case op_stricteq: {
- compileOpStrictEq(instruction + i, i, OpStrictEq);
- i += 4;
- break;
- }
- case op_nstricteq: {
- compileOpStrictEq(instruction + i, i, OpNStrictEq);
- i += 4;
- break;
- }
- case op_to_jsnumber: {
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
-
- m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
- X86Assembler::JmpSrc wasImmediate = m_jit.emitUnlinkedJnz();
-
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.cmpl_i32m(NumberType, OBJECT_OFFSET(StructureID, m_typeInfo.m_type), X86::ecx);
-
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
-
- m_jit.link(wasImmediate, m_jit.label());
-
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_in: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_in);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_push_new_scope: {
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_push_new_scope);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_catch: {
- emitGetCTIParam(CTI_ARGS_callFrame, X86::edi); // edi := r
- emitPutResult(instruction[i + 1].u.operand);
- i += 2;
- break;
- }
- case op_jmp_scopes: {
- unsigned count = instruction[i + 1].u.operand;
- emitPutArgConstant(count, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_jmp_scopes);
- unsigned target = instruction[i + 2].u.operand;
- m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
- i += 3;
- break;
- }
- case op_put_by_index: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- emitPutArgConstant(instruction[i + 2].u.operand, 4);
- emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_put_by_index);
- i += 4;
- break;
- }
- case op_switch_imm: {
- unsigned tableIndex = instruction[i + 1].u.operand;
- unsigned defaultOffset = instruction[i + 2].u.operand;
- unsigned scrutinee = instruction[i + 3].u.operand;
-
- // create jump table for switch destinations, track this switch statement.
- SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTables[tableIndex];
- m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Immediate));
- jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
-
- emitGetPutArg(scrutinee, 0, X86::ecx);
- emitPutArgConstant(tableIndex, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_switch_imm);
- m_jit.jmp_r(X86::eax);
- i += 4;
- break;
- }
- case op_switch_char: {
- unsigned tableIndex = instruction[i + 1].u.operand;
- unsigned defaultOffset = instruction[i + 2].u.operand;
- unsigned scrutinee = instruction[i + 3].u.operand;
-
- // create jump table for switch destinations, track this switch statement.
- SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTables[tableIndex];
- m_switches.append(SwitchRecord(jumpTable, i, defaultOffset, SwitchRecord::Character));
- jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
-
- emitGetPutArg(scrutinee, 0, X86::ecx);
- emitPutArgConstant(tableIndex, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_switch_char);
- m_jit.jmp_r(X86::eax);
- i += 4;
- break;
- }
- case op_switch_string: {
- unsigned tableIndex = instruction[i + 1].u.operand;
- unsigned defaultOffset = instruction[i + 2].u.operand;
- unsigned scrutinee = instruction[i + 3].u.operand;
-
- // create jump table for switch destinations, track this switch statement.
- StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTables[tableIndex];
- m_switches.append(SwitchRecord(jumpTable, i, defaultOffset));
-
- emitGetPutArg(scrutinee, 0, X86::ecx);
- emitPutArgConstant(tableIndex, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_switch_string);
- m_jit.jmp_r(X86::eax);
- i += 4;
- break;
- }
- case op_del_by_val: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_del_by_val);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_put_getter: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_put_getter);
- i += 4;
- break;
- }
- case op_put_setter: {
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_put_setter);
- i += 4;
- break;
- }
- case op_new_error: {
- JSValue* message = m_codeBlock->unexpectedConstants[instruction[i + 3].u.operand];
- emitPutArgConstant(instruction[i + 2].u.operand, 0);
- emitPutArgConstant(asInteger(message), 4);
- emitPutArgConstant(m_codeBlock->lineNumberForVPC(&instruction[i]), 8);
- emitCTICall(instruction + i, i, Machine::cti_op_new_error);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_debug: {
- emitPutArgConstant(instruction[i + 1].u.operand, 0);
- emitPutArgConstant(instruction[i + 2].u.operand, 4);
- emitPutArgConstant(instruction[i + 3].u.operand, 8);
- emitCTICall(instruction + i, i, Machine::cti_op_debug);
- i += 4;
- break;
- }
- case op_eq_null: {
- unsigned dst = instruction[i + 1].u.operand;
- unsigned src1 = instruction[i + 2].u.operand;
-
- emitGetArg(src1, X86::eax);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc isImmediate = m_jit.emitUnlinkedJnz();
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.testl_i32m(MasqueradesAsUndefined, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::ecx);
- m_jit.setnz_r(X86::eax);
-
- X86Assembler::JmpSrc wasNotImmediate = m_jit.emitUnlinkedJmp();
-
- m_jit.link(isImmediate, m_jit.label());
-
- m_jit.movl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::ecx);
- m_jit.andl_rr(X86::eax, X86::ecx);
- m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::ecx);
- m_jit.sete_r(X86::eax);
-
- m_jit.link(wasNotImmediate, m_jit.label());
-
- m_jit.movzbl_rr(X86::eax, X86::eax);
- emitTagAsBoolImmediate(X86::eax);
- emitPutResult(dst);
-
- i += 3;
- break;
- }
- case op_neq_null: {
- unsigned dst = instruction[i + 1].u.operand;
- unsigned src1 = instruction[i + 2].u.operand;
-
- emitGetArg(src1, X86::eax);
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc isImmediate = m_jit.emitUnlinkedJnz();
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- m_jit.testl_i32m(MasqueradesAsUndefined, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::ecx);
- m_jit.setz_r(X86::eax);
-
- X86Assembler::JmpSrc wasNotImmediate = m_jit.emitUnlinkedJmp();
-
- m_jit.link(isImmediate, m_jit.label());
-
- m_jit.movl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::ecx);
- m_jit.andl_rr(X86::eax, X86::ecx);
- m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::ecx);
- m_jit.setne_r(X86::eax);
-
- m_jit.link(wasNotImmediate, m_jit.label());
-
- m_jit.movzbl_rr(X86::eax, X86::eax);
- emitTagAsBoolImmediate(X86::eax);
- emitPutResult(dst);
-
- i += 3;
- break;
- }
- case op_enter: {
- // Even though CTI doesn't use them, we initialize our constant
- // registers to zap stale pointers, to avoid unnecessarily prolonging
- // object lifetime and increasing GC pressure.
- size_t count = m_codeBlock->numVars + m_codeBlock->constantRegisters.size();
- for (size_t j = 0; j < count; ++j)
- emitInitRegister(j);
-
- i+= 1;
- break;
- }
- case op_enter_with_activation: {
- // Even though CTI doesn't use them, we initialize our constant
- // registers to zap stale pointers, to avoid unnecessarily prolonging
- // object lifetime and increasing GC pressure.
- size_t count = m_codeBlock->numVars + m_codeBlock->constantRegisters.size();
- for (size_t j = 0; j < count; ++j)
- emitInitRegister(j);
-
- emitCTICall(instruction + i, i, Machine::cti_op_push_activation);
- emitPutResult(instruction[i + 1].u.operand);
-
- i+= 2;
- break;
- }
- case op_create_arguments: {
- emitCTICall(instruction + i, i, (m_codeBlock->numParameters == 1) ? Machine::cti_op_create_arguments_no_params : Machine::cti_op_create_arguments);
- i += 1;
- break;
- }
- case op_convert_this: {
- emitGetArg(instruction[i + 1].u.operand, X86::eax);
-
- emitJumpSlowCaseIfNotJSCell(X86::eax, i);
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::edx);
- m_jit.testl_i32m(NeedsThisConversion, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::edx);
- m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
-
- i += 2;
- break;
- }
- case op_profile_will_call: {
- emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
- m_jit.cmpl_i32m(0, X86::eax);
- X86Assembler::JmpSrc noProfiler = m_jit.emitUnlinkedJe();
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::eax);
- emitCTICall(instruction + i, i, Machine::cti_op_profile_will_call);
- m_jit.link(noProfiler, m_jit.label());
-
- i += 2;
- break;
- }
- case op_profile_did_call: {
- emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
- m_jit.cmpl_i32m(0, X86::eax);
- X86Assembler::JmpSrc noProfiler = m_jit.emitUnlinkedJe();
- emitGetPutArg(instruction[i + 1].u.operand, 0, X86::eax);
- emitCTICall(instruction + i, i, Machine::cti_op_profile_did_call);
- m_jit.link(noProfiler, m_jit.label());
-
- i += 2;
- break;
- }
- case op_get_array_length:
- case op_get_by_id_chain:
- case op_get_by_id_generic:
- case op_get_by_id_proto:
- case op_get_by_id_self:
- case op_get_string_length:
- case op_put_by_id_generic:
- case op_put_by_id_replace:
- case op_put_by_id_transition:
- ASSERT_NOT_REACHED();
- }
- }
-
- ASSERT(propertyAccessInstructionIndex == m_codeBlock->propertyAccessInstructions.size());
- ASSERT(callLinkInfoIndex == m_codeBlock->callLinkInfos.size());
-}
-
-
-void CTI::privateCompileLinkPass()
-{
- unsigned jmpTableCount = m_jmpTable.size();
- for (unsigned i = 0; i < jmpTableCount; ++i)
- m_jit.link(m_jmpTable[i].from, m_labels[m_jmpTable[i].to]);
- m_jmpTable.clear();
-}
-
-#define CTI_COMPILE_BINARY_OP_SLOW_CASE(name) \
- case name: { \
- m_jit.link(iter->from, m_jit.label()); \
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx); \
- emitCTICall(instruction + i, i, Machine::cti_##name); \
- emitPutResult(instruction[i + 1].u.operand); \
- i += 4; \
- break; \
- }
-
-void CTI::privateCompileSlowCases()
-{
- unsigned propertyAccessInstructionIndex = 0;
- unsigned callLinkInfoIndex = 0;
-
- Instruction* instruction = m_codeBlock->instructions.begin();
- for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end(); ++iter) {
- unsigned i = iter->to;
- switch (OpcodeID opcodeID = m_machine->getOpcodeID(instruction[i].u.opcode)) {
- case op_convert_this: {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_convert_this);
- emitPutResult(instruction[i + 1].u.operand);
- i += 2;
- break;
- }
- case op_add: {
- unsigned dst = instruction[i + 1].u.operand;
- unsigned src1 = instruction[i + 2].u.operand;
- unsigned src2 = instruction[i + 3].u.operand;
- if (JSValue* value = getConstantImmediateNumericArg(src1)) {
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.subl_i32r(getDeTaggedConstantImmediate(value), X86::edx);
- m_jit.link(notImm, m_jit.label());
- emitGetPutArg(src1, 0, X86::ecx);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_add);
- emitPutResult(dst);
- } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.subl_i32r(getDeTaggedConstantImmediate(value), X86::eax);
- m_jit.link(notImm, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitGetPutArg(src2, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_add);
- emitPutResult(dst);
- } else {
- OperandTypes types = OperandTypes::fromInt(instruction[i + 4].u.operand);
- if (types.first().mightBeNumber() && types.second().mightBeNumber())
- compileBinaryArithOpSlowCase(instruction + i, op_add, iter, dst, src1, src2, types, i);
- else
- ASSERT_NOT_REACHED();
- }
-
- i += 5;
- break;
- }
- case op_get_by_val: {
- // The slow case that handles accesses to arrays (below) may jump back up to here.
- X86Assembler::JmpDst beginGetByValSlow = m_jit.label();
-
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitFastArithIntToImmNoCheck(X86::edx);
- m_jit.link(notImm, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_get_by_val);
- emitPutResult(instruction[i + 1].u.operand);
- m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 4]);
-
- // This is slow case that handles accesses to arrays above the fast cut-off.
- // First, check if this is an access to the vector
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(ArrayStorage, m_vectorLength), X86::ecx);
- m_jit.link(m_jit.emitUnlinkedJbe(), beginGetByValSlow);
-
- // okay, missed the fast region, but it is still in the vector. Get the value.
- m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_vector[0]), X86::ecx, X86::edx, sizeof(JSValue*), X86::ecx);
- // Check whether the value loaded is zero; if so we need to return undefined.
- m_jit.testl_rr(X86::ecx, X86::ecx);
- m_jit.link(m_jit.emitUnlinkedJe(), beginGetByValSlow);
- emitPutResult(instruction[i + 1].u.operand, X86::ecx);
-
- i += 4;
- break;
- }
- case op_sub: {
- compileBinaryArithOpSlowCase(instruction + i, op_sub, iter, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
- i += 5;
- break;
- }
- case op_negate: {
- m_jit.link(iter->from, m_jit.label());
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_negate);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_rshift: {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::ecx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_rshift);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_lshift: {
- X86Assembler::JmpSrc notImm1 = iter->from;
- X86Assembler::JmpSrc notImm2 = (++iter)->from;
- m_jit.link((++iter)->from, m_jit.label());
- emitGetArg(instruction[i + 2].u.operand, X86::eax);
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- m_jit.link(notImm1, m_jit.label());
- m_jit.link(notImm2, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::ecx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_lshift);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_loop_if_less: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::edx, 0);
- emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_loop_if_less);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
- } else {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_loop_if_less);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
- }
- i += 4;
- break;
- }
- case op_put_by_id: {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
-
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 8);
- X86Assembler::JmpSrc call = emitCTICall(instruction + i, i, Machine::cti_op_put_by_id);
-
- // Track the location of the call; this will be used to recover repatch information.
- ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
- m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
- ++propertyAccessInstructionIndex;
-
- i += 8;
- break;
- }
- case op_get_by_id: {
- // As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset
- // so that we only need track one pointer into the slow case code - we track a pointer to the location
- // of the call (which we can use to look up the repatch information), but should a array-length or
- // prototype access trampoline fail we want to bail out back to here. To do so we can subtract back
- // the distance from the call to the head of the slow case.
-
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
-
-#ifndef NDEBUG
- X86Assembler::JmpDst coldPathBegin = m_jit.label();
-#endif
- emitPutArg(X86::eax, 0);
- Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
- emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
- X86Assembler::JmpSrc call = emitCTICall(instruction + i, i, Machine::cti_op_get_by_id);
- ASSERT(X86Assembler::getDifferenceBetweenLabels(coldPathBegin, call) == repatchOffsetGetByIdSlowCaseCall);
- emitPutResult(instruction[i + 1].u.operand);
-
- // Track the location of the call; this will be used to recover repatch information.
- ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
- m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
- ++propertyAccessInstructionIndex;
-
- i += 8;
- break;
- }
- case op_loop_if_lesseq: {
- emitSlowScriptCheck(instruction + i, i);
-
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::edx, 0);
- emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_loop_if_lesseq);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
- } else {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_loop_if_lesseq);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
- }
- i += 4;
- break;
- }
- case op_pre_inc: {
- unsigned srcDst = instruction[i + 1].u.operand;
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
- m_jit.link(notImm, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_pre_inc);
- emitPutResult(srcDst);
- i += 2;
- break;
- }
- case op_put_by_val: {
- // Normal slow cases - either is not an immediate imm, or is an array.
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitFastArithIntToImmNoCheck(X86::edx);
- m_jit.link(notImm, m_jit.label());
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitPutArg(X86::ecx, 8);
- emitCTICall(instruction + i, i, Machine::cti_op_put_by_val);
- m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 4]);
-
- // slow cases for immediate int accesses to arrays
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitGetArg(instruction[i + 3].u.operand, X86::ecx);
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitPutArg(X86::ecx, 8);
- emitCTICall(instruction + i, i, Machine::cti_op_put_by_val_array);
-
- i += 4;
- break;
- }
- case op_loop_if_true: {
- emitSlowScriptCheck(instruction + i, i);
-
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
- m_jit.testl_rr(X86::eax, X86::eax);
- unsigned target = instruction[i + 2].u.operand;
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
- i += 3;
- break;
- }
- case op_pre_dec: {
- unsigned srcDst = instruction[i + 1].u.operand;
- X86Assembler::JmpSrc notImm = iter->from;
- m_jit.link((++iter)->from, m_jit.label());
- m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
- m_jit.link(notImm, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_pre_dec);
- emitPutResult(srcDst);
- i += 2;
- break;
- }
- case op_jnless: {
- unsigned target = instruction[i + 3].u.operand;
- JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
- if (src2imm) {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::edx, 0);
- emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_jless);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
- } else {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_jless);
- m_jit.testl_rr(X86::eax, X86::eax);
- m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
- }
- i += 4;
- break;
- }
- case op_not: {
- m_jit.link(iter->from, m_jit.label());
- m_jit.xorl_i8r(JSImmediate::FullTagTypeBool, X86::eax);
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_not);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_jfalse: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
- m_jit.testl_rr(X86::eax, X86::eax);
- unsigned target = instruction[i + 2].u.operand;
- m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 2 + target]); // inverted!
- i += 3;
- break;
- }
- case op_post_inc: {
- unsigned srcDst = instruction[i + 2].u.operand;
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_post_inc);
- emitPutResult(instruction[i + 1].u.operand);
- emitPutResult(srcDst, X86::edx);
- i += 3;
- break;
- }
- case op_bitnot: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_bitnot);
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
- case op_bitand: {
- unsigned src1 = instruction[i + 2].u.operand;
- unsigned src2 = instruction[i + 3].u.operand;
- unsigned dst = instruction[i + 1].u.operand;
- if (getConstantImmediateNumericArg(src1)) {
- m_jit.link(iter->from, m_jit.label());
- emitGetPutArg(src1, 0, X86::ecx);
- emitPutArg(X86::eax, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_bitand);
- emitPutResult(dst);
- } else if (getConstantImmediateNumericArg(src2)) {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitGetPutArg(src2, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_bitand);
- emitPutResult(dst);
- } else {
- m_jit.link(iter->from, m_jit.label());
- emitGetPutArg(src1, 0, X86::ecx);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_bitand);
- emitPutResult(dst);
- }
- i += 5;
- break;
- }
- case op_jtrue: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
- m_jit.testl_rr(X86::eax, X86::eax);
- unsigned target = instruction[i + 2].u.operand;
- m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
- i += 3;
- break;
- }
- case op_post_dec: {
- unsigned srcDst = instruction[i + 2].u.operand;
- m_jit.link(iter->from, m_jit.label());
- m_jit.link((++iter)->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_post_dec);
- emitPutResult(instruction[i + 1].u.operand);
- emitPutResult(srcDst, X86::edx);
- i += 3;
- break;
- }
- case op_bitxor: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_bitxor);
- emitPutResult(instruction[i + 1].u.operand);
- i += 5;
- break;
- }
- case op_bitor: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_bitor);
- emitPutResult(instruction[i + 1].u.operand);
- i += 5;
- break;
- }
- case op_eq: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_eq);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_neq: {
- m_jit.link(iter->from, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::edx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_neq);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- CTI_COMPILE_BINARY_OP_SLOW_CASE(op_stricteq);
- CTI_COMPILE_BINARY_OP_SLOW_CASE(op_nstricteq);
- case op_instanceof: {
- m_jit.link(iter->from, m_jit.label());
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
- emitGetPutArg(instruction[i + 4].u.operand, 8, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_instanceof);
- emitPutResult(instruction[i + 1].u.operand);
- i += 5;
- break;
- }
- case op_mod: {
- X86Assembler::JmpSrc notImm1 = iter->from;
- X86Assembler::JmpSrc notImm2 = (++iter)->from;
- m_jit.link((++iter)->from, m_jit.label());
- emitFastArithReTagImmediate(X86::eax);
- emitFastArithReTagImmediate(X86::ecx);
- m_jit.link(notImm1, m_jit.label());
- m_jit.link(notImm2, m_jit.label());
- emitPutArg(X86::eax, 0);
- emitPutArg(X86::ecx, 4);
- emitCTICall(instruction + i, i, Machine::cti_op_mod);
- emitPutResult(instruction[i + 1].u.operand);
- i += 4;
- break;
- }
- case op_mul: {
- int dst = instruction[i + 1].u.operand;
- int src1 = instruction[i + 2].u.operand;
- int src2 = instruction[i + 3].u.operand;
- JSValue* src1Value = getConstantImmediateNumericArg(src1);
- JSValue* src2Value = getConstantImmediateNumericArg(src2);
- int32_t value;
- if (src1Value && ((value = JSImmediate::intValue(src1Value)) > 0)) {
- m_jit.link(iter->from, m_jit.label());
- // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
- emitGetPutArg(src1, 0, X86::ecx);
- emitGetPutArg(src2, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_mul);
- emitPutResult(dst);
- } else if (src2Value && ((value = JSImmediate::intValue(src2Value)) > 0)) {
- m_jit.link(iter->from, m_jit.label());
- // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
- emitGetPutArg(src1, 0, X86::ecx);
- emitGetPutArg(src2, 4, X86::ecx);
- emitCTICall(instruction + i, i, Machine::cti_op_mul);
- emitPutResult(dst);
- } else
- compileBinaryArithOpSlowCase(instruction + i, op_mul, iter, dst, src1, src2, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
- i += 5;
- break;
- }
-
- case op_call:
- case op_call_eval:
- case op_construct: {
- int dst = instruction[i + 1].u.operand;
- int callee = instruction[i + 2].u.operand;
- int argCount = instruction[i + 5].u.operand;
-
- m_jit.link(iter->from, m_jit.label());
-
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID != op_call_eval)
- compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
-
- // Fast check for JS function.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
- X86Assembler::JmpSrc callLinkFailNotObject = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
- X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
-
- // This handles JSFunctions
- emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
- // initialize the new call frame (pointed to by edx, after the last call), then set edi to point to it.
- compileOpCallInitializeCallFrame(callee, argCount);
- m_jit.movl_rr(X86::edx, X86::edi);
-
- // Try to link & repatch this call.
- CallLinkInfo* info = &(m_codeBlock->callLinkInfos[callLinkInfoIndex]);
- emitPutArgConstant(reinterpret_cast<unsigned>(info), 4);
- m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
- emitCTICall(instruction + i, i, Machine::cti_vm_lazyLinkCall);
- emitNakedCall(i, X86::eax);
- X86Assembler::JmpSrc storeResultForFirstRun = m_jit.emitUnlinkedJmp();
-
- // This is the address for the cold path *after* the first run (which tries to link the call).
- m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = m_jit.label();
-
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID != op_call_eval)
- compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
-
- // Check for JSFunctions.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
- X86Assembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
- X86Assembler::JmpSrc isJSFunction = m_jit.emitUnlinkedJe();
-
- // This handles host functions
- X86Assembler::JmpDst notJSFunctionlabel = m_jit.label();
- m_jit.link(isNotObject, notJSFunctionlabel);
- m_jit.link(callLinkFailNotObject, notJSFunctionlabel);
- m_jit.link(callLinkFailNotJSFunction, notJSFunctionlabel);
- emitCTICall(instruction + i, i, ((opcodeID == op_construct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
- X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
-
- // Next, handle JSFunctions...
- m_jit.link(isJSFunction, m_jit.label());
- emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
- // initialize the new call frame (pointed to by edx, after the last call).
- compileOpCallInitializeCallFrame(callee, argCount);
- m_jit.movl_rr(X86::edx, X86::edi);
-
- // load ctiCode from the new codeBlock.
- m_jit.movl_mr(OBJECT_OFFSET(CodeBlock, ctiCode), X86::eax, X86::eax);
-
- // Move the new callframe into edi.
- m_jit.movl_rr(X86::edx, X86::edi);
-
- // Check the ctiCode has been generated (if not compile it now), and make the call.
- m_jit.testl_rr(X86::eax, X86::eax);
- X86Assembler::JmpSrc hasCode = m_jit.emitUnlinkedJne();
- emitCTICall(instruction + i, i, Machine::cti_vm_compile);
- m_jit.link(hasCode, m_jit.label());
-
- emitNakedCall(i, X86::eax);
-
- // Put the return value in dst. In the interpreter, op_ret does this.
- X86Assembler::JmpDst storeResult = m_jit.label();
- m_jit.link(wasNotJSFunction, storeResult);
- m_jit.link(storeResultForFirstRun, storeResult);
- emitPutResult(dst);
-
-#if ENABLE(CODEBLOCK_SAMPLING)
- m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
-#endif
- ++callLinkInfoIndex;
-
- i += 7;
- break;
- }
- case op_to_jsnumber: {
- m_jit.link(iter->from, m_jit.label());
- m_jit.link(iter->from, m_jit.label());
-
- emitPutArg(X86::eax, 0);
- emitCTICall(instruction + i, i, Machine::cti_op_to_jsnumber);
-
- emitPutResult(instruction[i + 1].u.operand);
- i += 3;
- break;
- }
-
- default:
- ASSERT_NOT_REACHED();
- break;
- }
-
- m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i]);
- }
-
- ASSERT(propertyAccessInstructionIndex == m_codeBlock->propertyAccessInstructions.size());
- ASSERT(callLinkInfoIndex == m_codeBlock->callLinkInfos.size());
-}
-
-void CTI::privateCompile()
-{
-#if ENABLE(CODEBLOCK_SAMPLING)
- m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
-#endif
-#if ENABLE(OPCODE_SAMPLING)
- m_jit.movl_i32m(m_machine->sampler()->encodeSample(m_codeBlock->instructions.begin()), m_machine->sampler()->sampleSlot());
-#endif
-
- // Could use a popl_m, but would need to offset the following instruction if so.
- m_jit.popl_r(X86::ecx);
- emitPutToCallFrameHeader(X86::ecx, RegisterFile::ReturnPC);
-
- X86Assembler::JmpSrc slowRegisterFileCheck;
- X86Assembler::JmpDst afterRegisterFileCheck;
- if (m_codeBlock->codeType == FunctionCode) {
- // In the case of a fast linked call, we do not set this up in the caller.
- m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), RegisterFile::CodeBlock * static_cast<int>(sizeof(Register)), X86::edi);
-
- emitGetCTIParam(CTI_ARGS_registerFile, X86::eax);
- m_jit.leal_mr(m_codeBlock->numCalleeRegisters * sizeof(Register), X86::edi, X86::edx);
- m_jit.cmpl_mr(OBJECT_OFFSET(RegisterFile, m_end), X86::eax, X86::edx);
- slowRegisterFileCheck = m_jit.emitUnlinkedJg();
- afterRegisterFileCheck = m_jit.label();
- }
-
- privateCompileMainPass();
- privateCompileLinkPass();
- privateCompileSlowCases();
-
- if (m_codeBlock->codeType == FunctionCode) {
- m_jit.link(slowRegisterFileCheck, m_jit.label());
- emitCTICall(m_codeBlock->instructions.begin(), 0, Machine::cti_register_file_check);
- X86Assembler::JmpSrc backToBody = m_jit.emitUnlinkedJmp();
- m_jit.link(backToBody, afterRegisterFileCheck);
- }
-
- ASSERT(m_jmpTable.isEmpty());
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- // Translate vPC offsets into addresses in JIT generated code, for switch tables.
- for (unsigned i = 0; i < m_switches.size(); ++i) {
- SwitchRecord record = m_switches[i];
- unsigned opcodeIndex = record.m_opcodeIndex;
-
- if (record.m_type != SwitchRecord::String) {
- ASSERT(record.m_type == SwitchRecord::Immediate || record.m_type == SwitchRecord::Character);
- ASSERT(record.m_jumpTable.m_simpleJumpTable->branchOffsets.size() == record.m_jumpTable.m_simpleJumpTable->ctiOffsets.size());
-
- record.m_jumpTable.m_simpleJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
-
- for (unsigned j = 0; j < record.m_jumpTable.m_simpleJumpTable->branchOffsets.size(); ++j) {
- unsigned offset = record.m_jumpTable.m_simpleJumpTable->branchOffsets[j];
- record.m_jumpTable.m_simpleJumpTable->ctiOffsets[j] = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_simpleJumpTable->ctiDefault;
- }
- } else {
- ASSERT(record.m_type == SwitchRecord::String);
-
- record.m_jumpTable.m_stringJumpTable->ctiDefault = m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + record.m_defaultOffset]);
-
- StringJumpTable::StringOffsetTable::iterator end = record.m_jumpTable.m_stringJumpTable->offsetTable.end();
- for (StringJumpTable::StringOffsetTable::iterator it = record.m_jumpTable.m_stringJumpTable->offsetTable.begin(); it != end; ++it) {
- unsigned offset = it->second.branchOffset;
- it->second.ctiOffset = offset ? m_jit.getRelocatedAddress(code, m_labels[opcodeIndex + 3 + offset]) : record.m_jumpTable.m_stringJumpTable->ctiDefault;
- }
- }
- }
-
- for (Vector<HandlerInfo>::iterator iter = m_codeBlock->exceptionHandlers.begin(); iter != m_codeBlock->exceptionHandlers.end(); ++iter)
- iter->nativeCode = m_jit.getRelocatedAddress(code, m_labels[iter->target]);
-
- for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
- if (iter->to)
- X86Assembler::link(code, iter->from, iter->to);
- m_codeBlock->ctiReturnAddressVPCMap.add(m_jit.getRelocatedAddress(code, iter->from), iter->opcodeIndex);
- }
-
- // Link absolute addresses for jsr
- for (Vector<JSRInfo>::iterator iter = m_jsrSites.begin(); iter != m_jsrSites.end(); ++iter)
- X86Assembler::linkAbsoluteAddress(code, iter->addrPosition, iter->target);
-
- for (unsigned i = 0; i < m_codeBlock->propertyAccessInstructions.size(); ++i) {
- StructureStubInfo& info = m_codeBlock->propertyAccessInstructions[i];
- info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_propertyAccessCompilationInfo[i].callReturnLocation);
- info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_propertyAccessCompilationInfo[i].hotPathBegin);
- }
- for (unsigned i = 0; i < m_codeBlock->callLinkInfos.size(); ++i) {
- CallLinkInfo& info = m_codeBlock->callLinkInfos[i];
- info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].callReturnLocation);
- info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].hotPathBegin);
- info.hotPathOther = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].hotPathOther);
- info.coldPathOther = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].coldPathOther);
- }
-
- m_codeBlock->ctiCode = code;
-}
-
-void CTI::privateCompileGetByIdSelf(StructureID* structureID, size_t cachedOffset, void* returnAddress)
-{
- // Check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - getDirectOffset
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
- m_jit.ret();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- ctiRepatchCallByReturnAddress(returnAddress, code);
-}
-
-void CTI::privateCompileGetByIdProto(StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress)
-{
-#if USE(CTI_REPATCH_PIC)
- StructureStubInfo& info = m_codeBlock->getStubInfo(returnAddress);
-
- // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
- ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is
- // referencing the prototype object - let's speculatively load it's table nice and early!)
- JSObject* protoObject = asObject(structureID->prototypeForLookup(m_callFrame));
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
-
- // check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Check the prototype object's StructureID had not changed.
- StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructureID), static_cast<void*>(protoStructureIDAddress));
- X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - getDirectOffset
- m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::ecx);
-
- X86Assembler::JmpSrc success = m_jit.emitUnlinkedJmp();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- // Use the repatch information to link the failure cases back to the original slow case routine.
- void* slowCaseBegin = reinterpret_cast<char*>(info.callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
- X86Assembler::link(code, failureCases1, slowCaseBegin);
- X86Assembler::link(code, failureCases2, slowCaseBegin);
- X86Assembler::link(code, failureCases3, slowCaseBegin);
-
- // On success return back to the hot patch code, at a point it will perform the store to dest for us.
- intptr_t successDest = (intptr_t)(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
- X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
-
- // Track the stub we have created so that it will be deleted later.
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- // Finally repatch the jump to sow case back in the hot path to jump here instead.
- // FIXME: should revert this repatching, on failure.
- intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
- X86Assembler::repatchBranchOffset(jmpLocation, code);
-#else
- // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is
- // referencing the prototype object - let's speculatively load it's table nice and early!)
- JSObject* protoObject = asObject(structureID->prototypeForLookup(m_callFrame));
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
-
- // check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Check the prototype object's StructureID had not changed.
- StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructureID), static_cast<void*>(protoStructureIDAddress));
- X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - getDirectOffset
- m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
-
- m_jit.ret();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- ctiRepatchCallByReturnAddress(returnAddress, code);
-#endif
-}
-
-void CTI::privateCompileGetByIdChain(StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
-{
- ASSERT(count);
-
- Vector<X86Assembler::JmpSrc> bucketsOfFail;
-
- // Check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- bucketsOfFail.append(m_jit.emitUnlinkedJne());
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- bucketsOfFail.append(m_jit.emitUnlinkedJne());
-
- StructureID* currStructureID = structureID;
- RefPtr<StructureID>* chainEntries = chain->head();
- JSObject* protoObject = 0;
- for (unsigned i = 0; i<count; ++i) {
- protoObject = asObject(currStructureID->prototypeForLookup(m_callFrame));
- currStructureID = chainEntries[i].get();
-
- // Check the prototype object's StructureID had not changed.
- StructureID** protoStructureIDAddress = &(protoObject->m_structureID);
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(currStructureID), static_cast<void*>(protoStructureIDAddress));
- bucketsOfFail.append(m_jit.emitUnlinkedJne());
- }
- ASSERT(protoObject);
-
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
- m_jit.movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
- m_jit.ret();
-
- bucketsOfFail.append(m_jit.emitUnlinkedJmp());
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
- X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- ctiRepatchCallByReturnAddress(returnAddress, code);
-}
-
-void CTI::privateCompilePutByIdReplace(StructureID* structureID, size_t cachedOffset, void* returnAddress)
-{
- // check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(structureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // checks out okay! - putDirectOffset
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
- m_jit.ret();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
- X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
-
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- ctiRepatchCallByReturnAddress(returnAddress, code);
-}
-
-extern "C" {
-
- static JSObject* resizePropertyStorage(JSObject* baseObject, size_t oldSize, size_t newSize)
- {
- baseObject->allocatePropertyStorageInline(oldSize, newSize);
- return baseObject;
- }
-
-}
-
-static inline bool transitionWillNeedStorageRealloc(StructureID* oldStructureID, StructureID* newStructureID)
-{
- return oldStructureID->propertyStorageCapacity() != newStructureID->propertyStorageCapacity();
-}
-
-void CTI::privateCompilePutByIdTransition(StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
-{
- Vector<X86Assembler::JmpSrc, 16> failureCases;
- // check eax is an object of the right StructureID.
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- failureCases.append(m_jit.emitUnlinkedJne());
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(oldStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
- failureCases.append(m_jit.emitUnlinkedJne());
- Vector<X86Assembler::JmpSrc> successCases;
-
- // ecx = baseObject
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
- // proto(ecx) = baseObject->structureID()->prototype()
- m_jit.cmpl_i32m(ObjectType, OBJECT_OFFSET(StructureID, m_typeInfo) + OBJECT_OFFSET(TypeInfo, m_type), X86::ecx);
- failureCases.append(m_jit.emitUnlinkedJne());
- m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_prototype), X86::ecx, X86::ecx);
-
- // ecx = baseObject->m_structureID
- for (RefPtr<StructureID>* it = sIDC->head(); *it; ++it) {
- // null check the prototype
- m_jit.cmpl_i32r(asInteger(jsNull()), X86::ecx);
- successCases.append(m_jit.emitUnlinkedJe());
-
- // Check the structure id
- m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(it->get()), OBJECT_OFFSET(JSCell, m_structureID), X86::ecx);
- failureCases.append(m_jit.emitUnlinkedJne());
-
- m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::ecx, X86::ecx);
- m_jit.cmpl_i32m(ObjectType, OBJECT_OFFSET(StructureID, m_typeInfo) + OBJECT_OFFSET(TypeInfo, m_type), X86::ecx);
- failureCases.append(m_jit.emitUnlinkedJne());
- m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_prototype), X86::ecx, X86::ecx);
- }
-
- failureCases.append(m_jit.emitUnlinkedJne());
- for (unsigned i = 0; i < successCases.size(); ++i)
- m_jit.link(successCases[i], m_jit.label());
-
- X86Assembler::JmpSrc callTarget;
-
- // emit a call only if storage realloc is needed
- if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
- m_jit.pushl_r(X86::edx);
- m_jit.pushl_i32(newStructureID->propertyStorageCapacity());
- m_jit.pushl_i32(oldStructureID->propertyStorageCapacity());
- m_jit.pushl_r(X86::eax);
- callTarget = m_jit.emitCall();
- m_jit.addl_i32r(3 * sizeof(void*), X86::esp);
- m_jit.popl_r(X86::edx);
- }
-
- // Assumes m_refCount can be decremented easily, refcount decrement is safe as
- // codeblock should ensure oldStructureID->m_refCount > 0
- m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
- m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
- m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
-
- // write the value
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
-
- m_jit.ret();
-
- X86Assembler::JmpSrc failureJump;
- if (failureCases.size()) {
- for (unsigned i = 0; i < failureCases.size(); ++i)
- m_jit.link(failureCases[i], m_jit.label());
- m_jit.emitRestoreArgumentReferenceForTrampoline();
- failureJump = m_jit.emitUnlinkedJmp();
- }
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- if (failureCases.size())
- X86Assembler::link(code, failureJump, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
-
- if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID))
- X86Assembler::link(code, callTarget, reinterpret_cast<void*>(resizePropertyStorage));
-
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- ctiRepatchCallByReturnAddress(returnAddress, code);
-}
-
-void CTI::unlinkCall(CallLinkInfo* callLinkInfo)
-{
- // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid
- // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
- // match). Reset the check so it no longer matches.
- reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = asPointer(JSImmediate::impossibleValue());
-}
-
-void CTI::linkCall(JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, CallLinkInfo* callLinkInfo, int callerArgCount)
-{
- // Currently we only link calls with the exact number of arguments.
- if (callerArgCount == calleeCodeBlock->numParameters) {
- ASSERT(!callLinkInfo->isLinked());
-
- calleeCodeBlock->addCaller(callLinkInfo);
-
- reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = callee;
- ctiRepatchCallByReturnAddress(callLinkInfo->hotPathOther, ctiCode);
- }
-
- // repatch the instruction that jumps out to the cold path, so that we only try to link once.
- void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(callLinkInfo->hotPathBegin) + repatchOffsetOpCallCall);
- ctiRepatchCallByReturnAddress(repatchCheck, callLinkInfo->coldPathOther);
-}
-
-void* CTI::privateCompileArrayLengthTrampoline()
-{
- // Check eax is an array
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - get the length from the storage
- m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::eax);
- m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_length), X86::eax, X86::eax);
-
- m_jit.addl_rr(X86::eax, X86::eax);
- X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
- m_jit.addl_i8r(1, X86::eax);
-
- m_jit.ret();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- return code;
-}
-
-void* CTI::privateCompileStringLengthTrampoline()
-{
- // Check eax is a string
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringVptr), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - get the length from the Ustring.
- m_jit.movl_mr(OBJECT_OFFSET(JSString, m_value) + OBJECT_OFFSET(UString, m_rep), X86::eax, X86::eax);
- m_jit.movl_mr(OBJECT_OFFSET(UString::Rep, len), X86::eax, X86::eax);
-
- m_jit.addl_rr(X86::eax, X86::eax);
- X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJo();
- m_jit.addl_i8r(1, X86::eax);
-
- m_jit.ret();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
- X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- return code;
-}
-
-void CTI::patchGetByIdSelf(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
-{
- StructureStubInfo& info = codeBlock->getStubInfo(returnAddress);
-
- // We don't want to repatch more than once - in future go to cti_op_get_by_id_generic.
- // Should probably go to Machine::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
- ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Machine::cti_op_get_by_id_generic));
-
- // Repatch the offset into the propoerty map to load from, then repatch the StructureID to look for.
- X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
- X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdStructureID, reinterpret_cast<uint32_t>(structureID));
-}
-
-void CTI::patchPutByIdReplace(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
-{
- StructureStubInfo& info = codeBlock->getStubInfo(returnAddress);
-
- // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
- // Should probably go to Machine::cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
- ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Machine::cti_op_put_by_id_generic));
-
- // Repatch the offset into the propoerty map to load from, then repatch the StructureID to look for.
- X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetPutByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
- X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetPutByIdStructureID, reinterpret_cast<uint32_t>(structureID));
-}
-
-void CTI::privateCompilePatchGetArrayLength(void* returnAddress)
-{
- StructureStubInfo& info = m_codeBlock->getStubInfo(returnAddress);
-
- // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
- ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Machine::cti_op_get_by_id_fail));
-
- // Check eax is an array
- m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
- X86Assembler::JmpSrc failureCases1 = m_jit.emitUnlinkedJne();
- m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsArrayVptr), X86::eax);
- X86Assembler::JmpSrc failureCases2 = m_jit.emitUnlinkedJne();
-
- // Checks out okay! - get the length from the storage
- m_jit.movl_mr(OBJECT_OFFSET(JSArray, m_storage), X86::eax, X86::ecx);
- m_jit.movl_mr(OBJECT_OFFSET(ArrayStorage, m_length), X86::ecx, X86::ecx);
-
- m_jit.addl_rr(X86::ecx, X86::ecx);
- X86Assembler::JmpSrc failureClobberedECX = m_jit.emitUnlinkedJo();
- m_jit.addl_i8r(1, X86::ecx);
-
- X86Assembler::JmpSrc success = m_jit.emitUnlinkedJmp();
-
- m_jit.link(failureClobberedECX, m_jit.label());
- m_jit.emitRestoreArgumentReference();
- X86Assembler::JmpSrc failureCases3 = m_jit.emitUnlinkedJmp();
-
- void* code = m_jit.copy();
- ASSERT(code);
-
- // Use the repatch information to link the failure cases back to the original slow case routine.
- void* slowCaseBegin = reinterpret_cast<char*>(info.callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
- X86Assembler::link(code, failureCases1, slowCaseBegin);
- X86Assembler::link(code, failureCases2, slowCaseBegin);
- X86Assembler::link(code, failureCases3, slowCaseBegin);
-
- // On success return back to the hot patch code, at a point it will perform the store to dest for us.
- intptr_t successDest = (intptr_t)(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
- X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
-
- // Track the stub we have created so that it will be deleted later.
- m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
-
- // Finally repatch the jump to sow case back in the hot path to jump here instead.
- // FIXME: should revert this repatching, on failure.
- intptr_t jmpLocation = reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
- X86Assembler::repatchBranchOffset(jmpLocation, code);
-}
-
-void CTI::emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst)
-{
- m_jit.movl_mr(JSVariableObject::offsetOf_d(), variableObject, dst);
- m_jit.movl_mr(JSVariableObject::offsetOf_Data_registers(), dst, dst);
- m_jit.movl_mr(index * sizeof(Register), dst, dst);
-}
-
-void CTI::emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index)
-{
- m_jit.movl_mr(JSVariableObject::offsetOf_d(), variableObject, variableObject);
- m_jit.movl_mr(JSVariableObject::offsetOf_Data_registers(), variableObject, variableObject);
- m_jit.movl_rm(src, index * sizeof(Register), variableObject);
-}
-
-#if ENABLE(WREC)
-
-void* CTI::compileRegExp(Machine* machine, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase, bool multiline)
-{
- // TODO: better error messages
- if (pattern.size() > MaxPatternSize) {
- *error_ptr = "regular expression too large";
- return 0;
- }
-
- X86Assembler jit(machine->jitCodeBuffer());
- WRECParser parser(pattern, ignoreCase, multiline, jit);
-
- jit.emitConvertToFastCall();
- // (0) Setup:
- // Preserve regs & initialize outputRegister.
- jit.pushl_r(WRECGenerator::outputRegister);
- jit.pushl_r(WRECGenerator::currentValueRegister);
- // push pos onto the stack, both to preserve and as a parameter available to parseDisjunction
- jit.pushl_r(WRECGenerator::currentPositionRegister);
- // load output pointer
- jit.movl_mr(16
-#if COMPILER(MSVC)
- + 3 * sizeof(void*)
-#endif
- , X86::esp, WRECGenerator::outputRegister);
-
- // restart point on match fail.
- WRECGenerator::JmpDst nextLabel = jit.label();
-
- // (1) Parse Disjunction:
-
- // Parsing the disjunction should fully consume the pattern.
- JmpSrcVector failures;
- parser.parseDisjunction(failures);
- if (parser.isEndOfPattern()) {
- parser.m_err = WRECParser::Error_malformedPattern;
- }
- if (parser.m_err) {
- // TODO: better error messages
- *error_ptr = "TODO: better error messages";
- return 0;
- }
-
- // (2) Success:
- // Set return value & pop registers from the stack.
-
- jit.testl_rr(WRECGenerator::outputRegister, WRECGenerator::outputRegister);
- WRECGenerator::JmpSrc noOutput = jit.emitUnlinkedJe();
-
- jit.movl_rm(WRECGenerator::currentPositionRegister, 4, WRECGenerator::outputRegister);
- jit.popl_r(X86::eax);
- jit.movl_rm(X86::eax, WRECGenerator::outputRegister);
- jit.popl_r(WRECGenerator::currentValueRegister);
- jit.popl_r(WRECGenerator::outputRegister);
- jit.ret();
-
- jit.link(noOutput, jit.label());
-
- jit.popl_r(X86::eax);
- jit.movl_rm(X86::eax, WRECGenerator::outputRegister);
- jit.popl_r(WRECGenerator::currentValueRegister);
- jit.popl_r(WRECGenerator::outputRegister);
- jit.ret();
-
- // (3) Failure:
- // All fails link to here. Progress the start point & if it is within scope, loop.
- // Otherwise, return fail value.
- WRECGenerator::JmpDst here = jit.label();
- for (unsigned i = 0; i < failures.size(); ++i)
- jit.link(failures[i], here);
- failures.clear();
-
- jit.movl_mr(X86::esp, WRECGenerator::currentPositionRegister);
- jit.addl_i8r(1, WRECGenerator::currentPositionRegister);
- jit.movl_rm(WRECGenerator::currentPositionRegister, X86::esp);
- jit.cmpl_rr(WRECGenerator::lengthRegister, WRECGenerator::currentPositionRegister);
- jit.link(jit.emitUnlinkedJle(), nextLabel);
-
- jit.addl_i8r(4, X86::esp);
-
- jit.movl_i32r(-1, X86::eax);
- jit.popl_r(WRECGenerator::currentValueRegister);
- jit.popl_r(WRECGenerator::outputRegister);
- jit.ret();
-
- *numSubpatterns_ptr = parser.m_numSubpatterns;
-
- void* code = jit.copy();
- ASSERT(code);
- return code;
-}
-
-#endif // ENABLE(WREC)
-
-} // namespace JSC
-
-#endif // ENABLE(CTI)