Ignore:
Timestamp:
Sep 21, 2012, 5:43:03 PM (13 years ago)
Author:
[email protected]
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/Source/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.