2008-09-14 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 02:13:10 +0000 (02:13 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 02:13:10 +0000 (02:13 +0000)
        Reviewed by Cameron Zwarich.

        - split the "prototype" lookup for hasInstance into opcode stream so it can be cached

        ~5% speedup on v8 earley-boyer test

        * API/JSCallbackObject.h: Add a parameter for the pre-looked-up prototype.
        * API/JSCallbackObjectFunctions.h:
        (JSC::::hasInstance): Ditto.
        * API/JSValueRef.cpp:
        (JSValueIsInstanceOfConstructor): Look up and pass in prototype.
        * JavaScriptCore.exp:
        * VM/CTI.cpp:
        (JSC::CTI::privateCompileMainPass): Pass along prototype.
        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump): Print third arg.
        * VM/CodeGenerator.cpp:
        (JSC::CodeGenerator::emitInstanceOf): Implement this, now that there
        is a third argument.
        * VM/CodeGenerator.h:
        * VM/Machine.cpp:
        (JSC::Machine::privateExecute): Pass along the prototype.
        (JSC::Machine::cti_op_instanceof): ditto
        * kjs/JSObject.cpp:
        (JSC::JSObject::hasInstance): Expect to get a pre-looked-up prototype.
        * kjs/JSObject.h:
        * kjs/nodes.cpp:
        (JSC::InstanceOfNode::emitCode): Emit a get_by_id of the prototype
        property and pass that register to instanceof.
        * kjs/nodes.h:

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

14 files changed:
JavaScriptCore/API/JSCallbackObject.h
JavaScriptCore/API/JSCallbackObjectFunctions.h
JavaScriptCore/API/JSValueRef.cpp
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/JSObject.cpp
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h

index 68f2e7d5ee3ed6e73d7ebf8e673501088de61b86..0c145c5da6f786418c868df93cc5a0f82693f0be 100644 (file)
@@ -60,7 +60,7 @@ private:
     virtual bool deleteProperty(ExecState*, unsigned);
 
     virtual bool implementsHasInstance() const;
-    virtual bool hasInstance(ExecState *exec, JSValue *value);
+    virtual bool hasInstance(ExecState* exec, JSValue* value, JSValue* proto);
 
     virtual void getPropertyNames(ExecState*, PropertyNameArray&);
 
index 45a8bdb5c599a8bcaae42290885eaf03bda755c0..1c57cc5ee9a0f493bb37a10da037ed259e6db275 100644 (file)
@@ -283,7 +283,7 @@ bool JSCallbackObject<Base>::implementsHasInstance() const
 }
 
 template <class Base>
-bool JSCallbackObject<Base>::hasInstance(ExecState *exec, JSValue *value)
+bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue* value, JSValue*)
 {
     JSContextRef execRef = toRef(exec);
     JSObjectRef thisRef = toRef(this);
index fa64a88f21dde5b3f92030b4d07526b84925d2b3..ba9b38e62db9b48730e87754c19dc9aae46646b4 100644 (file)
@@ -146,7 +146,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject
     JSObject* jsConstructor = toJS(constructor);
     if (!jsConstructor->implementsHasInstance())
         return false;
-    bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
+    bool result = jsConstructor->hasInstance(exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown
     if (exec->hadException()) {
         if (exception)
             *exception = toRef(exec->exception());
index edd3f75caefc5faee6dfef65d7e061b67c6e6941..db096145eec4e3348af4df6cf4ae3f8b31726a67 100644 (file)
@@ -1,3 +1,36 @@
+2008-09-14  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Cameron Zwarich.
+        
+        - split the "prototype" lookup for hasInstance into opcode stream so it can be cached
+        
+        ~5% speedup on v8 earley-boyer test
+
+        * API/JSCallbackObject.h: Add a parameter for the pre-looked-up prototype.
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::::hasInstance): Ditto.
+        * API/JSValueRef.cpp:
+        (JSValueIsInstanceOfConstructor): Look up and pass in prototype.
+        * JavaScriptCore.exp:
+        * VM/CTI.cpp:
+        (JSC::CTI::privateCompileMainPass): Pass along prototype.
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump): Print third arg.
+        * VM/CodeGenerator.cpp:
+        (JSC::CodeGenerator::emitInstanceOf): Implement this, now that there
+        is a third argument.
+        * VM/CodeGenerator.h:
+        * VM/Machine.cpp:
+        (JSC::Machine::privateExecute): Pass along the prototype.
+        (JSC::Machine::cti_op_instanceof): ditto
+        * kjs/JSObject.cpp:
+        (JSC::JSObject::hasInstance): Expect to get a pre-looked-up prototype.
+        * kjs/JSObject.h:
+        * kjs/nodes.cpp:
+        (JSC::InstanceOfNode::emitCode): Emit a get_by_id of the prototype
+        property and pass that register to instanceof.
+        * kjs/nodes.h:
+
 2008-09-14  Gavin Barraclough  <barraclough@apple.com>
 
         Reviewed by Sam Weinig.
index 2823641e822e7d42ef424b9d51b16de0e22fb810..a7d987565754869d7f7104beabc58745bc184299 100644 (file)
@@ -216,7 +216,7 @@ __ZN3JSC8Debugger6attachEPNS_14JSGlobalObjectE
 __ZN3JSC8Debugger6detachEPNS_14JSGlobalObjectE
 __ZN3JSC8DebuggerC2Ev
 __ZN3JSC8DebuggerD2Ev
-__ZN3JSC8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
+__ZN3JSC8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueES4_
 __ZN3JSC8JSObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPS0_
 __ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_
 __ZN3JSC8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE
index ad00c5dd67d0aa4890c60e8eed1739d1a735607f..ac58c7774d1e90c2645428d829b35a82202364bc 100644 (file)
@@ -630,9 +630,10 @@ void CTI::privateCompileMainPass()
         case op_instanceof: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
+            emitGetPutArg(instruction[i + 4].u.operand, 8, X86::ecx);
             emitCall(i, Machine::cti_op_instanceof);
             emitPutResult(instruction[i + 1].u.operand);
-            i += 4;
+            i += 5;
             break;
         }
         case op_del_by_id: {
index 3a2056164805f891cd62f93a48d4b292f9c2343e..78b4d0915fcb3355deb88ecc963f9b9b29a42d7d 100644 (file)
@@ -488,7 +488,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             break;
         }
         case op_instanceof: {
-            printBinaryOp(location, it, "instanceof");
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str());
             break;
         }
         case op_typeof: {
index 00e7b6e1443ef13519c74a0c5ab1848868c6f325..af3d952c4802809b3405a32b8096804679f7f8e9 100644 (file)
@@ -805,6 +805,16 @@ bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, s
     return true;
 }
 
+RegisterID* CodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype)
+{ 
+    emitOpcode(op_instanceof);
+    instructions().append(dst->index());
+    instructions().append(value->index());
+    instructions().append(base->index());
+    instructions().append(basePrototype->index());
+    return dst;
+}
+
 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
 {
     size_t depth = 0;
index f4fdafa0ca6db0fa327ceaaf857ac532960f95db..6eebc6e1ab6594bda9c010814521b1cc73da4846 100644 (file)
@@ -252,7 +252,7 @@ namespace JSC {
         RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst);
         RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst);
 
-        RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base) { return emitBinaryOp(op_instanceof, dst, value, base); }
+        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); }
 
index 98f783db052fae260205dba3139e38f846cbd161..4c97b22a803115726220b68b337e667587bb53a8 100644 (file)
@@ -2037,10 +2037,14 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_instanceof) {
-        /* instanceof dst(r) value(r) constructor(r)
+        /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
 
            Tests whether register value is an instance of register
-           constructor, and puts the boolean result in register dst.
+           constructor, and puts the boolean result in register
+           dst. Register constructorProto must contain the "prototype"
+           property (not the actual prototype) of the object in
+           register constructor. This lookup is separated so that
+           polymorphic inline caching can apply.
 
            Raises an exception if register constructor is not an
            object.
@@ -2048,6 +2052,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         int dst = (++vPC)->u.operand;
         int value = (++vPC)->u.operand;
         int base = (++vPC)->u.operand;
+        int baseProto = (++vPC)->u.operand;
 
         JSValue* baseVal = r[base].jsValue(exec);
 
@@ -2055,7 +2060,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             goto vm_throw;
 
         JSObject* baseObj = static_cast<JSObject*>(baseVal);
-        r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
+        r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
 
         ++vPC;
         NEXT_OPCODE;
@@ -4176,7 +4181,8 @@ JSValue* Machine::cti_op_instanceof(CTI_ARGS)
     }
 
     JSObject* baseObj = static_cast<JSObject*>(baseVal);
-    JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec,  ARG_src1) : false);
+    JSValue* basePrototype = ARG_src3;
+    JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec,  ARG_src1, basePrototype) : false);
     VM_CHECK_EXCEPTION_AT_END();
     return result;
 }
index fad50ff83cbaf17edfb7b61d1b98d9719402f30b..342268e948c00f4ebf9f9d31e59eaf1ebee39e9f 100644 (file)
@@ -389,9 +389,8 @@ bool JSObject::implementsHasInstance() const
     return false;
 }
 
-bool JSObject::hasInstance(ExecState* exec, JSValue* value)
+bool JSObject::hasInstance(ExecState* exec, JSValue* value, JSValue* proto)
 {
-    JSValue* proto = get(exec, exec->propertyNames().prototype);
     if (!proto->isObject()) {
         throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
         return false;
index db49841ddbbe788efc0a8f9ee767eef4e298ef38..4efadbb8ea32bd03efd5640c5af63a8adc0ca8ea 100644 (file)
@@ -105,7 +105,7 @@ namespace JSC {
         virtual JSValue* defaultValue(ExecState*, PreferredPrimitiveType) const;
 
         virtual bool implementsHasInstance() const;
-        virtual bool hasInstance(ExecState*, JSValue*);
+        virtual bool hasInstance(ExecState*, JSValue*, JSValue* prototypeProperty);
 
         virtual void getPropertyNames(ExecState*, PropertyNameArray&);
 
index 510d668fd5dda6099d2afea22541838e0833a0d8..b9649cb3ea1f62f56d757ce3a177b640f0c32d4f 100644 (file)
@@ -794,6 +794,15 @@ RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID
     return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2);
 }
 
+RegisterID* InstanceOfNode::emitCode(CodeGenerator& generator, RegisterID* dst)
+{
+    RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+    RefPtr<RegisterID> src2 = generator.emitNode(m_expr2.get());
+    RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalExec()->propertyNames().prototype);
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+    return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype);
+}
+
 // ------------------------------ Binary Logical Nodes ----------------------------
 
 RegisterID* LogicalOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
index 39b296a846a9a67a067be2cade282a3f842dabd0..1e356513e0914909c073fe77c429666a278d35ea 100644 (file)
@@ -1427,6 +1427,8 @@ namespace JSC {
         virtual OpcodeID opcode() const JSC_FAST_CALL { return op_instanceof; }
         virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
         virtual Precedence precedence() const { return PrecRelational; }
+
+        virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
     };
 
     class InNode : public ThrowableBinaryOpNode {