Ignore:
Timestamp:
May 22, 2021, 8:50:06 PM (4 years ago)
Author:
Ross Kirsling
Message:

Support Ergonomic Brand Checks proposal (#x in obj)
https://bugs.webkit.org/show_bug.cgi?id=221093

Reviewed by Caio Araujo Neponoceno de Lima.

JSTests:

  • stress/private-in.js: Added.
  • test262/config.yaml: Add feature flag.

Source/JavaScriptCore:

This patch implements the following Stage 3 proposal (behind a runtime option):
https://github.com/tc39/proposal-private-fields-in-in

Specifically, it extends the in keyword to allow the LHS to be a private name,
thereby allowing users to implement Array.isArray-esque brand checks for their own classes
*without* having to wrap a private member get in a try-catch.

For example:
`
class C {

#x;
static isC(obj) { return #x in obj; }

}
`

This is done by adding two new bytecode ops, HasPrivateName and HasPrivateBrand. For the moment,
these are implemented without fast paths, as we should do so for InByVal first and then have these follow suit.

  • bytecode/BytecodeList.rb:
  • bytecode/BytecodeUseDef.cpp:

(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitHasPrivateName):
(JSC::BytecodeGenerator::emitHasPrivateBrand):
(JSC::BytecodeGenerator::emitCheckPrivateBrand):

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

(JSC::InNode::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/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileHasPrivateName):
(JSC::DFG::SpeculativeJIT::compileHasPrivateBrand):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileHasPrivateName):
(JSC::FTL::DFG::LowerDFGToB3::compileHasPrivateBrand):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JITOperations.cpp:

(JSC::JSC_DEFINE_JIT_OPERATION):

  • jit/JITOperations.h:
  • llint/LowLevelInterpreter.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createPrivateIdentifierNode):

  • parser/NodeConstructors.h:

(JSC::PrivateIdentifierNode::PrivateIdentifierNode):

  • parser/Nodes.h:

(JSC::ExpressionNode::isPrivateIdentifier const):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseBinaryExpression):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createPrivateIdentifierNode):

  • parser/VariableEnvironment.h:
  • runtime/CommonSlowPaths.cpp:

(JSC::JSC_DEFINE_COMMON_SLOW_PATH):

  • runtime/CommonSlowPaths.h:
  • runtime/JSObject.h:
  • runtime/JSObjectInlines.h:

(JSC::JSObject::hasPrivateField):
(JSC::JSObject::hasPrivateBrand):
(JSC::JSObject::checkPrivateBrand):

  • runtime/OptionsList.h:
Location:
trunk/Source/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r276719 r277926  
    27252725}
    27262726
     2727RegisterID* BytecodeGenerator::emitHasPrivateName(RegisterID* dst, RegisterID* base, RegisterID* property)
     2728{
     2729    OpHasPrivateName::emit(this, dst, base, property);
     2730    return dst;
     2731}
     2732
    27272733RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
    27282734{
     
    27972803}
    27982804
     2805RegisterID* BytecodeGenerator::emitHasPrivateBrand(RegisterID* dst, RegisterID* base, RegisterID* brand, bool isStatic)
     2806{
     2807    if (isStatic) {
     2808        Ref<Label> isObjectLabel = newLabel();
     2809        emitJumpIfTrue(emitIsObject(newTemporary(), base), isObjectLabel.get());
     2810        emitThrowTypeError("Cannot access static private method or accessor of a non-Object");
     2811        emitLabel(isObjectLabel.get());
     2812        emitEqualityOp<OpStricteq>(dst, base, brand);
     2813    } else
     2814        OpHasPrivateBrand::emit(this, dst, base, brand);
     2815    return dst;
     2816}
     2817
    27992818void BytecodeGenerator::emitCheckPrivateBrand(RegisterID* base, RegisterID* brand, bool isStatic)
    28002819{
     
    28022821        Ref<Label> brandCheckOkLabel = newLabel();
    28032822        emitJumpIfTrue(emitEqualityOp<OpStricteq>(newTemporary(), base, brand), brandCheckOkLabel.get());
    2804         emitThrowTypeError("Cannot access static private method or acessor");
     2823        emitThrowTypeError("Cannot access static private method or accessor");
    28052824        emitLabel(brandCheckOkLabel.get());
    28062825        return;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r276384 r277926  
    841841        RegisterID* emitPrivateFieldPut(RegisterID* base, RegisterID* property, RegisterID* value);
    842842        RegisterID* emitGetPrivateName(RegisterID* dst, RegisterID* base, RegisterID* property);
     843        RegisterID* emitHasPrivateName(RegisterID* dst, RegisterID* base, RegisterID* property);
    843844
    844845        void emitCreatePrivateBrand(RegisterID* dst, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
     
    847848
    848849        RegisterID* emitGetPrivateBrand(RegisterID* dst, RegisterID* scope, bool isStatic);
     850        RegisterID* emitHasPrivateBrand(RegisterID* dst, RegisterID* base, RegisterID* brand, bool isStatic);
    849851        void emitCheckPrivateBrand(RegisterID* base, RegisterID* brand, bool isStatic);
    850852
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r275439 r277926  
    32073207RegisterID* InNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    32083208{
     3209    if (m_expr1->isPrivateIdentifier()) {
     3210        RefPtr<RegisterID> base = generator.emitNode(m_expr2);
     3211
     3212        auto identifier = static_cast<PrivateIdentifierNode*>(m_expr1)->value();
     3213        auto privateTraits = generator.getPrivateTraits(identifier);
     3214        Variable var = generator.variable(identifier);
     3215        RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
     3216
     3217        if (privateTraits.isField()) {
     3218            RefPtr<RegisterID> privateName = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound);
     3219            return generator.emitHasPrivateName(generator.finalDestination(dst, base.get()), base.get(), privateName.get());
     3220        }
     3221
     3222        ASSERT(privateTraits.isPrivateMethodOrAccessor());
     3223        RefPtr<RegisterID> privateBrand = generator.emitGetPrivateBrand(generator.newTemporary(), scope.get(), privateTraits.isStatic());
     3224        return generator.emitHasPrivateBrand(generator.finalDestination(dst, base.get()), base.get(), privateBrand.get(), privateTraits.isStatic());
     3225    }
     3226
    32093227    if (isNonIndexStringElement(*m_expr1)) {
    32103228        RefPtr<RegisterID> base = generator.emitNode(m_expr2);
Note: See TracChangeset for help on using the changeset viewer.