Ignore:
Timestamp:
Dec 11, 2015, 1:43:45 PM (10 years ago)
Author:
[email protected]
Message:

[ES6] Add support for Symbol.hasInstance
https://bugs.webkit.org/show_bug.cgi?id=151839

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch adds support for Symbol.hasInstance, unfortunately in order to prevent
regressions several new bytecodes and DFG IR nodes were necessary. Before, Symbol.hasInstance
when executing an instanceof expression we would emit three bytecodes: overrides_has_instance, get_by_id,
then instanceof. As the spec has changed, we emit a more complicated set of bytecodes in addition to some
new ones. First the role of overrides_has_instance and its corresponding DFG node have changed. Now it returns
a js-boolean indicating whether the RHS of the instanceof expression (from here on called the constructor for simplicity)
needs non-default behavior for resolving the expression. i.e. The constructor has a Symbol.hasInstance that differs from the one on
Function.prototype[Symbol.hasInstance] or is a bound/C-API function. Once we get to the DFG this node is generally eliminated as
we can prove the value of Symbol.hasInstance is a constant. The second new bytecode is instanceof_custom. insntanceof_custom, just
emits a call to slow path code that computes the result.

In the DFG, there is also a new node, CheckTypeInfoFlags, which checks the type info flags are consistent with the ones provided and
OSR exits if the flags are not. Additionally, we attempt to prove that the result of CheckHasValue will be a constant and transform
it into a CheckTypeInfoFlags followed by a JSConstant.

  • API/JSCallbackObject.h:
  • builtins/FunctionPrototype.js:

(symbolHasInstance):

  • bytecode/BytecodeBasicBlock.cpp:

(JSC::isBranch): Deleted.

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • bytecode/ExitKind.cpp:

(JSC::exitKindToString):

  • bytecode/ExitKind.h:
  • bytecode/PreciseJumpTargets.cpp:

(JSC::getJumpTargetsForBytecodeOffset): Deleted.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitOverridesHasInstance):
(JSC::BytecodeGenerator::emitInstanceOfCustom):
(JSC::BytecodeGenerator::emitCheckHasInstance): Deleted.

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::InstanceOfNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGHeapLocation.cpp:

(WTF::printInternal):

  • dfg/DFGHeapLocation.h:
  • dfg/DFGNode.h:

(JSC::DFG::Node::hasCellOperand):
(JSC::DFG::Node::hasTypeInfoOperand):
(JSC::DFG::Node::typeInfoOperand):

  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCheckTypeInfoFlags):
(JSC::DFG::SpeculativeJIT::compileInstanceOfCustom):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLIntrinsicRepository.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileOverridesHasInstance):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCheckTypeInfoFlags):
(JSC::FTL::DFG::LowerDFGToLLVM::compileInstanceOfCustom):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCheckHasInstance): Deleted.

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:
  • jit/JITInlines.h:

(JSC::JIT::callOperation):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_overrides_has_instance):
(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emit_op_instanceof_custom):
(JSC::JIT::emitSlow_op_instanceof):
(JSC::JIT::emitSlow_op_instanceof_custom):
(JSC::JIT::emit_op_check_has_instance): Deleted.
(JSC::JIT::emitSlow_op_check_has_instance): Deleted.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_overrides_has_instance):
(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emit_op_instanceof_custom):
(JSC::JIT::emitSlow_op_instanceof_custom):
(JSC::JIT::emit_op_check_has_instance): Deleted.
(JSC::JIT::emitSlow_op_check_has_instance): Deleted.

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • llint/LLIntData.cpp:

(JSC::LLInt::Data::performAssertions):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/CommonIdentifiers.h:
  • runtime/ExceptionHelpers.cpp:

(JSC::invalidParameterInstanceofSourceAppender):
(JSC::invalidParameterInstanceofNotFunctionSourceAppender):
(JSC::invalidParameterInstanceofhasInstanceValueNotFunctionSourceAppender):
(JSC::createInvalidInstanceofParameterErrorNotFunction):
(JSC::createInvalidInstanceofParameterErrorhasInstanceValueNotFunction):
(JSC::createInvalidInstanceofParameterError): Deleted.

  • runtime/ExceptionHelpers.h:
  • runtime/FunctionPrototype.cpp:

(JSC::FunctionPrototype::addFunctionProperties):

  • runtime/FunctionPrototype.h:
  • runtime/JSBoundFunction.cpp:

(JSC::isBoundFunction):
(JSC::hasInstanceBoundFunction):

  • runtime/JSBoundFunction.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::functionProtoHasInstanceSymbolFunction):

  • runtime/JSObject.cpp:

(JSC::JSObject::hasInstance):
(JSC::objectPrivateFuncInstanceOf):

  • runtime/JSObject.h:
  • runtime/JSTypeInfo.h:

(JSC::TypeInfo::TypeInfo):
(JSC::TypeInfo::overridesHasInstance):

  • runtime/WriteBarrier.h:

(JSC::WriteBarrierBase<Unknown>::slot):

  • tests/es6.yaml:
  • tests/stress/instanceof-custom-hasinstancesymbol.js: Added.

(Constructor):
(value):
(instanceOf):
(body):

  • tests/stress/symbol-hasInstance.js: Added.

(Constructor):
(value):
(ObjectClass.Symbol.hasInstance):
(NumberClass.Symbol.hasInstance):

LayoutTests:

Fix tests to reflect the changes to instanceof in ES6.

Added a new regression test for bound functions in instanceof
as the perfomance on bound functions should, to some degree,
reflect the performance on C-API users.

  • js/Object-getOwnPropertyNames-expected.txt:
  • js/exception-for-nonobject-expected.txt:
  • js/exception-instanceof-expected.txt:
  • js/instance-of-immediates-expected.txt:
  • js/regress/instanceof-bound-expected.txt: Added.
  • js/regress/instanceof-bound.html: Added.
  • js/regress/script-tests/instanceof-bound.js: Added.

(Constructor):
(test):

  • js/script-tests/Object-getOwnPropertyNames.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r193766 r193974  
    10141014            break;
    10151015        }
    1016         case op_check_has_instance: {
     1016        case op_overrides_has_instance: {
    10171017            int r0 = (++it)->u.operand;
    10181018            int r1 = (++it)->u.operand;
    10191019            int r2 = (++it)->u.operand;
    1020             int offset = (++it)->u.operand;
    1021             printLocationAndOp(out, exec, location, it, "check_has_instance");
    1022             out.printf("%s, %s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), offset, location + offset);
     1020            printLocationAndOp(out, exec, location, it, "overrides_has_instance");
     1021            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
    10231022            break;
    10241023        }
     
    10291028            printLocationAndOp(out, exec, location, it, "instanceof");
    10301029            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
     1030            break;
     1031        }
     1032        case op_instanceof_custom: {
     1033            int r0 = (++it)->u.operand;
     1034            int r1 = (++it)->u.operand;
     1035            int r2 = (++it)->u.operand;
     1036            int r3 = (++it)->u.operand;
     1037            printLocationAndOp(out, exec, location, it, "instanceof_custom");
     1038            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
    10311039            break;
    10321040        }
Note: See TracChangeset for help on using the changeset viewer.