Ignore:
Timestamp:
Sep 23, 2020, 10:19:38 AM (5 years ago)
Author:
Caio Lima
Message:

[JSC][ESNext] Create a new opcode to handle private fields store/define
https://bugs.webkit.org/show_bug.cgi?id=213372

Reviewed by Yusuke Suzuki.

JSTests:

Adjusting tests that emit get_private_name to avoid execution in
FTL/DFG.

  • microbenchmarks/class-fields-private/polymorphic-put-private-field.js: Added.
  • microbenchmarks/class-fields-private/put-private-field.js: Added.
  • microbenchmarks/polymorphic-put-public-field.js: Added.
  • microbenchmarks/put-public-field.js: Added.
  • stress/dfg-put-private-name-check-barrier-insertion.js: Added.
  • stress/dfg-put-private-name-compiled-as-put-by-id-direct.js: Added.
  • stress/dfg-put-private-name-compiled-as-put-private-name-by-id.js: Added.
  • stress/put-private-name-by-id-set-do-not-add-structure-trasition.js: Added.
  • stress/put-private-name-check-structure-miss.js: Added.
  • stress/put-private-name-constant-folding-to-mult-put-by-offset.js: Added.
  • stress/put-private-name-constant-folding-to-put-by-offset.js: Added.
  • stress/put-private-name-generic.js: Added.
  • stress/put-private-name-invalid-define.js: Added.
  • stress/put-private-name-invalid-store.js: Added.
  • stress/put-private-name-invalidate-compiled-with-constant-symbol.js: Added.
  • stress/put-private-name-polymorphic-with-constant-symbol.js: Added.
  • stress/put-private-name-with-constant-symbol.js: Added.
  • stress/put-private-name-with-different-identifier.js: Added.

Source/JavaScriptCore:

This patch is adding a new opcode to handle private field storage.
Before this change, we were using put_by_val_direct and including
the information of PutKind into PutByValFlags. We initially decided
to use put_by_val_direct to take advantage of all IC mechanism already
implemented for this instruction, however the semantics of private field
is different enough to complicate the understanding of
put_by_val_direct.

The new instruction is called put_private_name and has as its operands
baseObject where the put is going to be placed, the property
that's going to be installed (it is always a private symbol of a
private field), the value we are going to store and the
PrivateFieldPutKind that can be Define or Set.
The difference of each PrivateFieldPutKind is the following:

  • Define: It defines a new private field. If this field is already

present, it throws a TypeError.

  • Set: It sets the value of a private field. If the field is not

present at the moment of set, it throws a TypeError.

This patch includes support of IC for all tiers. For DFG and FTL, we
are only emmiting IC when we are able to emit CheckConstant
for subscript identifier during Bytecode parsing. We are adding a new
DFG node called PutPrivateNameById that handles such cases when we
have constant identifiers.
We are also adding a new DFG node PutPrivateName that handles generic
case of put_private_name. The strategy used to compile
put_private_name is very similar with what we are using with
put_by_val[_direct]. We first try to compile it as [Multi]PutByOffset
using profiled information from LLInt and Baseline execution. If it
is not possible, we then emit PutPrivateName[ById] node. We get another
chance to transform PutPrivateNameById into PutByOffset if we can prove
its structure set at constant folding phase.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • bytecode/BytecodeList.rb:
  • bytecode/BytecodeUseDef.cpp:

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

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::propagateTransitions):
(JSC::CodeBlock::finalizeLLIntInlineCaches):

  • bytecode/Fits.h:
  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):

  • bytecode/PutByIdStatus.h:
  • bytecode/PutByValFlags.cpp: Removed.
  • bytecode/PutByValFlags.h: Removed.
  • bytecode/PutKind.h:

(): Deleted.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDirectPutByVal):
(JSC::BytecodeGenerator::emitDefinePrivateField):
(JSC::BytecodeGenerator::emitPrivateFieldPut):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handlePutPrivateNameById):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handlePutByVal):
(JSC::DFG::ecmaMode): Deleted.
(JSC::DFG::ecmaMode<OpPutByValDirect>): Deleted.

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::tryFoldAsPutByOffset):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToPutByOffset):
(JSC::DFG::Node::convertToMultiPutByOffset):
(JSC::DFG::Node::hasCacheableIdentifier):
(JSC::DFG::Node::hasPrivateFieldPutKind):
(JSC::DFG::Node::privateFieldPutKind):

  • dfg/DFGNodeType.h:
  • dfg/DFGOpInfo.h:

(JSC::DFG::OpInfo::OpInfo):

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compilePutPrivateName):
(JSC::DFG::SpeculativeJIT::compilePutPrivateNameById):
(JSC::DFG::SpeculativeJIT::compilePutByIdFlush):
(JSC::DFG::SpeculativeJIT::compilePutById):
(JSC::DFG::SpeculativeJIT::compilePutByIdDirect):
(JSC::DFG::SpeculativeJIT::cachedPutById):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStoreBarrierInsertionPhase.cpp:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compilePutPrivateNameById):
(JSC::FTL::DFG::LowerDFGToB3::compilePutPrivateName):
(JSC::FTL::DFG::LowerDFGToB3::cachedPutById):
(JSC::FTL::DFG::LowerDFGToB3::compilePutById):

  • generator/DSL.rb:
  • jit/JIT.cpp:

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

  • jit/JIT.h:

(JSC::ByValCompilationInfo::ByValCompilationInfo):

  • jit/JITInlineCacheGenerator.cpp:

(JSC::JITPutByIdGenerator::JITPutByIdGenerator):
(JSC::JITPutByIdGenerator::slowPathFunction):

  • jit/JITInlineCacheGenerator.h:

(JSC::JITPutByIdGenerator::JITPutByIdGenerator):

  • jit/JITInlines.h:

(JSC::JIT::ecmaMode<OpPutPrivateName>):
(JSC::JIT::ecmaMode<OpPutByValDirect>): Deleted.
(JSC::JIT::privateFieldAccessKind): Deleted.
(JSC::JIT::privateFieldAccessKind<OpPutByValDirect>): Deleted.

  • jit/JITOperations.cpp:

(JSC::setPrivateField):
(JSC::putPrivateField): Deleted.

  • jit/JITOperations.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitPutByValWithCachedId):
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::emit_op_put_private_name):
(JSC::JIT::emitSlow_op_put_private_name):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emitPutPrivateNameWithCachedId):
(JSC::JIT::privateCompilePutPrivateNameWithCachedId):
(JSC::JIT::privateCompilePutByValWithCachedId):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_put_private_name):
(JSC::JIT::emitSlow_op_put_private_name):
(JSC::JIT::emit_op_put_by_id):

  • jit/Repatch.cpp:

(JSC::appropriateGenericPutByIdFunction):
(JSC::appropriateOptimizingPutByIdFunction):
(JSC::tryCachePutByID):
(JSC::resetPutByID):

  • llint/LLIntOffsetsExtractor.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSObject.h:
  • runtime/JSObjectInlines.h:

(JSC::JSObject::setPrivateField):
(JSC::JSObject::putPrivateField): Deleted.

  • runtime/PrivateFieldPutKind.cpp: Added.

(JSC::PrivateFieldPutKind::dump const):

  • runtime/PrivateFieldPutKind.h: Added.

(JSC::PrivateFieldPutKind::fromByte):
(JSC::PrivateFieldPutKind::none):
(JSC::PrivateFieldPutKind::set):
(JSC::PrivateFieldPutKind::define):
(JSC::PrivateFieldPutKind::isNone const):
(JSC::PrivateFieldPutKind::isSet const):
(JSC::PrivateFieldPutKind::isDefine const):
(JSC::PrivateFieldPutKind::value const):
(JSC::PrivateFieldPutKind::PrivateFieldPutKind):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r266969 r267489  
    536536static auto appropriateGenericPutByIdFunction(const PutPropertySlot &slot, PutKind putKind) -> decltype(&operationPutByIdDirectStrict)
    537537{
    538     if (slot.isStrictMode()) {
    539         if (putKind == Direct)
     538    switch (putKind) {
     539    case PutKind::NotDirect:
     540        if (slot.isStrictMode())
     541            return operationPutByIdStrict;
     542        return operationPutByIdNonStrict;
     543    case PutKind::Direct:
     544        if (slot.isStrictMode())
    540545            return operationPutByIdDirectStrict;
    541         if (putKind == DirectPrivateFieldCreate)
    542             return operationPutByIdDefinePrivateFieldStrict;
    543         if (putKind == DirectPrivateFieldPut)
    544             return operationPutByIdPutPrivateFieldStrict;
    545         return operationPutByIdStrict;
    546     }
    547     if (putKind == Direct)
    548546        return operationPutByIdDirectNonStrict;
    549     return operationPutByIdNonStrict;
     547    case PutKind::DirectPrivateFieldDefine:
     548        ASSERT(slot.isStrictMode());
     549        return operationPutByIdDefinePrivateFieldStrict;
     550    case PutKind::DirectPrivateFieldSet:
     551        ASSERT(slot.isStrictMode());
     552        return operationPutByIdSetPrivateFieldStrict;
     553    }
     554    // Make win port compiler happy
     555    RELEASE_ASSERT_NOT_REACHED();
     556    return nullptr;
    550557}
    551558
    552559static auto appropriateOptimizingPutByIdFunction(const PutPropertySlot &slot, PutKind putKind) -> decltype(&operationPutByIdDirectStrictOptimize)
    553560{
    554     if (slot.isStrictMode()) {
    555         if (putKind == Direct)
     561    switch (putKind) {
     562    case PutKind::NotDirect:
     563        if (slot.isStrictMode())
     564            return operationPutByIdStrictOptimize;
     565        return operationPutByIdNonStrictOptimize;
     566    case PutKind::Direct:
     567        if (slot.isStrictMode())
    556568            return operationPutByIdDirectStrictOptimize;
    557         if (putKind == DirectPrivateFieldCreate)
    558             return operationPutByIdDefinePrivateFieldStrictOptimize;
    559         if (putKind == DirectPrivateFieldPut)
    560             return operationPutByIdPutPrivateFieldStrictOptimize;
    561         return operationPutByIdStrictOptimize;
    562     }
    563     if (putKind == Direct)
    564569        return operationPutByIdDirectNonStrictOptimize;
    565     return operationPutByIdNonStrictOptimize;
     570    case PutKind::DirectPrivateFieldDefine:
     571        ASSERT(slot.isStrictMode());
     572        return operationPutByIdDefinePrivateFieldStrictOptimize;
     573    case PutKind::DirectPrivateFieldSet:
     574        ASSERT(slot.isStrictMode());
     575        return operationPutByIdSetPrivateFieldStrictOptimize;
     576    }
     577    // Make win port compiler happy
     578    RELEASE_ASSERT_NOT_REACHED();
     579    return nullptr;
    566580}
    567581
     
    609623                return GiveUpOnCache;
    610624        }
     625
     626        if (isProxy && (putKind == PutKind::DirectPrivateFieldSet || putKind == PutKind::DirectPrivateFieldDefine))
     627            return GiveUpOnCache;
    611628
    612629        std::unique_ptr<AccessCase> newCase;
     
    670687                std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain;
    671688                ObjectPropertyConditionSet conditionSet;
    672                 if (putKind == NotDirect) {
    673                     ASSERT(putKind != DirectPrivateFieldPut && putKind != DirectPrivateFieldCreate);
     689                if (putKind == PutKind::NotDirect) {
    674690                    auto cacheStatus = prepareChainForCaching(globalObject, baseCell, nullptr);
    675691                    if (!cacheStatus)
     
    689705                }
    690706
    691                 if (putKind == DirectPrivateFieldCreate) {
     707                if (putKind == PutKind::DirectPrivateFieldDefine) {
    692708                    ASSERT(ident.isPrivateName());
    693709                    conditionSet = generateConditionsForPropertyMiss(vm, codeBlock, globalObject, newStructure, ident.impl());
     
    15221538    else if (unoptimizedFunction == operationPutByIdDirectStrict || unoptimizedFunction == operationPutByIdDirectStrictOptimize)
    15231539        optimizedFunction = operationPutByIdDirectStrictOptimize;
    1524     else if (unoptimizedFunction == operationPutByIdPutPrivateFieldStrict || unoptimizedFunction == operationPutByIdPutPrivateFieldStrictOptimize)
    1525         optimizedFunction = operationPutByIdPutPrivateFieldStrictOptimize;
     1540    else if (unoptimizedFunction == operationPutByIdSetPrivateFieldStrict || unoptimizedFunction == operationPutByIdSetPrivateFieldStrictOptimize)
     1541        optimizedFunction = operationPutByIdSetPrivateFieldStrictOptimize;
    15261542    else if (unoptimizedFunction == operationPutByIdDefinePrivateFieldStrict || unoptimizedFunction == operationPutByIdDefinePrivateFieldStrictOptimize)
    15271543        optimizedFunction = operationPutByIdDefinePrivateFieldStrictOptimize;
Note: See TracChangeset for help on using the changeset viewer.