2008-09-15 Gavin Barraclough <barraclough@apple.com>
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 23:33:25 +0000 (23:33 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 23:33:25 +0000 (23:33 +0000)
        Reviewed by Geoff Garen.

        Inline code generation of eq_null/neq_null for CTI.  Uses vptr checking for
        StringObjectsThatAreMasqueradingAsBeingUndefined.  In the long run, the
        masquerading may be handled differently (through the StructureIDs - see bug
        #20823).

        >1% on v8-tests.

        * VM/CTI.cpp:
        (JSC::CTI::emitJumpSlowCaseIfIsJSCell):
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        * VM/CTI.h:
        * VM/Machine.cpp:
        (JSC::Machine::Machine):
        (JSC::Machine::cti_op_eq_null):
        (JSC::Machine::cti_op_neq_null):
        * VM/Machine.h:
        (JSC::Machine::doesMasqueradesAsUndefined):
        * kjs/JSWrapperObject.h:
        (JSC::JSWrapperObject::):
        (JSC::JSWrapperObject::JSWrapperObject):
        * kjs/StringObject.h:
        (JSC::StringObject::StringObject):
        * kjs/StringObjectThatMasqueradesAsUndefined.h:
        (JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined):

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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/kjs/JSCell.h
JavaScriptCore/kjs/JSWrapperObject.h
JavaScriptCore/kjs/StringObject.h
JavaScriptCore/kjs/StringObjectThatMasqueradesAsUndefined.h

index eceb9db..03c4c1a 100644 (file)
@@ -1,3 +1,33 @@
+2008-09-15  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Geoff Garen.
+
+        Inline code generation of eq_null/neq_null for CTI.  Uses vptr checking for
+        StringObjectsThatAreMasqueradingAsBeingUndefined.  In the long run, the
+        masquerading may be handled differently (through the StructureIDs - see bug
+        #20823).
+
+        >1% on v8-tests.
+
+        * VM/CTI.cpp:
+        (JSC::CTI::emitJumpSlowCaseIfIsJSCell):
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        * VM/CTI.h:
+        * VM/Machine.cpp:
+        (JSC::Machine::Machine):
+        (JSC::Machine::cti_op_eq_null):
+        (JSC::Machine::cti_op_neq_null):
+        * VM/Machine.h:
+        (JSC::Machine::doesMasqueradesAsUndefined):
+        * kjs/JSWrapperObject.h:
+        (JSC::JSWrapperObject::):
+        (JSC::JSWrapperObject::JSWrapperObject):
+        * kjs/StringObject.h:
+        (JSC::StringObject::StringObject):
+        * kjs/StringObjectThatMasqueradesAsUndefined.h:
+        (JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined):
+
 2008-09-15  Cameron Zwarich  <cwzwarich@uwaterloo.ca>
 
         Rubber-stamped by Oliver Hunt.
index 6a2a36d..b556019 100644 (file)
@@ -317,6 +317,12 @@ ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCall(unsigned opcodeIndex, CTIHelper
     return call;
 }
 
+ALWAYS_INLINE void CTI::emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex)
+{
+    m_jit.testl_i32r(JSImmediate::TagMask, reg);
+    m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), opcodeIndex));
+}
+
 ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex)
 {
     m_jit.testl_i32r(JSImmediate::TagMask, reg);
@@ -1389,16 +1395,32 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_eq_null: {
-            emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
-            emitCall(i, Machine::cti_op_eq_null);
+            emitGetArg(instruction[i + 2].u.operand, X86::edx);
+
+            // go to a slow case either if this is not an immediate, or if the immediate is not undefined/null.
+            emitJumpSlowCaseIfIsJSCell(X86::edx, i);
+            m_jit.andl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::edx);
+            m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::edx);
+            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
             emitPutResult(instruction[i + 1].u.operand);
+
             i += 3;
             break;
         }
         case op_neq_null: {
-            emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
-            emitCall(i, Machine::cti_op_neq_null);
+            emitGetArg(instruction[i + 2].u.operand, X86::edx);
+
+            // go to a slow case either if this is not an immediate, or if the immediate is not undefined/null.
+            emitJumpSlowCaseIfIsJSCell(X86::edx, i);
+            m_jit.andl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::edx);
+            m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::edx);
+            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
             emitPutResult(instruction[i + 1].u.operand);
+
             i += 3;
             break;
         }
@@ -1847,6 +1869,50 @@ void CTI::privateCompileSlowCases()
             break;
         }
         CTI_COMPILE_BINARY_OP_SLOW_CASE(op_mul);
+        case op_eq_null: {
+            m_jit.link(iter->from, m_jit.label());
+
+            // Value is a JSCell - speculate false, check for StringObjectThatMasqueradesAsUndefined.
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringObjectThatMasqueradesAsUndefinedVptr), X86::edx);
+            m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3]);
+            
+            // Value is a StringObjectThatMasqueradesAsUndefined
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 3]);
+
+            // Value is an immediate other than undefined/null
+            m_jit.link((++iter)->from, m_jit.label());
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            
+            i += 3;
+            break;
+        }
+        case op_neq_null: {
+            m_jit.link(iter->from, m_jit.label());
+
+            // Value is a JSCell - speculate false, check for StringObjectThatMasqueradesAsUndefined.
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringObjectThatMasqueradesAsUndefinedVptr), X86::edx);
+            m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3]);
+            
+            // Value is a StringObjectThatMasqueradesAsUndefined
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 3]);
+
+            // Value is an immediate other than undefined/null
+            m_jit.link((++iter)->from, m_jit.label());
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+            emitPutResult(instruction[i + 1].u.operand);
+            
+            i += 3;
+            break;
+        }
         default:
             ASSERT_NOT_REACHED();
             break;
index 6eb761a..0258046 100644 (file)
@@ -244,7 +244,11 @@ namespace JSC {
         static const int repatchOffsetGetByIdStructureID = 19;
         static const int repatchOffsetGetByIdBranchToSlowCase = 25;
         static const int repatchOffsetGetByIdPropertyMapOffset = 34;
+#if ENABLE(SAMPLING_TOOL)
+        static const int repatchOffsetGetByIdSlowCaseCall = 27;
+#else
         static const int repatchOffsetGetByIdSlowCaseCall = 17;
+#endif
 
     public:
         static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
@@ -351,6 +355,7 @@ namespace JSC {
         JSValue* getConstantImmediateNumericArg(unsigned src);
         unsigned getDeTaggedConstantImmediate(JSValue* imm);
 
+        void CTI::emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
         void CTI::emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
         void emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID, unsigned opcodeIndex);
         void emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
index 8a7a001..379dd2e 100644 (file)
@@ -53,6 +53,7 @@
 #include "debugger.h"
 #include "operations.h"
 #include "SamplingTool.h"
+#include "StringObjectThatMasqueradesAsUndefined.h"
 #include <stdio.h>
 
 #if PLATFORM(DARWIN)
@@ -572,6 +573,10 @@ Machine::Machine()
     m_jsArrayVptr = jsArray->vptr();
     static_cast<JSCell*>(jsArray)->~JSCell();
 
+    StringObjectThatMasqueradesAsUndefined* jsStringObjectThatMasqueradesAsUndefined = new (storage) StringObjectThatMasqueradesAsUndefined(StringObjectThatMasqueradesAsUndefined::VPtrStealingHack);
+    m_jsStringObjectThatMasqueradesAsUndefinedVptr = jsStringObjectThatMasqueradesAsUndefined->vptr();
+    static_cast<JSCell*>(jsStringObjectThatMasqueradesAsUndefined)->~JSCell();
+
     JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
     m_jsStringVptr = jsString->vptr();
     static_cast<JSCell*>(jsString)->~JSCell();
@@ -5401,10 +5406,11 @@ void Machine::cti_op_debug(CTI_ARGS)
 JSValue* Machine::cti_op_eq_null(CTI_ARGS)
 {
     JSValue* src = ARG_src1;
+    
     if (src->isUndefinedOrNull())
         return jsBoolean(true);
 
-    return jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
+    return jsBoolean(ARG_exec->machine()->doesMasqueradesAsUndefined(src));
 }
 
 JSValue* Machine::cti_op_neq_null(CTI_ARGS)
@@ -5413,7 +5419,7 @@ JSValue* Machine::cti_op_neq_null(CTI_ARGS)
     if (src->isUndefinedOrNull())
         return jsBoolean(false);
 
-    return jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
+    return jsBoolean(!ARG_exec->machine()->doesMasqueradesAsUndefined(src));
 }
 
 void* Machine::cti_vm_throw(CTI_ARGS)
index 0f4d3ae..bcf3105 100644 (file)
@@ -259,6 +259,7 @@ namespace JSC {
 
         bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
         bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
+        bool doesMasqueradesAsUndefined(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringObjectThatMasqueradesAsUndefinedVptr; }
         
         void tryCacheGetByID(ExecState*, CodeBlock*, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
         void uncacheGetByID(CodeBlock*, Instruction* vPC);
@@ -290,6 +291,7 @@ namespace JSC {
         
         void* m_jsArrayVptr;
         void* m_jsStringVptr;
+        void* m_jsStringObjectThatMasqueradesAsUndefinedVptr;
         void* m_jsFunctionVptr;
 
 #if HAVE(COMPUTED_GOTO)
index 3c9fbfb..c1ad5f9 100644 (file)
@@ -78,6 +78,10 @@ namespace JSC {
         virtual JSObject* toObject(ExecState*) const = 0;
 
         // WebCore uses this to make document.all and style.filter undetectable
+        //
+        // This in checked in CTI using a vptr check, so currently only StringObjectThatMasqueradesAsUndefined
+        // overloading ths is supported.  If this behaviour is required in other classes, then we will need
+        // update the code generated.
         virtual bool masqueradeAsUndefined() const { return false; }
 
         // Garbage collection.
index 3c7c6f9..ea33f2e 100644 (file)
@@ -34,6 +34,13 @@ namespace JSC {
     */ 
     class JSWrapperObject : public JSObject {
     public:
+
+        enum VPtrStealingHackType { VPtrStealingHack };
+        JSWrapperObject(VPtrStealingHackType)
+            : JSObject(StructureID::create(jsNull()))
+        {
+        }
+
         JSWrapperObject(JSObject* prototype);
         
         JSValue* internalValue() const;
index 597c8dd..cc41d2e 100644 (file)
@@ -28,6 +28,10 @@ namespace JSC {
 
     class StringObject : public JSWrapperObject {
     public:
+        StringObject(VPtrStealingHackType type)
+            : JSWrapperObject(type)
+        {
+        }
         StringObject(ExecState*, JSObject* prototype);
         StringObject(ExecState*, JSObject* prototype, const UString&);
 
index 122eb42..6ee9497 100644 (file)
@@ -29,6 +29,10 @@ namespace JSC {
     // WebCore uses this to make style.filter undetectable
     class StringObjectThatMasqueradesAsUndefined : public StringObject {
     public:
+        StringObjectThatMasqueradesAsUndefined(VPtrStealingHackType type)
+            : StringObject(type)
+        {
+        }
         StringObjectThatMasqueradesAsUndefined(ExecState* exec, JSObject* prototype, const UString& string)
             : StringObject(exec, prototype, string)
         {