Changeset 129281 in webkit


Ignore:
Timestamp:
Sep 21, 2012 5:43:03 PM (12 years ago)
Author:
barraclough@apple.com
Message:

instanceof should not get the prototype for non-default HasInstance
https://bugs.webkit.org/show_bug.cgi?id=68656

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

Instanceof is currently implemented as a sequance of three opcodes:

check_has_instance
get_by_id(prototype)
op_instanceof

There are three interesting types of base value that instanceof can be applied to:

(A) Objects supporting default instanceof behaviour (functions, other than those created with bind)
(B) Objects overriding the default instancecof behaviour with a custom one (API objects, bound functions)
(C) Values that do not respond to the HasInstance? trap.

Currently check_has_instance handles case (C), leaving the op_instanceof opcode to handle (A) & (B). There are
two problems with this apporach. Firstly, this is suboptimal for case (A), since we have to check for
hasInstance support twice (once in check_has_instance, then for default behaviour in op_instanceof). Secondly,
this means that in cases (B) we also perform the get_by_id, which is both suboptimal and an observable spec
violation.

The fix here is to move handing of non-default instanceof (cases (B)) to the check_has_instance op, leaving
op_instanceof to handle only cases (A).

  • API/JSCallbackObject.h:

(JSCallbackObject):

  • API/JSCallbackObjectFunctions.h:

(JSC::::customHasInstance):

  • API/JSValueRef.cpp:

(JSValueIsInstanceOfConstructor):

  • renamed hasInstance to customHasInstance
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dump):

  • added additional parameters to check_has_instance opcode
  • bytecode/Opcode.h:

(JSC):
(JSC::padOpcodeName):

  • added additional parameters to check_has_instance opcode
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitCheckHasInstance):

  • added additional parameters to check_has_instance opcode
  • bytecompiler/BytecodeGenerator.h:

(BytecodeGenerator):

  • added additional parameters to check_has_instance opcode
  • bytecompiler/NodesCodegen.cpp:

(JSC::InstanceOfNode::emitBytecode):

  • added additional parameters to check_has_instance opcode
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • added additional parameters to check_has_instance opcode
  • interpreter/Interpreter.cpp:

(JSC::isInvalidParamForIn):
(JSC::Interpreter::privateExecute):

  • Add handling for non-default instanceof to op_check_has_instance
  • jit/JITInlineMethods.h:

(JSC::JIT::emitArrayProfilingSiteForBytecodeIndex):

  • Fixed no-LLInt no_DFG build
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_check_has_instance):
(JSC::JIT::emitSlow_op_check_has_instance):

  • check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.

(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emitSlow_op_instanceof):

  • no need to check for ImplementsDefaultHasInstance.
  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_check_has_instance):
(JSC::JIT::emitSlow_op_check_has_instance):

  • check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.

(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emitSlow_op_instanceof):

  • no need to check for ImplementsDefaultHasInstance.
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jit/JITStubs.h:
    • Add handling for non-default instanceof to op_check_has_instance
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
    • move check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.
  • runtime/ClassInfo.h:

(MethodTable):
(JSC):

  • renamed hasInstance to customHasInstance
  • runtime/CommonSlowPaths.h:

(CommonSlowPaths):

  • removed opInstanceOfSlow (this was whittled down to one function call!)
  • runtime/JSBoundFunction.cpp:

(JSC::JSBoundFunction::customHasInstance):

  • runtime/JSBoundFunction.h:

(JSBoundFunction):

  • renamed hasInstance to customHasInstance, reimplemented.
  • runtime/JSCell.cpp:

(JSC::JSCell::customHasInstance):

  • runtime/JSCell.h:

(JSCell):

  • runtime/JSObject.cpp:

(JSC::JSObject::hasInstance):
(JSC):
(JSC::JSObject::defaultHasInstance):

  • runtime/JSObject.h:

(JSObject):

LayoutTests:

  • fast/js/function-bind-expected.txt:
    • check in passing result.
Location:
trunk
Files:
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r129279 r129281  
     12012-09-21  Gavin Barraclough  <barraclough@apple.com>
     2
     3        instanceof should not get the prototype for non-default HasInstance
     4        https://bugs.webkit.org/show_bug.cgi?id=68656
     5
     6        Reviewed by Oliver Hunt.
     7
     8        * fast/js/function-bind-expected.txt:
     9            - check in passing result.
     10
    1112012-09-21  Benjamin Poulain  <bpoulain@apple.com>
    212
  • trunk/LayoutTests/fast/js/function-bind-expected.txt

    r108729 r129281  
    2727    [native code]
    2828}' is not a constructor (evaluating 'new abcAt(1)').
    29 FAIL boundFunctionPrototypeAccessed should be false. Was true.
     29PASS boundFunctionPrototypeAccessed is false
    3030PASS Function.bind.length is 1
    3131PASS successfullyParsed is true
  • trunk/Source/JavaScriptCore/API/JSCallbackObject.h

    r128851 r129281  
    187187    static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
    188188
    189     static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto);
     189    static bool customHasInstance(JSObject*, ExecState*, JSValue);
    190190
    191191    static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
  • trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h

    r128400 r129281  
    390390
    391391template <class Parent>
    392 bool JSCallbackObject<Parent>::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue)
     392bool JSCallbackObject<Parent>::customHasInstance(JSObject* object, ExecState* exec, JSValue value)
    393393{
    394394    JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object);
  • trunk/Source/JavaScriptCore/API/JSValueRef.cpp

    r128851 r129281  
    176176    if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
    177177        return false;
    178     bool result = jsConstructor->methodTable()->hasInstance(jsConstructor, exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown
     178    bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
    179179    if (exec->hadException()) {
    180180        if (exception)
  • trunk/Source/JavaScriptCore/ChangeLog

    r129274 r129281  
     12012-09-21  Gavin Barraclough  <barraclough@apple.com>
     2
     3        instanceof should not get the prototype for non-default HasInstance
     4        https://bugs.webkit.org/show_bug.cgi?id=68656
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Instanceof is currently implemented as a sequance of three opcodes:
     9            check_has_instance
     10            get_by_id(prototype)
     11            op_instanceof
     12        There are three interesting types of base value that instanceof can be applied to:
     13            (A) Objects supporting default instanceof behaviour (functions, other than those created with bind)
     14            (B) Objects overriding the default instancecof behaviour with a custom one (API objects, bound functions)
     15            (C) Values that do not respond to the [[HasInstance]] trap.
     16        Currently check_has_instance handles case (C), leaving the op_instanceof opcode to handle (A) & (B). There are
     17        two problems with this apporach. Firstly, this is suboptimal for case (A), since we have to check for
     18        hasInstance support twice (once in check_has_instance, then for default behaviour in op_instanceof). Secondly,
     19        this means that in cases (B) we also perform the get_by_id, which is both suboptimal and an observable spec
     20        violation.
     21
     22        The fix here is to move handing of non-default instanceof (cases (B)) to the check_has_instance op, leaving
     23        op_instanceof to handle only cases (A).
     24
     25        * API/JSCallbackObject.h:
     26        (JSCallbackObject):
     27        * API/JSCallbackObjectFunctions.h:
     28        (JSC::::customHasInstance):
     29        * API/JSValueRef.cpp:
     30        (JSValueIsInstanceOfConstructor):
     31            - renamed hasInstance to customHasInstance
     32        * bytecode/CodeBlock.cpp:
     33        (JSC::CodeBlock::dump):
     34            - added additional parameters to check_has_instance opcode
     35        * bytecode/Opcode.h:
     36        (JSC):
     37        (JSC::padOpcodeName):
     38            - added additional parameters to check_has_instance opcode
     39        * bytecompiler/BytecodeGenerator.cpp:
     40        (JSC::BytecodeGenerator::emitCheckHasInstance):
     41            - added additional parameters to check_has_instance opcode
     42        * bytecompiler/BytecodeGenerator.h:
     43        (BytecodeGenerator):
     44            - added additional parameters to check_has_instance opcode
     45        * bytecompiler/NodesCodegen.cpp:
     46        (JSC::InstanceOfNode::emitBytecode):
     47            - added additional parameters to check_has_instance opcode
     48        * dfg/DFGByteCodeParser.cpp:
     49        (JSC::DFG::ByteCodeParser::parseBlock):
     50            - added additional parameters to check_has_instance opcode
     51        * interpreter/Interpreter.cpp:
     52        (JSC::isInvalidParamForIn):
     53        (JSC::Interpreter::privateExecute):
     54            - Add handling for non-default instanceof to op_check_has_instance
     55        * jit/JITInlineMethods.h:
     56        (JSC::JIT::emitArrayProfilingSiteForBytecodeIndex):
     57            - Fixed no-LLInt no_DFG build
     58        * jit/JITOpcodes.cpp:
     59        (JSC::JIT::emit_op_check_has_instance):
     60        (JSC::JIT::emitSlow_op_check_has_instance):
     61            - check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.
     62        (JSC::JIT::emit_op_instanceof):
     63        (JSC::JIT::emitSlow_op_instanceof):
     64            - no need to check for ImplementsDefaultHasInstance.
     65        * jit/JITOpcodes32_64.cpp:
     66        (JSC::JIT::emit_op_check_has_instance):
     67        (JSC::JIT::emitSlow_op_check_has_instance):
     68            - check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.
     69        (JSC::JIT::emit_op_instanceof):
     70        (JSC::JIT::emitSlow_op_instanceof):
     71            - no need to check for ImplementsDefaultHasInstance.
     72        * jit/JITStubs.cpp:
     73        (JSC::DEFINE_STUB_FUNCTION):
     74        * jit/JITStubs.h:
     75            - Add handling for non-default instanceof to op_check_has_instance
     76        * llint/LLIntSlowPaths.cpp:
     77        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     78        * llint/LowLevelInterpreter32_64.asm:
     79        * llint/LowLevelInterpreter64.asm:
     80            - move check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance.
     81        * runtime/ClassInfo.h:
     82        (MethodTable):
     83        (JSC):
     84            - renamed hasInstance to customHasInstance
     85        * runtime/CommonSlowPaths.h:
     86        (CommonSlowPaths):
     87            - removed opInstanceOfSlow (this was whittled down to one function call!)
     88        * runtime/JSBoundFunction.cpp:
     89        (JSC::JSBoundFunction::customHasInstance):
     90        * runtime/JSBoundFunction.h:
     91        (JSBoundFunction):
     92            - renamed hasInstance to customHasInstance, reimplemented.
     93        * runtime/JSCell.cpp:
     94        (JSC::JSCell::customHasInstance):
     95        * runtime/JSCell.h:
     96        (JSCell):
     97        * runtime/JSObject.cpp:
     98        (JSC::JSObject::hasInstance):
     99        (JSC):
     100        (JSC::JSObject::defaultHasInstance):
     101        * runtime/JSObject.h:
     102        (JSObject):
     103
    11042012-09-21  Filip Pizlo  <fpizlo@apple.com>
    2105
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r128534 r129281  
    874874        }
    875875        case op_check_has_instance: {
    876             int base = (++it)->u.operand;
    877             dataLog("[%4d] check_has_instance\t\t %s", location, registerName(exec, base).data());
     876            int r0 = (++it)->u.operand;
     877            int r1 = (++it)->u.operand;
     878            int r2 = (++it)->u.operand;
     879            int offset = (++it)->u.operand;
     880            dataLog("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset);
    878881            dumpBytecodeCommentAndNewLine(location);
    879882            break;
  • trunk/Source/JavaScriptCore/bytecode/Opcode.h

    r128534 r129281  
    8585        macro(op_bitor, 5) \
    8686        \
    87         macro(op_check_has_instance, 2) \
     87        macro(op_check_has_instance, 5) \
    8888        macro(op_instanceof, 5) \
    8989        macro(op_typeof, 3) \
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r128832 r129281  
    14581458}
    14591459
    1460 void BytecodeGenerator::emitCheckHasInstance(RegisterID* base)
    1461 {
     1460void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target)
     1461{
     1462    size_t begin = instructions().size();
    14621463    emitOpcode(op_check_has_instance);
     1464    instructions().append(dst->index());
     1465    instructions().append(value->index());
    14631466    instructions().append(base->index());
     1467    instructions().append(target->bind(begin, instructions().size()));
    14641468}
    14651469
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r128534 r129281  
    456456        RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst);
    457457
    458         void emitCheckHasInstance(RegisterID* base);
     458        void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target);
    459459        RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype);
    460460        RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r129156 r129281  
    10891089    RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator));
    10901090    RefPtr<RegisterID> src2 = generator.emitNode(m_expr2);
     1091    RefPtr<RegisterID> prototype = generator.newTemporary();
     1092    RefPtr<RegisterID> dstReg = generator.finalDestination(dst, src1.get());
     1093    RefPtr<Label> target = generator.newLabel();
    10911094
    10921095    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    1093     generator.emitCheckHasInstance(src2.get());
     1096    generator.emitCheckHasInstance(dstReg.get(), src1.get(), src2.get(), target.get());
    10941097
    10951098    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    1096     RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype);
     1099    generator.emitGetById(prototype.get(), src2.get(), generator.globalData()->propertyNames->prototype);
    10971100
    10981101    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    1099     return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype);
     1102    RegisterID* result = generator.emitInstanceOf(dstReg.get(), src1.get(), src2.get(), prototype.get());
     1103    generator.emitLabel(target.get());
     1104    return result;
    11001105}
    11011106
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r129156 r129281  
    20502050
    20512051        case op_check_has_instance:
    2052             addToGraph(CheckHasInstance, get(currentInstruction[1].u.operand));
     2052            addToGraph(CheckHasInstance, get(currentInstruction[3].u.operand));
    20532053            NEXT_OPCODE(op_check_has_instance);
    20542054
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r129156 r129281  
    130130        return false;
    131131    exceptionData = createInvalidParamError(callFrame, "in" , value);
    132     return true;
    133 }
    134 
    135 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
    136 {
    137     if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
    138         return false;
    139     exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
    140132    return true;
    141133}
     
    24022394           an valid parameter for instanceof.
    24032395        */
    2404         int base = vPC[1].u.operand;
     2396        int dst = vPC[1].u.operand;
     2397        int value = vPC[2].u.operand;
     2398        int base = vPC[3].u.operand;
     2399        int target = vPC[4].u.operand;
     2400
    24052401        JSValue baseVal = callFrame->r(base).jsValue();
    24062402
    2407         if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
    2408             goto vm_throw;
    2409 
    2410         vPC += OPCODE_LENGTH(op_check_has_instance);
    2411         NEXT_INSTRUCTION();
     2403        if (baseVal.isObject()) {
     2404            TypeInfo info = asObject(baseVal)->structure()->typeInfo();
     2405            if (info.implementsDefaultHasInstance()) {
     2406                vPC += OPCODE_LENGTH(op_check_has_instance);
     2407                NEXT_INSTRUCTION();
     2408            }
     2409            if (info.implementsHasInstance()) {
     2410                JSValue baseVal = callFrame->r(base).jsValue();
     2411                bool result = asObject(baseVal)->methodTable()->customHasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue());
     2412                CHECK_FOR_EXCEPTION();
     2413                callFrame->uncheckedR(dst) = jsBoolean(result);
     2414
     2415                vPC += target;
     2416                NEXT_INSTRUCTION();
     2417            }
     2418        }
     2419
     2420        exceptionValue = createInvalidParamError(callFrame, "instanceof" , baseVal);
     2421        goto vm_throw;
    24122422    }
    24132423    DEFINE_OPCODE(op_instanceof) {
     
    24262436        int dst = vPC[1].u.operand;
    24272437        int value = vPC[2].u.operand;
    2428         int base = vPC[3].u.operand;
    24292438        int baseProto = vPC[4].u.operand;
    24302439
    2431         JSValue baseVal = callFrame->r(base).jsValue();
    2432 
    2433         ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
    2434 
    2435         bool result = asObject(baseVal)->methodTable()->hasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
     2440        ASSERT(callFrame->r(vPC[3].u.operand).jsValue().isObject() && asObject(callFrame->r(vPC[3].u.operand).jsValue())->structure()->typeInfo().implementsDefaultHasInstance());
     2441
     2442        bool result = JSObject::defaultHasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
    24362443        CHECK_FOR_EXCEPTION();
    24372444        callFrame->uncheckedR(dst) = jsBoolean(result);
  • trunk/Source/JavaScriptCore/jit/JITInlineMethods.h

    r129045 r129281  
    553553    emitArrayProfilingSite(structureAndIndexingType, scratch, m_codeBlock->getOrAddArrayProfile(bytecodeIndex));
    554554#else
     555    UNUSED_PARAM(bytecodeIndex);
    555556    emitArrayProfilingSite(structureAndIndexingType, scratch, 0);
    556557#endif
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r128802 r129281  
    408408void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
    409409{
    410     unsigned baseVal = currentInstruction[1].u.operand;
     410    unsigned baseVal = currentInstruction[3].u.operand;
    411411
    412412    emitGetVirtualRegister(baseVal, regT0);
     
    417417    // Check that baseVal 'ImplementsHasInstance'.
    418418    loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
    419     addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance)));
     419    addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
    420420}
    421421
     
    424424    unsigned dst = currentInstruction[1].u.operand;
    425425    unsigned value = currentInstruction[2].u.operand;
    426     unsigned baseVal = currentInstruction[3].u.operand;
    427426    unsigned proto = currentInstruction[4].u.operand;
    428427
     
    430429    // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result.
    431430    emitGetVirtualRegister(value, regT2);
    432     emitGetVirtualRegister(baseVal, regT0);
    433431    emitGetVirtualRegister(proto, regT1);
    434432
     
    441439    addSlowCase(emitJumpIfNotObject(regT3));
    442440   
    443     // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this.
    444     // Check that baseVal 'ImplementsDefaultHasInstance'.
    445     loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
    446     addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
    447 
    448441    // Optimistically load the result true, and start looping.
    449442    // Initially, regT1 still contains proto and regT2 still contains value.
     
    14531446void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    14541447{
    1455     unsigned baseVal = currentInstruction[1].u.operand;
     1448    unsigned dst = currentInstruction[1].u.operand;
     1449    unsigned value = currentInstruction[2].u.operand;
     1450    unsigned baseVal = currentInstruction[3].u.operand;
    14561451
    14571452    linkSlowCaseIfNotJSCell(iter, baseVal);
    14581453    linkSlowCase(iter);
    14591454    JITStubCall stubCall(this, cti_op_check_has_instance);
     1455    stubCall.addArgument(value, regT2);
    14601456    stubCall.addArgument(baseVal, regT2);
    1461     stubCall.call();
     1457    stubCall.call(dst);
     1458
     1459    emitJumpSlowToHot(jump(), currentInstruction[4].u.operand);
    14621460}
    14631461
     
    14711469    linkSlowCaseIfNotJSCell(iter, value);
    14721470    linkSlowCaseIfNotJSCell(iter, proto);
    1473     linkSlowCase(iter);
    14741471    linkSlowCase(iter);
    14751472    JITStubCall stubCall(this, cti_op_instanceof);
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r128122 r129281  
    544544void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
    545545{
    546     unsigned baseVal = currentInstruction[1].u.operand;
     546    unsigned baseVal = currentInstruction[3].u.operand;
    547547
    548548    emitLoadPayload(baseVal, regT0);
     
    553553    // Check that baseVal 'ImplementsHasInstance'.
    554554    loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
    555     addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance)));
     555    addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
    556556}
    557557
     
    560560    unsigned dst = currentInstruction[1].u.operand;
    561561    unsigned value = currentInstruction[2].u.operand;
    562     unsigned baseVal = currentInstruction[3].u.operand;
    563562    unsigned proto = currentInstruction[4].u.operand;
    564563
     
    566565    // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result.
    567566    emitLoadPayload(value, regT2);
    568     emitLoadPayload(baseVal, regT0);
    569567    emitLoadPayload(proto, regT1);
    570568
     
    576574    loadPtr(Address(regT1, JSCell::structureOffset()), regT3);
    577575    addSlowCase(emitJumpIfNotObject(regT3));
    578 
    579     // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this.
    580     // Check that baseVal 'ImplementsDefaultHasInstance'.
    581     loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
    582     addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
    583576
    584577    // Optimistically load the result true, and start looping.
     
    605598void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    606599{
    607     unsigned baseVal = currentInstruction[1].u.operand;
     600    unsigned dst = currentInstruction[1].u.operand;
     601    unsigned value = currentInstruction[2].u.operand;
     602    unsigned baseVal = currentInstruction[3].u.operand;
    608603
    609604    linkSlowCaseIfNotJSCell(iter, baseVal);
     
    611606
    612607    JITStubCall stubCall(this, cti_op_check_has_instance);
     608    stubCall.addArgument(value);
    613609    stubCall.addArgument(baseVal);
    614     stubCall.call();
     610    stubCall.call(dst);
     611
     612    emitJumpSlowToHot(jump(), currentInstruction[4].u.operand);
    615613}
    616614
     
    624622    linkSlowCaseIfNotJSCell(iter, value);
    625623    linkSlowCaseIfNotJSCell(iter, proto);
    626     linkSlowCase(iter);
    627624    linkSlowCase(iter);
    628625
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r128832 r129281  
    19381938}
    19391939
    1940 DEFINE_STUB_FUNCTION(void, op_check_has_instance)
    1941 {
    1942     STUB_INIT_STACK_FRAME(stackFrame);
    1943 
    1944     CallFrame* callFrame = stackFrame.callFrame;
    1945     JSValue baseVal = stackFrame.args[0].jsValue();
    1946 
    1947     // ECMA-262 15.3.5.3:
    1948     // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
    1949 #ifndef NDEBUG
    1950     TypeInfo typeInfo(UnspecifiedType);
    1951     ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance());
    1952 #endif
     1940DEFINE_STUB_FUNCTION(EncodedJSValue, op_check_has_instance)
     1941{
     1942    STUB_INIT_STACK_FRAME(stackFrame);
     1943
     1944    CallFrame* callFrame = stackFrame.callFrame;
     1945    JSValue value = stackFrame.args[0].jsValue();
     1946    JSValue baseVal = stackFrame.args[1].jsValue();
     1947
     1948    if (baseVal.isObject()) {
     1949        JSObject* baseObject = asObject(baseVal);
     1950        ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance());
     1951        if (baseObject->structure()->typeInfo().implementsHasInstance()) {
     1952            bool result = baseObject->methodTable()->customHasInstance(baseObject, callFrame, value);
     1953            CHECK_FOR_EXCEPTION_AT_END();
     1954            return JSValue::encode(jsBoolean(result));
     1955        }
     1956    }
     1957
    19531958    stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal);
    19541959    VM_THROW_EXCEPTION_AT_END();
     1960    return JSValue::encode(JSValue());
    19551961}
    19561962
     
    20832089    CallFrame* callFrame = stackFrame.callFrame;
    20842090    JSValue value = stackFrame.args[0].jsValue();
    2085     JSValue baseVal = stackFrame.args[1].jsValue();
    20862091    JSValue proto = stackFrame.args[2].jsValue();
    20872092   
    2088     bool result = CommonSlowPaths::opInstanceOfSlow(callFrame, value, baseVal, proto);
     2093    ASSERT(stackFrame.args[1].jsValue().isObject() && asObject(stackFrame.args[1].jsValue())->structure()->typeInfo().implementsDefaultHasInstance());
     2094    ASSERT(!value.isObject() || !proto.isObject());
     2095
     2096    bool result = JSObject::defaultHasInstance(callFrame, value, proto);
    20892097    CHECK_FOR_EXCEPTION_AT_END();
    20902098    return JSValue::encode(jsBoolean(result));
  • trunk/Source/JavaScriptCore/jit/JITStubs.h

    r127394 r129281  
    351351    EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    352352    EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     353    EncodedJSValue JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    353354    EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    354355    EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     
    432433    int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    433434    int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    434     void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    435435    void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    436436    void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r128832 r129281  
    719719{
    720720    LLINT_BEGIN();
    721     JSValue baseVal = LLINT_OP_C(1).jsValue();
    722 #ifndef NDEBUG
    723     TypeInfo typeInfo(UnspecifiedType);
    724     ASSERT(!baseVal.isObject()
    725            || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance());
    726 #endif
     721   
     722    JSValue value = LLINT_OP_C(2).jsValue();
     723    JSValue baseVal = LLINT_OP_C(3).jsValue();
     724    if (baseVal.isObject()) {
     725        JSObject* baseObject = asObject(baseVal);
     726        ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance());
     727        if (baseObject->structure()->typeInfo().implementsHasInstance()) {
     728            pc += pc[4].u.operand;
     729            LLINT_RETURN(jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value)));
     730        }
     731    }
    727732    LLINT_THROW(createInvalidParamError(exec, "instanceof", baseVal));
    728733}
     
    731736{
    732737    LLINT_BEGIN();
    733     LLINT_RETURN(jsBoolean(CommonSlowPaths::opInstanceOfSlow(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue())));
     738    JSValue value = LLINT_OP_C(2).jsValue();
     739    JSValue proto = LLINT_OP_C(4).jsValue();
     740    ASSERT(LLINT_OP_C(3).jsValue().isObject() && asObject(LLINT_OP_C(3).jsValue())->structure()->typeInfo().implementsDefaultHasInstance());
     741    ASSERT(!value.isObject() || !proto.isObject());
     742    LLINT_RETURN(jsBoolean(JSObject::defaultHasInstance(exec, value, proto)));
    734743}
    735744
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r129045 r129281  
    834834_llint_op_check_has_instance:
    835835    traceExecution()
    836     loadi 4[PC], t1
     836    loadi 12[PC], t1
    837837    loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
    838838    loadp JSCell::m_structure[t0], t0
    839     btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
    840     dispatch(2)
     839    btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow
     840    dispatch(5)
    841841
    842842.opCheckHasInstanceSlow:
    843843    callSlowPath(_llint_slow_path_check_has_instance)
    844     dispatch(2)
     844    dispatch(0)
    845845
    846846
    847847_llint_op_instanceof:
    848848    traceExecution()
    849     # Check that baseVal implements the default HasInstance behavior.
    850     # FIXME: This should be deprecated.
    851     loadi 12[PC], t1
    852     loadConstantOrVariablePayloadUnchecked(t1, t0)
    853     loadp JSCell::m_structure[t0], t0
    854     btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
    855    
    856849    # Actually do the work.
    857850    loadi 16[PC], t0
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r129045 r129281  
    692692_llint_op_check_has_instance:
    693693    traceExecution()
    694     loadis 8[PB, PC, 8], t1
     694    loadis 24[PB, PC, 8], t1
    695695    loadConstantOrVariableCell(t1, t0, .opCheckHasInstanceSlow)
    696696    loadp JSCell::m_structure[t0], t0
    697     btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
    698     dispatch(2)
     697    btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow
     698    dispatch(5)
    699699
    700700.opCheckHasInstanceSlow:
    701701    callSlowPath(_llint_slow_path_check_has_instance)
    702     dispatch(2)
     702    dispatch(0)
    703703
    704704
    705705_llint_op_instanceof:
    706706    traceExecution()
    707     # Check that baseVal implements the default HasInstance behavior.
    708     # FIXME: This should be deprecated.
    709     loadis 24[PB, PC, 8], t1
    710     loadConstantOrVariable(t1, t0)
    711     loadp JSCell::m_structure[t0], t0
    712     btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
    713    
    714707    # Actually do the work.
    715708    loadis 32[PB, PC, 8], t0
  • trunk/Source/JavaScriptCore/runtime/ClassInfo.h

    r128400 r129281  
    8282        ClassNameFunctionPtr className;
    8383
    84         typedef bool (*HasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue, JSValue);
    85         HasInstanceFunctionPtr hasInstance;
     84        typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue);
     85        CustomHasInstanceFunctionPtr customHasInstance;
    8686
    8787        typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes);
     
    131131        &ClassName::getPropertyNames, \
    132132        &ClassName::className, \
    133         &ClassName::hasInstance, \
     133        &ClassName::customHasInstance, \
    134134        &ClassName::putDirectVirtual, \
    135135        &ClassName::defineOwnProperty, \
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h

    r126893 r129281  
    7676}
    7777
    78 ALWAYS_INLINE bool opInstanceOfSlow(ExecState* exec, JSValue value, JSValue baseVal, JSValue proto)
    79 {
    80     ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell()
    81            || !value.isObject() || !baseVal.isObject() || !proto.isObject()
    82            || !asObject(baseVal)->structure()->typeInfo().implementsDefaultHasInstance());
    83 
    84 
    85     // ECMA-262 15.3.5.3:
    86     // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
    87     TypeInfo typeInfo(UnspecifiedType);
    88     if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) {
    89         exec->globalData().exception = createInvalidParamError(exec, "instanceof", baseVal);
    90         return false;
    91     }
    92     ASSERT(typeInfo.type() != UnspecifiedType);
    93 
    94     if (!typeInfo.overridesHasInstance() && !value.isObject())
    95         return false;
    96 
    97     return asObject(baseVal)->methodTable()->hasInstance(asObject(baseVal), exec, value, proto);
    98 }
    99 
    10078inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal)
    10179{
  • trunk/Source/JavaScriptCore/runtime/JSBoundFunction.cpp

    r128400 r129281  
    9090}
    9191
    92 bool JSBoundFunction::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue)
     92bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value)
    9393{
    94     JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(object);
    95     // FIXME: our instanceof implementation will have already (incorrectly) performed
    96     // a [[Get]] of .prototype from the bound function object, which is incorrect!
    97     // https://bugs.webkit.org/show_bug.cgi?id=68656
    98     JSValue proto = thisObject->m_targetFunction->get(exec, exec->propertyNames().prototype);
    99     return thisObject->m_targetFunction->methodTable()->hasInstance(thisObject->m_targetFunction.get(), exec, value, proto);
     94    return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value);
    10095}
    10196
  • trunk/Source/JavaScriptCore/runtime/JSBoundFunction.h

    r127191 r129281  
    4040    static JSBoundFunction* create(ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&);
    4141
    42     static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto);
     42    static bool customHasInstance(JSObject*, ExecState*, JSValue);
    4343
    4444    JSObject* targetFunction() { return m_targetFunction.get(); }
  • trunk/Source/JavaScriptCore/runtime/JSCell.cpp

    r128400 r129281  
    200200}
    201201
    202 bool JSCell::hasInstance(JSObject*, ExecState*, JSValue, JSValue)
     202bool JSCell::customHasInstance(JSObject*, ExecState*, JSValue)
    203203{
    204204    ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r128900 r129281  
    161161        static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    162162        static String className(const JSObject*);
    163         static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
     163        JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
    164164        static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
    165165        static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r129179 r129281  
    784784}
    785785
    786 bool JSObject::hasInstance(JSObject*, ExecState* exec, JSValue value, JSValue proto)
     786bool JSObject::hasInstance(ExecState* exec, JSValue value)
     787{
     788    TypeInfo info = structure()->typeInfo();
     789    if (info.implementsDefaultHasInstance())
     790        return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
     791    if (info.implementsHasInstance())
     792        return methodTable()->customHasInstance(this, exec, value);
     793    throwError(exec, createInvalidParamError(exec, "instanceof" , this));
     794    return false;
     795}
     796
     797bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
    787798{
    788799    if (!value.isObject())
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r129179 r129281  
    307307        JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
    308308
    309         JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
     309        bool hasInstance(ExecState*, JSValue);
     310        static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty);
    310311
    311312        JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
Note: See TracChangeset for help on using the changeset viewer.