Ignore:
Timestamp:
Nov 4, 2019, 6:52:02 PM (6 years ago)
Author:
[email protected]
Message:

[JSC] Introduce LinkTimeConstant mechanism
https://bugs.webkit.org/show_bug.cgi?id=153792

Reviewed by Saam Barati.

Source/JavaScriptCore:

We are using private-name-variables of JSGlobalObject as a way to access to constants that are materialized per JSGlobalObject.
And we also have special-pointers and old link-time-constants to access to per JSGlobalObject constants.
We have bytecode intrinsic constants, but it is only available for per VM values.

However, these ones have multiple problems.

  1. private-name-variables is too costly. We need to have an entry in JSGlobalObject's variable, this makes SymbolTable of JSGlobalObject large. It also requires WatchpointSet to make it constant-fold in DFG. And accessing these variables from builtin JS takes op_resolve_scope and op_get_from_scope, enlarging bytecode and slow in interpreter and baseline compared to just getting them as a constant register.
  2. special-pointers are tailored to op_jne_ptr opcode, and not usable in the other bytecode since this is completely separate from VirtualRegister.
  3. Old link-time-constants implementation is putting array of all link-time-constants on each UnlinkedCodeBlock, even if it is not used. If you increase # of link-time-constant, it increases sizeof(UnlinkedCodeBlock).

In this patch, we introduce a new link-time-constant mechanism and remove the above old ones mostly. (private-name-variables still exists for WebCore and @assert).
We manage link-time-constants in BytecodeIntrinsicRegistry, and emit Int32:LinkTimeConstantID constant when generating an UnlinkedCodeBlock. Later, this constant
is alternated to an actual value when we link UnlinkedCodeBlock to CodeBlock with specific JSGlobalObject. private-name-variables accesses are now converted to
constant register so that it is very efficiently accessed and it reduces memory used for SymbolTable and WatchpointSet. op_jne_ptr takes link-time-constant
VirtualRegisters instead of special-pointers, so that we can remove special-pointers mechanism. We also replace old link-time-constants with new one, which reduces
sizeof(UnlinkedCodeBlock).

Furthermore, new link-time-constant supports lazy initialization by using LazyProperty in JSGlobalObject. This allows us to lazily generate many internal functions
that are previously initialized eagerly. This reduces # of allocated JSFunction significantly when initializing JSGlobalObject.

This patch also manually adds 256 to MarkedSpace's size-class. We empirically know that adding 256 here makes sequence of size-class better for memory consumption.
But this was achieved by adding sizeof(UnlinkedFunctionCodeBlock). Now sizeof(UnlinkedFunctionCodeBlock) is changed by this patch, and this patch unintentionally
breaks that sequence. We should explicitly add 256 instead of adding sizeof(UnlinkedFunctionCodeBlock) adhocly.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Scripts/wkbuiltins/builtins_generate_combined_header.py:

(generate_section_for_global_private_code_name_macro):

  • Sources.txt:
  • builtins/BuiltinNames.h:
  • builtins/PromiseConstructor.js:

(nakedConstructor.Promise):
(nakedConstructor.InternalPromise):
(nakedConstructor.Promise.reject): Deleted.
(nakedConstructor.InternalPromise.reject): Deleted.

  • bytecode/BytecodeDumper.cpp:

(JSC::CodeBlockBytecodeDumper<Block>::dumpConstants):

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
(JSC::BytecodeIntrinsicRegistry::lookup const):

  • bytecode/BytecodeIntrinsicRegistry.h:

(JSC::BytecodeIntrinsicRegistry::Entry::Entry):
(JSC::BytecodeIntrinsicRegistry::Entry::type const):
(JSC::BytecodeIntrinsicRegistry::Entry::linkTimeConstant const):
(JSC::BytecodeIntrinsicRegistry::Entry::emitter const):

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

(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::setConstantRegisters):

  • bytecode/Fits.h:
  • bytecode/LinkTimeConstant.cpp: Renamed from Source/JavaScriptCore/bytecode/SpecialPointer.h.

(WTF::printInternal):

  • bytecode/LinkTimeConstant.h: Added.
  • bytecode/SpecialPointer.cpp: Removed.
  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::addConstant):
(JSC::UnlinkedCodeBlock::registerIndexForLinkTimeConstant): Deleted.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitJumpIfNotFunctionCall):
(JSC::BytecodeGenerator::emitJumpIfNotFunctionApply):
(JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
(JSC::BytecodeGenerator::emitCallDefineProperty):
(JSC::BytecodeGenerator::emitGetAsyncIterator):

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

(JSC::ImportNode::emitBytecode):
(JSC::BytecodeIntrinsicNode::emitBytecode):
(JSC::promiseInternalFieldIndex):
(JSC::generatorInternalFieldIndex):
(JSC::asyncGeneratorInternalFieldIndex):
(JSC::FunctionNode::emitBytecode):
(JSC::ObjectPatternNode::bindValue const):
(JSC::ObjectSpreadExpressionNode::emitBytecode):

  • dfg/DFGByteCodeParser.cpp:

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

  • heap/MarkedSpace.cpp:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_jneq_ptr):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_jneq_ptr):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createResolve):
(JSC::ASTBuilder::makeFunctionCallNode):

  • parser/NodeConstructors.h:

(JSC::BytecodeIntrinsicNode::BytecodeIntrinsicNode):

  • parser/Nodes.h:
  • runtime/CachedTypes.cpp:

(JSC::CachedCodeBlock<CodeBlockType>::decode const):
(JSC::CachedCodeBlock<CodeBlockType>::encode):

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

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

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::linkTimeConstant const):
(JSC::JSGlobalObject::callFunction const): Deleted.
(JSC::JSGlobalObject::applyFunction const): Deleted.
(JSC::JSGlobalObject::throwTypeErrorFunction const): Deleted.
(JSC::JSGlobalObject::newPromiseCapabilityFunction const): Deleted.
(JSC::JSGlobalObject::resolvePromiseFunction const): Deleted.
(JSC::JSGlobalObject::rejectPromiseFunction const): Deleted.
(JSC::JSGlobalObject::promiseProtoThenFunction const): Deleted.
(JSC::JSGlobalObject::regExpProtoExecFunction const): Deleted.
(JSC::JSGlobalObject::regExpProtoGlobalGetter const): Deleted.
(JSC::JSGlobalObject::regExpProtoUnicodeGetter const): Deleted.
(JSC::JSGlobalObject::actualPointerFor): Deleted.
(JSC::JSGlobalObject::jsCellForLinkTimeConstant): Deleted.

  • runtime/JSGlobalObjectInlines.h:

(JSC::JSGlobalObject::throwTypeErrorFunction const):
(JSC::JSGlobalObject::newPromiseCapabilityFunction const):
(JSC::JSGlobalObject::resolvePromiseFunction const):
(JSC::JSGlobalObject::rejectPromiseFunction const):
(JSC::JSGlobalObject::promiseProtoThenFunction const):
(JSC::JSGlobalObject::regExpProtoExecFunction const):
(JSC::JSGlobalObject::regExpProtoGlobalGetter const):
(JSC::JSGlobalObject::regExpProtoUnicodeGetter const):

LayoutTests:

  • inspector/debugger/tail-deleted-frames/tail-deleted-frames-this-value-expected.txt:
File:
1 edited

Legend:

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

    r252021 r252032  
    212212RegisterID* ImportNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    213213{
    214     RefPtr<RegisterID> importModule = generator.emitGetGlobalPrivate(generator.newTemporary(), generator.propertyNames().builtinNames().importModulePrivateName());
     214    RefPtr<RegisterID> importModule = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::importModule);
    215215    CallArguments arguments(generator, nullptr, 1);
    216216    generator.emitLoad(arguments.thisRegister(), jsUndefined());
     
    986986RegisterID* BytecodeIntrinsicNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    987987{
    988     return (this->*m_emitter)(generator, dst);
     988    if (m_entry.type() == BytecodeIntrinsicRegistry::Type::Emitter)
     989        return (this->*m_entry.emitter())(generator, dst);
     990    if (dst == generator.ignoredResult())
     991        return nullptr;
     992    return generator.moveLinkTimeConstant(dst, m_entry.linkTimeConstant());
    989993}
    990994
     
    10141018static JSPromise::Field promiseInternalFieldIndex(BytecodeIntrinsicNode* node)
    10151019{
    1016     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_promiseFieldFlags)
     1020    ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
     1021    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_promiseFieldFlags)
    10171022        return JSPromise::Field::Flags;
    1018     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_promiseFieldReactionsOrResult)
     1023    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_promiseFieldReactionsOrResult)
    10191024        return JSPromise::Field::ReactionsOrResult;
    10201025    RELEASE_ASSERT_NOT_REACHED();
     
    10241029static JSGenerator::Field generatorInternalFieldIndex(BytecodeIntrinsicNode* node)
    10251030{
    1026     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldState)
     1031    ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
     1032    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldState)
    10271033        return JSGenerator::Field::State;
    1028     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldNext)
     1034    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldNext)
    10291035        return JSGenerator::Field::Next;
    1030     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldThis)
     1036    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldThis)
    10311037        return JSGenerator::Field::This;
    1032     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldFrame)
     1038    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldFrame)
    10331039        return JSGenerator::Field::Frame;
    10341040    RELEASE_ASSERT_NOT_REACHED();
     
    10381044static JSAsyncGenerator::Field asyncGeneratorInternalFieldIndex(BytecodeIntrinsicNode* node)
    10391045{
    1040     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldState)
     1046    ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
     1047    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldState)
    10411048        return JSAsyncGenerator::Field::State;
    1042     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldNext)
     1049    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldNext)
    10431050        return JSAsyncGenerator::Field::Next;
    1044     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldThis)
     1051    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldThis)
    10451052        return JSAsyncGenerator::Field::This;
    1046     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldFrame)
     1053    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldFrame)
    10471054        return JSAsyncGenerator::Field::Frame;
    1048     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldSuspendReason)
     1055    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldSuspendReason)
    10491056        return JSAsyncGenerator::Field::SuspendReason;
    1050     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldQueueFirst)
     1057    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldQueueFirst)
    10511058        return JSAsyncGenerator::Field::QueueFirst;
    1052     if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldQueueLast)
     1059    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_asyncGeneratorFieldQueueLast)
    10531060        return JSAsyncGenerator::Field::QueueLast;
    10541061    RELEASE_ASSERT_NOT_REACHED();
     
    40974104
    40984105        // load and call @asyncFunctionResume
    4099         auto var = generator.variable(generator.propertyNames().builtinNames().asyncFunctionResumePrivateName());
    4100         RefPtr<RegisterID> scope = generator.newTemporary();
    4101         generator.move(scope.get(), generator.emitResolveScope(scope.get(), var));
    4102         RefPtr<RegisterID> asyncFunctionResume = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     4106        RefPtr<RegisterID> asyncFunctionResume = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::asyncFunctionResume);
    41034107
    41044108        CallArguments args(generator, nullptr, 4);
     
    45794583    RefPtr<RegisterID> addMethod;
    45804584    if (m_containsRestElement && m_containsComputedProperty) {
    4581         auto var = generator.variable(generator.propertyNames().builtinNames().SetPrivateName());
    4582 
    4583         RefPtr<RegisterID> scope = generator.newTemporary();
    4584         generator.move(scope.get(), generator.emitResolveScope(scope.get(), var));
    4585         RefPtr<RegisterID> setConstructor = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     4585        RefPtr<RegisterID> setConstructor = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::Set);
    45864586
    45874587        CallArguments args(generator, nullptr, 0);
     
    46344634           
    46354635            // load and call @copyDataProperties
    4636             auto var = generator.variable(generator.propertyNames().builtinNames().copyDataPropertiesPrivateName());
    4637            
    4638             RefPtr<RegisterID> scope = generator.newTemporary();
    4639             generator.move(scope.get(), generator.emitResolveScope(scope.get(), var));
    4640             RefPtr<RegisterID> copyDataProperties = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     4636            RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties);
    46414637           
    46424638            CallArguments args(generator, nullptr, 3);
     
    48114807   
    48124808    // load and call @copyDataPropertiesNoExclusions
    4813     auto var = generator.variable(generator.propertyNames().builtinNames().copyDataPropertiesNoExclusionsPrivateName());
    4814    
    4815     RefPtr<RegisterID> scope = generator.newTemporary();
    4816     generator.move(scope.get(), generator.emitResolveScope(scope.get(), var));
    4817     RefPtr<RegisterID> copyDataProperties = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     4809    RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataPropertiesNoExclusions);
    48184810   
    48194811    CallArguments args(generator, nullptr, 2);
Note: See TracChangeset for help on using the changeset viewer.