2008-09-26 Gavin Barraclough <barraclough@apple.com>
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 27 Sep 2008 01:44:15 +0000 (01:44 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 27 Sep 2008 01:44:15 +0000 (01:44 +0000)
        Reviewed by Maciej Stachowiak & Oliver Hunt.

        Add support for reusing temporary JSNumberCells.  This change is based on the observation
        that if the result of certain operations is a JSNumberCell and is consumed by a subsequent
        operation that would produce a JSNumberCell, we can reuse the object rather than allocating
        a fresh one.  E.g. given the expression ((a * b) * c), we can statically determine that
        (a * b) will have a numeric result (or else it will have thrown an exception), so the result
        will either be a JSNumberCell or a JSImmediate.

        This patch changes three areas of JSC:
            * The AST now tracks type information about the result of each node.
            * This information is consumed in bytecode compilation, and certain bytecode operations
              now carry the statically determined type information about their operands.
            * CTI uses the information in a number of fashions:
                * Where an operand to certain arithmetic operations is reusable, it will plant code
                  to try to perform the operation in JIT code & reuse the cell, where appropriate.
                * Where it can be statically determined that an operand can only be numeric (typically
                  the result of another arithmetic operation) the code will not redundantly check that
                  the JSCell is a JSNumberCell.
                * Where either of the operands to an add are non-numeric do not plant an optimized
                  arithmetic code path, just call straight out to the C function.

        +6% Sunspider (10% progression on 3D, 16% progression on math, 60% progression on access-nbody),
        +1% v8-tests (improvements in raytrace & crypto)

        * VM/CTI.cpp: Add optimized code generation with reuse of temporary JSNumberCells.
        * VM/CTI.h:
        * kjs/JSNumberCell.h:
        * masm/X86Assembler.h:

        * VM/CodeBlock.cpp: Add type information to specific bytecodes.
        * VM/CodeGenerator.cpp:
        * VM/CodeGenerator.h:
        * VM/Machine.cpp:

        * kjs/nodes.cpp: Track static type information for nodes.
        * kjs/nodes.h:
        * kjs/ResultDescriptor.h: (Added)
        * JavaScriptCore.xcodeproj/project.pbxproj:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36976 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/JSNumberCell.h
JavaScriptCore/kjs/ResultType.h [new file with mode: 0644]
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/masm/X86Assembler.h

index 2fd4ec4c23a6d5dfac64b300f85487a52d80af70..d6ec0ec1d066a1894310468e7baa14a94f074287 100644 (file)
@@ -1,3 +1,45 @@
+2008-09-26  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Maciej Stachowiak & Oliver Hunt.
+
+        Add support for reusing temporary JSNumberCells.  This change is based on the observation
+        that if the result of certain operations is a JSNumberCell and is consumed by a subsequent
+        operation that would produce a JSNumberCell, we can reuse the object rather than allocating
+        a fresh one.  E.g. given the expression ((a * b) * c), we can statically determine that
+        (a * b) will have a numeric result (or else it will have thrown an exception), so the result
+        will either be a JSNumberCell or a JSImmediate.
+
+        This patch changes three areas of JSC:
+            * The AST now tracks type information about the result of each node.
+            * This information is consumed in bytecode compilation, and certain bytecode operations
+              now carry the statically determined type information about their operands.
+            * CTI uses the information in a number of fashions:
+                * Where an operand to certain arithmetic operations is reusable, it will plant code
+                  to try to perform the operation in JIT code & reuse the cell, where appropriate.
+                * Where it can be statically determined that an operand can only be numeric (typically
+                  the result of another arithmetic operation) the code will not redundantly check that
+                  the JSCell is a JSNumberCell.
+                * Where either of the operands to an add are non-numeric do not plant an optimized
+                  arithmetic code path, just call straight out to the C function.
+
+        +6% Sunspider (10% progression on 3D, 16% progression on math, 60% progression on access-nbody),
+        +1% v8-tests (improvements in raytrace & crypto)
+
+        * VM/CTI.cpp: Add optimized code generation with reuse of temporary JSNumberCells.
+        * VM/CTI.h:
+        * kjs/JSNumberCell.h:
+        * masm/X86Assembler.h:
+
+        * VM/CodeBlock.cpp: Add type information to specific bytecodes.
+        * VM/CodeGenerator.cpp:
+        * VM/CodeGenerator.h:
+        * VM/Machine.cpp:
+
+        * kjs/nodes.cpp: Track static type information for nodes.
+        * kjs/nodes.h:
+        * kjs/ResultDescriptor.h: (Added)
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+
 2008-09-26  Yichao Yin  <yichao.yin@torchmobile.com.cn>
 
         Reviewed by George Staikos, Maciej Stachowiak.
index b1a892ff23222f74bf7210e46f2090925cd0e41d..7023080b6a359678b3b6b915c013b16146af41f6 100644 (file)
@@ -86,6 +86,7 @@
                869081410E640C89000D36ED /* X86Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 869081400E640C89000D36ED /* X86Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                869083150E6518D7000D36ED /* WREC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 869083130E6518D7000D36ED /* WREC.cpp */; };
                869083160E6518D7000D36ED /* WREC.h in Headers */ = {isa = PBXBuildFile; fileRef = 869083140E6518D7000D36ED /* WREC.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                905B02AE0E28640F006DF882 /* RefCountedLeakCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */; };
                90D3469C0E285280009492EE /* RefCountedLeakCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D3469B0E285280009492EE /* RefCountedLeakCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                930754C108B0F68000AB3056 /* pcre_compile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930754BF08B0F68000AB3056 /* pcre_compile.cpp */; };
                869081400E640C89000D36ED /* X86Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = X86Assembler.h; sourceTree = "<group>"; };
                869083130E6518D7000D36ED /* WREC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WREC.cpp; sourceTree = "<group>"; };
                869083140E6518D7000D36ED /* WREC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WREC.h; sourceTree = "<group>"; };
+               869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; };
                905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefCountedLeakCounter.cpp; sourceTree = "<group>"; };
                90D3469B0E285280009492EE /* RefCountedLeakCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCountedLeakCounter.h; sourceTree = "<group>"; };
                9303F567099118FA00AD71B8 /* OwnPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnPtr.h; sourceTree = "<group>"; };
                                F692A87C0255597D01FF60F7 /* RegExpObject.h */,
                                BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */,
                                BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */,
+                               869EBCB60E8C6D4A008722CC /* ResultType.h */,
                                9374D3A8038D9D74008635CE /* ScopeChain.cpp */,
                                9374D3A7038D9D74008635CE /* ScopeChain.h */,
                                7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */,
                                147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,
                                7E2ADD8E0E79AAD500D50C51 /* CharacterClassConstructor.h in Headers */,
                                140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */,
+                               869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = 1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */;
                        buildSettings = {
+                               GCC_VERSION = 4.0;
                                STRIP_INSTALLED_PRODUCT = NO;
                        };
                        name = Release;
index 2b75b86da6467d9151a2ed7319df369cfbe714bf..a175699308637e885adce4dfab8f758aa35e7d1d 100644 (file)
 #include "JSArray.h"
 #include "Machine.h"
 #include "wrec/WREC.h"
+#include "ResultType.h"
+#if PLATFORM(MAC)
+#include <sys/sysctl.h>
+#endif
 
 using namespace std;
 
 namespace JSC {
 
+#if PLATFORM(MAC)
+bool isSSE3Present()
+{
+    struct SSE3Check {
+        SSE3Check()
+        {
+            int hasSSE3 = 0;
+            size_t length = sizeof(hasSSE3);
+            int error = sysctlbyname("hw.optional.sse3", &hasSSE3, &length, NULL, 0);
+            present = hasSSE3 && !error;
+        }
+        bool present;
+    };
+    static SSE3Check check;
+    return check.present;
+}
+#else
+bool isSSE3Present()
+{
+    return false;
+}
+#endif
+
 #if COMPILER(GCC) && PLATFORM(X86)
 asm(
 ".globl _ctiTrampoline" "\n"
@@ -601,6 +628,220 @@ void CTI::emitSlowScriptCheck(unsigned opcodeIndex)
     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, X86::ecx);
+}
+
+void CTI::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
+{
+    StructureID* numberStructureID = m_exec->globalData().numberStructureID.get();
+    X86Assembler::JmpSrc wasJSNumberCell1, wasJSNumberCell1b, wasJSNumberCell2, wasJSNumberCell2b;
+
+    emitGetArg(src1, X86::eax);
+    emitGetArg(src2, X86::edx);
+
+    if (types.second().isReusable() && isSSE3Present()) {
+        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() && isSSE3Present()) {
+        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);
+        emitFastArithDeTagImmediate(X86::eax);
+        emitFastArithImmToInt(X86::edx);
+        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() && isSSE3Present()) {
+        m_jit.link(wasJSNumberCell2, m_jit.label());
+        m_jit.link(wasJSNumberCell2b, m_jit.label());
+    }
+    else if (types.first().isReusable() && isSSE3Present()) {
+        m_jit.link(wasJSNumberCell1, m_jit.label());
+        m_jit.link(wasJSNumberCell1b, m_jit.label());
+    }
+}
+
+void CTI::compileBinaryArithOpSlowCase(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() && isSSE3Present()) {
+        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() && isSSE3Present()) {
+        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);
+
+    emitGetPutArg(src1, 0, X86::ecx);
+    emitGetPutArg(src2, 4, X86::ecx);
+    if (opcodeID == op_add)
+        emitCall(i, Machine::cti_op_add);
+    else if (opcodeID == op_sub)
+        emitCall(i, Machine::cti_op_sub);
+    else {
+        ASSERT(opcodeID == op_mul);
+        emitCall(i, Machine::cti_op_mul);
+    }
+    emitPutResult(dst);
+}
+
 void CTI::privateCompileMainPass()
 {
     Instruction* instruction = m_codeBlock->instructions.begin();
@@ -632,33 +873,32 @@ void CTI::privateCompileMainPass()
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src1 = instruction[i + 2].u.operand;
             unsigned src2 = instruction[i + 3].u.operand;
-            if (isConstant(src2)) {
-                JSValue* value = getConstant(m_exec, src2);
-                if (JSImmediate::isNumber(value)) {
-                    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);
-                    i += 4;
-                    break;
-                }
-            } else if (!isConstant(src1)) {
-                emitGetArg(src1, X86::eax);
+
+            if (JSValue* value = getConstantImmediateNumericArg(src1)) {
                 emitGetArg(src2, X86::edx);
-                emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
-                emitFastArithDeTagImmediate(X86::eax);
-                m_jit.addl_rr(X86::edx, X86::eax);
+                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);
-                i += 4;
-                break;
+            } 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);
+                    emitCall(i, Machine::cti_op_add);
+                    emitPutResult(instruction[i + 1].u.operand);
+                }
             }
-            emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
-            emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
-            emitCall(i, Machine::cti_op_add);
-            emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+
+            i += 5;
             break;
         }
         case op_end: {
@@ -875,37 +1115,27 @@ void CTI::privateCompileMainPass()
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src1 = instruction[i + 2].u.operand;
             unsigned src2 = instruction[i + 3].u.operand;
-            if (isConstant(src1) || isConstant(src2)) {
-                unsigned constant = src1;
-                unsigned nonconstant = src2;
-                if (!isConstant(src1)) {
-                    constant = src2;
-                    nonconstant = src1;
-                }
-                JSValue* value = getConstant(m_exec, constant);
-                if (JSImmediate::isNumber(value)) {
-                    emitGetArg(nonconstant, X86::eax);
-                    emitJumpSlowCaseIfNotImmNum(X86::eax, i);
-                    emitFastArithImmToInt(X86::eax);
-                    m_jit.imull_i32r( X86::eax, getDeTaggedConstantImmediate(value), X86::eax);
-                    m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
-                    emitFastArithPotentiallyReTagImmediate(X86::eax);
-                    emitPutResult(dst);
-                    i += 4;
-                    break;
-                }
-            }
 
-            emitGetArg(src1, X86::eax);
-            emitGetArg(src2, X86::edx);
-            emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
-            emitFastArithDeTagImmediate(X86::eax);
-            emitFastArithImmToInt(X86::edx);
-            m_jit.imull_rr(X86::edx, X86::eax);
-            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
-            emitFastArithPotentiallyReTagImmediate(X86::eax);
-            emitPutResult(dst);
-            i += 4;
+            if (JSValue* src1Value = getConstantImmediateNumericArg(src1)) {
+                emitGetArg(src2, X86::eax);
+                emitJumpSlowCaseIfNotImmNum(X86::eax, i);
+                emitFastArithImmToInt(X86::eax);
+                m_jit.imull_i32r(X86::eax, getDeTaggedConstantImmediate(src1Value), X86::eax);
+                m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
+                emitFastArithReTagImmediate(X86::eax);
+                emitPutResult(dst);
+            } else if (JSValue* src2Value = getConstantImmediateNumericArg(src2)) {
+                emitGetArg(src1, X86::eax);
+                emitJumpSlowCaseIfNotImmNum(X86::eax, i);
+                emitFastArithImmToInt(X86::eax);
+                m_jit.imull_i32r(X86::eax, getDeTaggedConstantImmediate(src2Value), 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: {
@@ -1086,14 +1316,8 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_sub: {
-            emitGetArg(instruction[i + 2].u.operand, X86::eax);
-            emitGetArg(instruction[i + 3].u.operand, X86::edx);
-            emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
-            m_jit.subl_rr(X86::edx, X86::eax);
-            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJo(), i));
-            emitFastArithReTagImmediate(X86::eax);
-            emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            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: {
@@ -1343,7 +1567,7 @@ void CTI::privateCompileMainPass()
                 emitJumpSlowCaseIfNotImmNum(X86::eax, i);
                 emitPutResult(dst);
             }
-            i += 4;
+            i += 5;
             break;
         }
         case op_rshift: {
@@ -1454,7 +1678,7 @@ void CTI::privateCompileMainPass()
             m_jit.xorl_rr(X86::edx, X86::eax);
             emitFastArithReTagImmediate(X86::eax);
             emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            i += 5;
             break;
         }
         case op_new_regexp: {
@@ -1471,7 +1695,7 @@ void CTI::privateCompileMainPass()
             emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
             m_jit.orl_rr(X86::edx, X86::eax);
             emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            i += 5;
             break;
         }
         case op_call_eval: {
@@ -1811,35 +2035,35 @@ void CTI::privateCompileSlowCases()
         switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
         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 (isConstant(src2)) {
-                JSValue* value = getConstant(m_exec, src2);
-                if (JSImmediate::isNumber(value)) {
-                    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);
-                    emitCall(i, Machine::cti_op_add);
-                    emitPutResult(dst);
-                    i += 4;
-                    break;
-                }
+            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);
+                emitCall(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);
+                emitCall(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(op_add, iter, dst, src1, src2, types, i);
+                else
+                    ASSERT_NOT_REACHED();
             }
 
-            ASSERT(!isConstant(instruction[i + 2].u.operand));
-
-            X86Assembler::JmpSrc notImm = iter->from;
-            m_jit.link((++iter)->from, m_jit.label());
-            m_jit.subl_rr(X86::edx, X86::eax);
-            emitFastArithReTagImmediate(X86::eax);
-            m_jit.link(notImm, m_jit.label());
-            emitPutArg(X86::eax, 0);
-            emitPutArg(X86::edx, 4);
-            emitCall(i, Machine::cti_op_add);
-            emitPutResult(dst);
-            i += 4;
+            i += 5;
             break;
         }
         case op_get_by_val: {
@@ -1874,15 +2098,8 @@ void CTI::privateCompileSlowCases()
             break;
         }
         case op_sub: {
-            X86Assembler::JmpSrc notImm = iter->from;
-            m_jit.link((++iter)->from, m_jit.label());
-            m_jit.addl_rr(X86::edx, X86::eax);
-            m_jit.link(notImm, m_jit.label());
-            emitPutArg(X86::eax, 0);
-            emitPutArg(X86::edx, 4);
-            emitCall(i, Machine::cti_op_sub);
-            emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            compileBinaryArithOpSlowCase(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_rshift: {
@@ -1956,7 +2173,7 @@ void CTI::privateCompileSlowCases()
             // 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 tramopile fail we want to bail out back to here.  To do so we can subtract back
+            // 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());
@@ -2155,7 +2372,7 @@ void CTI::privateCompileSlowCases()
                 emitCall(i, Machine::cti_op_bitand);
                 emitPutResult(dst);
             }
-            i += 4;
+            i += 5;
             break;
         }
         case op_jtrue: {
@@ -2186,7 +2403,7 @@ void CTI::privateCompileSlowCases()
             emitPutArg(X86::edx, 4);
             emitCall(i, Machine::cti_op_bitxor);
             emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            i += 5;
             break;
         }
         case op_bitor: {
@@ -2195,7 +2412,7 @@ void CTI::privateCompileSlowCases()
             emitPutArg(X86::edx, 4);
             emitCall(i, Machine::cti_op_bitor);
             emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            i += 5;
             break;
         }
         case op_eq: {
@@ -2243,7 +2460,22 @@ void CTI::privateCompileSlowCases()
             i += 4;
             break;
         }
-        CTI_COMPILE_BINARY_OP_SLOW_CASE(op_mul);
+        case op_mul: {
+            int dst = instruction[i + 1].u.operand;
+            int src1 = instruction[i + 2].u.operand;
+            int src2 = instruction[i + 3].u.operand;
+            if (getConstantImmediateNumericArg(src1) || getConstantImmediateNumericArg(src2)) {
+                m_jit.link(iter->from, m_jit.label());
+                emitGetPutArg(src1, 0, X86::ecx);
+                emitGetPutArg(src2, 4, X86::ecx);
+                emitCall(i, Machine::cti_op_mul);
+                emitPutResult(dst);
+            } else
+                compileBinaryArithOpSlowCase(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: {
index bec8ad9bf46c3d13d9008879b1ead46334804e01..5c2e9f5317641e3f02ef0e61e5239c8e7528824d 100644 (file)
@@ -114,6 +114,7 @@ namespace JSC {
     class StringJumpTable;
     class StructureIDChain;
     struct Instruction;
+    struct OperandTypes;
 
     typedef JSValue* (*CTIHelper_j)(CTI_ARGS);
     typedef JSPropertyNameIterator* (*CTIHelper_p)(CTI_ARGS);
@@ -354,6 +355,9 @@ namespace JSC {
         void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
         enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
         void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
+        void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell,  X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2);
+        void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
+        void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
 
         void emitGetArg(unsigned src, X86Assembler::RegisterID dst);
         void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch);
index ca8ad8804deda13c2e86f4a344057e091c120090..cd5f0947422fcd38e3fbf46d4f8acfd2b82e89a2 100644 (file)
@@ -450,10 +450,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
         }
         case op_add: {
             printBinaryOp(location, it, "add");
+            ++it;
             break;
         }
         case op_mul: {
             printBinaryOp(location, it, "mul");
+            ++it;
             break;
         }
         case op_div: {
@@ -466,6 +468,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
         }
         case op_sub: {
             printBinaryOp(location, it, "sub");
+            ++it;
             break;
         }
         case op_lshift: {
@@ -482,14 +485,17 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
         }
         case op_bitand: {
             printBinaryOp(location, it, "bitand");
+            ++it;
             break;
         }
         case op_bitxor: {
             printBinaryOp(location, it, "bitxor");
+            ++it;
             break;
         }
         case op_bitor: {
             printBinaryOp(location, it, "bitor");
+            ++it;
             break;
         }
         case op_bitnot: {
index fcd1275a54b818dad3aeec548019644704f1acff..95fa4a6e714c079fa4ef1d364fa43de6cda131d0 100644 (file)
@@ -676,12 +676,18 @@ RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
     return dst;
 }
 
-RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
+RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types)
 {
     emitOpcode(opcode);
     instructions().append(dst->index());
     instructions().append(src1->index());
     instructions().append(src2->index());
+
+    if (opcode == op_bitor || opcode == op_bitand || opcode == op_bitxor ||
+        opcode == op_add || opcode == op_mul || opcode == op_sub) {
+        instructions().append(types.toInt());
+    }
+
     return dst;
 }
 
index 3681b85dde16595ff93826979e233ff7b78b394d..efb68436d70a720c3ab47ab4e45f6eb14cd9fe4b 100644 (file)
@@ -233,7 +233,7 @@ namespace JSC {
         RegisterID* emitUnexpectedLoad(RegisterID* dst, double);
 
         RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
-        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
+        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
         RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
         RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
 
@@ -254,7 +254,7 @@ namespace JSC {
 
         RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype);
         RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
-        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base); }
+        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
 
         RegisterID* emitResolve(RegisterID* dst, const Identifier& property);
         RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue* globalObject);
index 0257232c481a923c3b869e16b996103c6b8ef42c..6acc8aa44dfceacc8d3c6ed0183c9672fce854b0 100644 (file)
@@ -1827,7 +1827,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             VM_CHECK_EXCEPTION();
             r[dst] = result;
         }
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_mul) {
@@ -1849,7 +1849,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst] = result;
         }
 
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_div) {
@@ -1922,7 +1922,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             VM_CHECK_EXCEPTION();
             r[dst] = result;
         }
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_lshift) {
@@ -2018,7 +2018,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst] = result;
         }
 
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_bitxor) {
@@ -2043,7 +2043,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst] = result;
         }
 
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_bitor) {
@@ -2068,7 +2068,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             r[dst] = result;
         }
 
-        ++vPC;
+        vPC += 2;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_bitnot) {
index 2f1c3ca207d98e4e60d6c5623768b9d37e2f968c..b66d8c176dc92422386dca7c22d3d4d3db3c5563 100644 (file)
@@ -42,6 +42,7 @@ namespace JSC {
     struct Instruction;
 
     class JSNumberCell : public JSCell {
+        friend class CTI;
         friend JSValue* jsNumberCell(ExecState*, double);
         friend JSValue* jsNaN(ExecState*);
     public:
diff --git a/JavaScriptCore/kjs/ResultType.h b/JavaScriptCore/kjs/ResultType.h
new file mode 100644 (file)
index 0000000..435ceea
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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. 
+ */
+
+#ifndef ResultType_h
+#define ResultType_h
+
+namespace JSC {
+
+    struct ResultType {
+        friend struct OperandTypes;
+
+        typedef char Type;
+        static const Type TypeReusable = 1;
+        
+        static const Type TypeMaybeNumber = 2;
+        static const Type TypeMaybeString = 4;
+        static const Type TypeMaybeNull = 8;
+        static const Type TypeMaybeBool = 16;
+        static const Type TypeMaybeOther = 32;
+
+        static const Type TypeReusableNumber = 3;
+        static const Type TypeStringOrReusableNumber = 4;
+    
+        explicit ResultType(Type type)
+            : m_type(type)
+        {
+        }
+        
+        bool isReusable()
+        {
+            return (m_type & TypeReusable);
+        }
+        
+        bool definitelyIsNumber()
+        {
+            return ((m_type & ~TypeReusable) == TypeMaybeNumber);
+        }
+        
+        bool isNotNumber()
+        {
+            return ((m_type & TypeMaybeNumber) == 0);
+        }
+        
+        bool mightBeNumber()
+        {
+            return !isNotNumber();
+        }
+        
+        static ResultType nullType()
+        {
+            return ResultType(TypeMaybeNull);
+        }
+        
+        static ResultType boolean()
+        {
+            return ResultType(TypeMaybeBool);
+        }
+        
+        static ResultType constNumber()
+        {
+            return ResultType(TypeMaybeNumber);
+        }
+        
+        static ResultType reusableNumber()
+        {
+            return ResultType(TypeReusable | TypeMaybeNumber);
+        }
+        
+        static ResultType reusableNumberOrString()
+        {
+            return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString);
+        }
+        
+        static ResultType string()
+        {
+            return ResultType(TypeMaybeString);
+        }
+        
+        static ResultType unknown()
+        {
+            return ResultType(TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther);
+        }
+        
+        static ResultType forAdd(ResultType op1, ResultType op2)
+        {
+            if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+                return reusableNumber();
+            if (op1.isNotNumber() || op2.isNotNumber())
+                return string();
+            return reusableNumberOrString();
+        }
+
+    private:
+        Type m_type;
+    };
+    
+    struct OperandTypes
+    {
+        OperandTypes(ResultType first = ResultType::unknown(), ResultType second = ResultType::unknown())
+        {
+            m_u.rds.first = first.m_type;
+            m_u.rds.second = second.m_type;
+        }
+        
+        union {
+            struct {
+                ResultType::Type first;
+                ResultType::Type second;
+            } rds;
+            int i;
+        } m_u;
+
+        ResultType first()
+        {
+            return ResultType(m_u.rds.first);
+        }
+
+        ResultType second()
+        {
+            return ResultType(m_u.rds.second);
+        }
+
+        int toInt()
+        {
+            return m_u.i;
+        }
+        static OperandTypes fromInt(int value)
+        {
+            OperandTypes types;
+            types.m_u.i = value;
+            return types;
+        }
+    };
+
+} // namespace JSC
+
+#endif // ResultType_h
index e4fb7191662aa495c6542b1dfb9eea3b494b3a1b..be642b52cb7874eb0627203e46c279d0a920d590 100644 (file)
@@ -141,14 +141,6 @@ void ParserRefCounted::deleteNewObjects(JSGlobalData* globalData)
 
 Node::Node(JSGlobalData* globalData)
     : ParserRefCounted(globalData)
-    , m_expectedReturnType(ObjectType)
-{
-    m_line = globalData->lexer->lineNo();
-}
-
-Node::Node(JSGlobalData* globalData, JSType expectedReturn)
-    : ParserRefCounted(globalData)
-    , m_expectedReturnType(expectedReturn)
 {
     m_line = globalData->lexer->lineNo();
 }
@@ -663,7 +655,7 @@ RegisterID* PrefixResolveNode::emitCode(CodeGenerator& generator, RegisterID* ds
             if (dst == ignoredResult())
                 return 0;
             RefPtr<RegisterID> r0 = generator.emitUnexpectedLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0);
-            return generator.emitBinaryOp(op_add, r0.get(), local, r0.get());
+            return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes());
         }
 
         emitPreIncOrDec(generator, local, m_operator);
@@ -754,7 +746,7 @@ RegisterID* BinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
     RegisterID* src2 = generator.emitNode(m_expr2.get());
-    return generator.emitBinaryOp(opcode, generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    return generator.emitBinaryOp(opcode, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
 }
 
 RegisterID* EqualNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -780,7 +772,7 @@ RegisterID* ReverseBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID*
 {
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
     RegisterID* src2 = generator.emitNode(m_expr2.get());
-    return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get());
+    return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor()));
 }
 
 RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -788,7 +780,7 @@ RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
     RegisterID* src2 = generator.emitNode(m_expr2.get());
     generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
-    return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
 }
 
 RegisterID* InstanceOfNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -846,7 +838,7 @@ RegisterID* ConditionalNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 // ------------------------------ ReadModifyResolveNode -----------------------------------
 
 // FIXME: should this be moved to be a method on CodeGenerator?
-static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper)
+static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper, OperandTypes types)
 {
     OpcodeID opcode;
     switch (oper) {
@@ -888,7 +880,7 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generat
             return dst;
     }
     
-    return generator.emitBinaryOp(opcode, dst, src1, src2);
+    return generator.emitBinaryOp(opcode, dst, src1, src2, types);
 }
 
 RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -896,20 +888,20 @@ RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID
     if (RegisterID* local = generator.registerFor(m_ident)) {
         if (generator.isLocalConstant(m_ident)) {
             RegisterID* src2 = generator.emitNode(m_right.get());
-            return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator);
+            return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
         }
         
         if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
             RefPtr<RegisterID> result = generator.newTemporary();
             generator.emitMove(result.get(), local);
             RegisterID* src2 = generator.emitNode(m_right.get());
-            emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator);
+            emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
             generator.emitMove(local, result.get());
             return generator.moveToDestinationIfNeeded(dst, result.get());
         }
         
         RegisterID* src2 = generator.emitNode(m_right.get());
-        RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator);
+        RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
@@ -919,7 +911,7 @@ RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID
     if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) {
         RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject);
         RegisterID* src2 = generator.emitNode(m_right.get());
-        RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
+        RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
         generator.emitPutScopedVar(depth, index, result, globalObject);
         return result;
     }
@@ -929,7 +921,7 @@ RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID
     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
     RegisterID* src2 = generator.emitNode(m_right.get());
     generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
-    RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
+    RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
     return generator.emitPutById(base.get(), m_ident, result);
 }
 
@@ -985,7 +977,7 @@ RegisterID* ReadModifyDotNode::emitCode(CodeGenerator& generator, RegisterID* ds
     generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
     RegisterID* change = generator.emitNode(m_right.get());
-    RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
+    RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
 
     generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitPutById(base.get(), m_ident, updatedValue);
@@ -1020,7 +1012,7 @@ RegisterID* ReadModifyBracketNode::emitCode(CodeGenerator& generator, RegisterID
     generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     RegisterID* change = generator.emitNode(m_right.get());
-    RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
+    RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
 
     generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutByVal(base.get(), property.get(), updatedValue);
@@ -1567,7 +1559,7 @@ RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID
         for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
             RefPtr<RegisterID> clauseVal = generator.newTemporary();
             generator.emitNode(clauseVal.get(), list->getClause()->expr());
-            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
+            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes());
             labelVector.append(generator.newLabel());
             generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
         }
@@ -1575,7 +1567,7 @@ RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID
         for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
             RefPtr<RegisterID> clauseVal = generator.newTemporary();
             generator.emitNode(clauseVal.get(), list->getClause()->expr());
-            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
+            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes());
             labelVector.append(generator.newLabel());
             generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
         }
index 0792666d1195f63d5f84427ed1da3b390866414c..7ae9994f18374b6ae862c5113e5762d8c2edcb00 100644 (file)
@@ -32,6 +32,7 @@
 #include "LabelStack.h"
 #include "Opcode.h"
 #include "RegisterID.h"
+#include "ResultType.h"
 #include "SourceRange.h"
 #include "SymbolTable.h"
 #include "regexp.h"
@@ -193,17 +194,14 @@ namespace JSC {
         virtual bool needsParensIfLeftmost() const { return false; }
         
     protected:
-        Node(JSGlobalData*, JSType) JSC_FAST_CALL; // used by ExpressionNode
-
-        int m_line : 28;
-        unsigned m_expectedReturnType : 3; // JSType
+        int m_line;
     };
 
     class ExpressionNode : public Node {
     public:
-        ExpressionNode(JSGlobalData* globalData) JSC_FAST_CALL : Node(globalData) {}
-        ExpressionNode(JSGlobalData* globalData, JSType expectedReturn) JSC_FAST_CALL
-            : Node(globalData, expectedReturn)
+        ExpressionNode(JSGlobalData* globalData, ResultType resultDesc = ResultType::unknown()) JSC_FAST_CALL
+            : Node(globalData)
+            , m_resultDesc(resultDesc)
         {
         }
 
@@ -216,10 +214,13 @@ namespace JSC {
         virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; }
         virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; }
 
-        JSType expectedReturnType() const JSC_FAST_CALL { return static_cast<JSType>(m_expectedReturnType); }
+        ResultType resultDescriptor() const JSC_FAST_CALL { return m_resultDesc; }
 
         // This needs to be in public in order to compile using GCC 3.x 
         typedef enum { EvalOperator, FunctionCall } CallerType;
+
+    private:
+        ResultType m_resultDesc;
     };
 
     class StatementNode : public Node {
@@ -245,7 +246,7 @@ namespace JSC {
     class NullNode : public ExpressionNode {
     public:
         NullNode(JSGlobalData* globalData) JSC_FAST_CALL
-            : ExpressionNode(globalData, NullType)
+            : ExpressionNode(globalData, ResultType::nullType())
         {
         }
 
@@ -260,7 +261,7 @@ namespace JSC {
     class BooleanNode : public ExpressionNode {
     public:
         BooleanNode(JSGlobalData* globalData, bool value) JSC_FAST_CALL
-            : ExpressionNode(globalData, BooleanType)
+            : ExpressionNode(globalData, ResultType::boolean())
             , m_value(value)
         {
         }
@@ -278,7 +279,7 @@ namespace JSC {
     class NumberNode : public ExpressionNode {
     public:
         NumberNode(JSGlobalData* globalData, double v) JSC_FAST_CALL
-            : ExpressionNode(globalData, NumberType)
+            : ExpressionNode(globalData, ResultType::constNumber())
             , m_double(v)
         {
         }
@@ -315,7 +316,7 @@ namespace JSC {
     class StringNode : public ExpressionNode {
     public:
         StringNode(JSGlobalData* globalData, const Identifier& v) JSC_FAST_CALL
-            : ExpressionNode(globalData, StringType)
+            : ExpressionNode(globalData, ResultType::string())
             , m_value(v)
         {
         }
@@ -844,7 +845,7 @@ namespace JSC {
     class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
-            : ExpressionNode(globalData, NumberType)
+            : ExpressionNode(globalData, ResultType::constNumber()) // could be reusable for pre?
             , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_ident(ident)
         {
@@ -1026,7 +1027,7 @@ namespace JSC {
     class TypeOfResolveNode : public ExpressionNode {
     public:
         TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL
-            : ExpressionNode(globalData, StringType)
+            : ExpressionNode(globalData, ResultType::string())
             , m_ident(ident)
         {
         }
@@ -1046,7 +1047,7 @@ namespace JSC {
     class TypeOfValueNode : public ExpressionNode {
     public:
         TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
-            : ExpressionNode(globalData, StringType)
+            : ExpressionNode(globalData, ResultType::string())
             , m_expr(expr)
         {
         }
@@ -1146,7 +1147,7 @@ namespace JSC {
         {
         }
 
-        UnaryOpNode(JSGlobalData* globalData, JSType type, ExpressionNode* expr)
+        UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr)
             : ExpressionNode(globalData, type)
             , m_expr(expr)
         {
@@ -1162,7 +1163,7 @@ namespace JSC {
     class UnaryPlusNode : public UnaryOpNode {
     public:
         UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
-            : UnaryOpNode(globalData, NumberType, expr)
+            : UnaryOpNode(globalData, ResultType::constNumber(), expr)
         {
         }
 
@@ -1174,7 +1175,7 @@ namespace JSC {
     class NegateNode : public UnaryOpNode {
     public:
         NegateNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
-            : UnaryOpNode(globalData, NumberType, expr)
+            : UnaryOpNode(globalData, ResultType::reusableNumber(), expr)
         {
         }
 
@@ -1186,7 +1187,7 @@ namespace JSC {
     class BitwiseNotNode : public UnaryOpNode {
     public:
         BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
-            : UnaryOpNode(globalData, NumberType, expr)
+            : UnaryOpNode(globalData, ResultType::reusableNumber(), expr)
         {
         }
 
@@ -1198,7 +1199,7 @@ namespace JSC {
     class LogicalNotNode : public UnaryOpNode {
     public:
         LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
-            : UnaryOpNode(globalData, BooleanType, expr)
+            : UnaryOpNode(globalData, ResultType::boolean(), expr)
         {
         }
 
@@ -1217,7 +1218,7 @@ namespace JSC {
         {
         }
 
-        BinaryOpNode(JSGlobalData* globalData, JSType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+        BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
             : ExpressionNode(globalData, type)
             , m_expr1(expr1)
             , m_expr2(expr2)
@@ -1244,7 +1245,7 @@ namespace JSC {
         {
         }
 
-        ReverseBinaryOpNode(JSGlobalData* globalData, JSType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+        ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
             : ExpressionNode(globalData, type)
             , m_expr1(expr1)
             , m_expr2(expr2)
@@ -1264,7 +1265,7 @@ namespace JSC {
     class MultNode : public BinaryOpNode {
     public:
         MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1276,7 +1277,7 @@ namespace JSC {
     class DivNode : public BinaryOpNode {
     public:
         DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1288,7 +1289,7 @@ namespace JSC {
     class ModNode : public BinaryOpNode {
     public:
         ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1300,7 +1301,7 @@ namespace JSC {
     class AddNode : public BinaryOpNode {
     public:
         AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1312,7 +1313,7 @@ namespace JSC {
     class SubNode : public BinaryOpNode {
     public:
         SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1324,7 +1325,7 @@ namespace JSC {
     class LeftShiftNode : public BinaryOpNode {
     public:
         LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1336,7 +1337,7 @@ namespace JSC {
     class RightShiftNode : public BinaryOpNode {
     public:
         RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1348,7 +1349,7 @@ namespace JSC {
     class UnsignedRightShiftNode : public BinaryOpNode {
     public:
         UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1360,7 +1361,7 @@ namespace JSC {
     class LessNode : public BinaryOpNode {
     public:
         LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1372,7 +1373,7 @@ namespace JSC {
     class GreaterNode : public ReverseBinaryOpNode {
     public:
         GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : ReverseBinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1384,7 +1385,7 @@ namespace JSC {
     class LessEqNode : public BinaryOpNode {
     public:
         LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1396,7 +1397,7 @@ namespace JSC {
     class GreaterEqNode : public ReverseBinaryOpNode {
     public:
         GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : ReverseBinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1407,7 +1408,7 @@ namespace JSC {
 
     class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
     public:
-        ThrowableBinaryOpNode(JSGlobalData* globalData, JSType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+        ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
             : BinaryOpNode(globalData, type, expr1, expr2, rightHasAssignments)
         {
         }
@@ -1421,7 +1422,7 @@ namespace JSC {
     class InstanceOfNode : public ThrowableBinaryOpNode {
     public:
         InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : ThrowableBinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : ThrowableBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1447,7 +1448,7 @@ namespace JSC {
     class EqualNode : public BinaryOpNode {
     public:
         EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1460,7 +1461,7 @@ namespace JSC {
     class NotEqualNode : public BinaryOpNode {
     public:
         NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1472,7 +1473,7 @@ namespace JSC {
     class StrictEqualNode : public BinaryOpNode {
     public:
         StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1485,7 +1486,7 @@ namespace JSC {
     class NotStrictEqualNode : public BinaryOpNode {
     public:
         NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1497,7 +1498,7 @@ namespace JSC {
     class BitAndNode : public BinaryOpNode {
     public:
         BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1509,7 +1510,7 @@ namespace JSC {
     class BitOrNode : public BinaryOpNode {
     public:
         BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1521,7 +1522,7 @@ namespace JSC {
     class BitXOrNode : public BinaryOpNode {
     public:
         BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
-            : BinaryOpNode(globalData, NumberType, expr1, expr2, rightHasAssignments)
+            : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
         {
         }
 
@@ -1536,7 +1537,7 @@ namespace JSC {
     class LogicalOpNode : public ExpressionNode {
     public:
         LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) JSC_FAST_CALL
-            : ExpressionNode(globalData, BooleanType)
+            : ExpressionNode(globalData, ResultType::boolean())
             , m_expr1(expr1)
             , m_expr2(expr2)
             , m_operator(oper)
index a224497e2eb4bd6d25e81a1a69caaf80c7ea917a..26f60184b317dd8e2a2828065ac34a57396ab436 100644 (file)
@@ -162,12 +162,23 @@ namespace X86 {
         hasSib = esp,
         noScale = esp,
     } RegisterID;
+
+    typedef enum {
+        xmm0,
+        xmm1,
+        xmm2,
+        xmm3,
+        xmm4,
+        xmm5,
+        xmm6,
+        xmm7,
+    } XMMRegisterID;
 }
 
 class X86Assembler {
 public:
     typedef X86::RegisterID RegisterID;
-
+    typedef X86::XMMRegisterID XMMRegisterID;
     typedef enum {
         OP_ADD_EvGv                     = 0x01,
         OP_ADD_GvEv                     = 0x03,
@@ -182,6 +193,7 @@ public:
         OP_PUSH_EAX                     = 0x50,
         OP_POP_EAX                      = 0x58,
         PRE_OPERAND_SIZE                = 0x66,
+        PRE_SSE_66                      = 0x66,
         OP_IMUL_GvEvIz                  = 0x69,
         OP_GROUP1_EvIz                  = 0x81,
         OP_GROUP1_EvIb                  = 0x83,
@@ -201,23 +213,35 @@ public:
         OP_GROUP2_EvCL                  = 0xD3,
         OP_CALL_rel32                   = 0xE8,
         OP_JMP_rel32                    = 0xE9,
+        PRE_SSE_F2                      = 0xF2,
         OP_GROUP3_Ev                    = 0xF7,
         OP_GROUP3_EvIz                  = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test. 
         OP_GROUP5_Ev                    = 0xFF,
 
-        OP2_JO_rel32    = 0x80,
-        OP2_JB_rel32    = 0x82,
-        OP2_JAE_rel32   = 0x83,
-        OP2_JE_rel32    = 0x84,
-        OP2_JNE_rel32   = 0x85,
-        OP2_JBE_rel32   = 0x86,
-        OP2_JA_rel32    = 0x87,
-        OP2_JL_rel32    = 0x8C,
-        OP2_JGE_rel32   = 0x8D,
-        OP2_JLE_rel32   = 0x8E,
-        OP2_IMUL_GvEv   = 0xAF,
-        OP2_MOVZX_GvEb  = 0xB6,
-        OP2_MOVZX_GvEw  = 0xB7,
+        OP2_MOVSD_VsdWsd    = 0x10,
+        OP2_MOVSD_WsdVsd    = 0x11,
+        OP2_CVTSI2SD_VsdEd  = 0x2A,
+        OP2_CVTTSD2SI_GdWsd = 0x2C,
+        OP2_UCOMISD_VsdWsd  = 0x2E,
+        OP2_ADDSD_VsdWsd    = 0x58,
+        OP2_MULSD_VsdWsd    = 0x59,
+        OP2_SUBSD_VsdWsd    = 0x5C,
+        OP2_MOVD_EdVd       = 0x7E,
+        OP2_JO_rel32        = 0x80,
+        OP2_JB_rel32        = 0x82,
+        OP2_JAE_rel32       = 0x83,
+        OP2_JE_rel32        = 0x84,
+        OP2_JNE_rel32       = 0x85,
+        OP2_JBE_rel32       = 0x86,
+        OP2_JA_rel32        = 0x87,
+        OP2_JP_rel32        = 0x8A,
+        OP2_JL_rel32        = 0x8C,
+        OP2_JGE_rel32       = 0x8D,
+        OP2_JLE_rel32       = 0x8E,
+        OP2_IMUL_GvEv       = 0xAF,
+        OP2_MOVZX_GvEb      = 0xB6,
+        OP2_MOVZX_GvEw      = 0xB7,
+        OP2_PEXTRW_GdUdIb   = 0xC5,
 
         GROUP1_OP_ADD = 0,
         GROUP1_OP_OR  = 1,
@@ -661,6 +685,12 @@ public:
         emitModRm_rm(dst, base, offset);
     }
 
+    void leal_mr(int offset, RegisterID index, int scale, RegisterID dst)
+    {
+        m_buffer->putByte(OP_LEA);
+        emitModRm_rmsib(dst, X86::noBase, index, scale, offset);
+    }
+
     void ret()
     {
         m_buffer->putByte(OP_RET);
@@ -678,6 +708,111 @@ public:
         emitModRm_opm(GROUP5_OP_JMPN, base, offset);
     }
     
+    void movsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MOVSD_VsdWsd);
+        emitModRm_rm((RegisterID)dst, base, offset);
+    }
+
+    void movsd_rm(XMMRegisterID src, int offset, RegisterID base)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MOVSD_WsdVsd);
+        emitModRm_rm((RegisterID)src, base, offset);
+    }
+
+    void movd_rr(XMMRegisterID src, RegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_66);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MOVD_EdVd);
+        emitModRm_rr((RegisterID)src, dst);
+    }
+
+    void cvtsi2sd_rr(RegisterID src, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_CVTSI2SD_VsdEd);
+        emitModRm_rr((RegisterID)dst, src);
+    }
+
+    void cvttsd2si_rr(XMMRegisterID src, RegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_CVTTSD2SI_GdWsd);
+        emitModRm_rr(dst, (RegisterID)src);
+    }
+
+    void addsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_ADDSD_VsdWsd);
+        emitModRm_rm((RegisterID)dst, base, offset);
+    }
+
+    void subsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_SUBSD_VsdWsd);
+        emitModRm_rm((RegisterID)dst, base, offset);
+    }
+
+    void mulsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MULSD_VsdWsd);
+        emitModRm_rm((RegisterID)dst, base, offset);
+    }
+
+    void addsd_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_ADDSD_VsdWsd);
+        emitModRm_rr((RegisterID)dst, (RegisterID)src);
+    }
+
+    void subsd_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_SUBSD_VsdWsd);
+        emitModRm_rr((RegisterID)dst, (RegisterID)src);
+    }
+
+    void mulsd_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_F2);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MULSD_VsdWsd);
+        emitModRm_rr((RegisterID)dst, (RegisterID)src);
+    }
+
+    void ucomis_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_66);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_UCOMISD_VsdWsd);
+        emitModRm_rr((RegisterID)dst, (RegisterID)src);
+    }
+
+    void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst)
+    {
+        m_buffer->putByte(PRE_SSE_66);
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_PEXTRW_GdUdIb);
+        emitModRm_rr(dst, (RegisterID)src);
+        m_buffer->putByte(whichWord);
+    }
+
     // Opaque label types
     
     class JmpSrc {
@@ -826,6 +961,14 @@ public:
         m_buffer->putInt(0);
         return JmpSrc(m_buffer->getOffset());
     }
+
+    JmpSrc emitUnlinkedJp()
+    {
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_JP_rel32);
+        m_buffer->putInt(0);
+        return JmpSrc(m_buffer->getOffset());
+    }
     
     void emitPredictionNotTaken()
     {