Ignore:
Timestamp:
Feb 21, 2021, 4:41:30 PM (4 years ago)
Author:
[email protected]
Message:

Implement the Top-level await proposal
https://bugs.webkit.org/show_bug.cgi?id=202484

Reviewed by Yusuke Suzuki.

JSTests:

  • test262/config.yaml:

Source/JavaScriptCore:

This patch adds support for the TLA proposal. The bulk of this patch is adding a couple of main parts.

1) converting the AbstractModuleRecord to contain many of same internal fields as JSGenerator so much of the async codegen can be shared.

2) having the link phase of the module loader record whether a module subgraph is async.
3) teaching the module loader that evaluating a module may require more than one vm entry and forwarding the awaited value as well as the resume mode to the VM.

One thing particularly interesting about this patch is that moduleEvaluation now *sometimes* (when a strongly connected subgraph is async) will return a promise. This happened to already be awaited when called from loadAndEvaluateModule (unnecessarily before) but now also needs to be handled by requestImportModule.

No new tests because every test I came up with was subsumed by tests already in test262.

  • API/JSAPIGlobalObject.h:
  • API/JSAPIGlobalObject.mm:

(JSC::JSAPIGlobalObject::moduleLoaderEvaluate):

(globalPrivate.newRegistryEntry):
(link):
(async requestImportModule):
(moduleEvaluation): Deleted.
(requestImportModule): Deleted.

  • bytecode/BytecodeGeneratorification.cpp:

(JSC::BytecodeGeneratorification::run):
(JSC::performGeneratorification):

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):

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

(JSC::computeUsesForBytecodeIndexImpl):

  • bytecode/UnlinkedModuleProgramCodeBlock.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitWillLeaveCallFrameDebugHook):
(JSC::BytecodeGenerator::emitGenericEnumeration):
(JSC::BytecodeGenerator::emitYieldPoint):
(JSC::BytecodeGenerator::emitYield):
(JSC::BytecodeGenerator::emitDelegateYield):
(JSC::BytecodeGenerator::emitGeneratorStateChange):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::generatorStateRegister):
(JSC::BytecodeGenerator::generatorValueRegister):
(JSC::BytecodeGenerator::generatorResumeModeRegister):
(JSC::BytecodeGenerator::generatorFrameRegister):

  • bytecompiler/NodesCodegen.cpp:

(JSC::abstractModuleRecordInternalFieldIndex):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getAbstractModuleRecordInternalField):
(JSC::FunctionNode::emitBytecode):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::executeModuleProgram):

  • interpreter/Interpreter.h:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createAwait):
(JSC::ASTBuilder::usesAwait):

  • parser/Nodes.cpp:

(JSC::ModuleProgramNode::ModuleProgramNode):

  • parser/Nodes.h:
  • parser/Parser.cpp:

(JSC::JSToken::dump const):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseAwaitExpression):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseUnaryExpression):

  • parser/ParserModes.h:
  • parser/ParserTokens.h:
  • runtime/AbstractModuleRecord.cpp:

(JSC::AbstractModuleRecord::finishCreation):
(JSC::AbstractModuleRecord::link):
(JSC::AbstractModuleRecord::evaluate):

  • runtime/AbstractModuleRecord.h:

(JSC::AbstractModuleRecord::initialValues):
(JSC::AbstractModuleRecord::internalField):
(JSC::AbstractModuleRecord::internalField const):

  • runtime/JSAsyncGenerator.h:
  • runtime/JSGenerator.h:
  • runtime/JSGlobalObject.h:
  • runtime/JSModuleLoader.cpp:

(JSC::JSModuleLoader::evaluate):
(JSC::JSModuleLoader::evaluateNonVirtual):
(JSC::JSC_DEFINE_HOST_FUNCTION):

  • runtime/JSModuleLoader.h:
  • runtime/JSModuleRecord.cpp:

(JSC::JSModuleRecord::link):
(JSC::JSModuleRecord::evaluate):

  • runtime/JSModuleRecord.h:
  • runtime/ModuleProgramExecutable.h:
  • runtime/OptionsList.h:
  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::dump const):

  • runtime/SymbolTable.h:
  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::linkImpl):

  • wasm/js/WebAssemblyModuleRecord.h:

Source/WebCore:

  • bindings/js/JSDOMGlobalObject.cpp:

(WebCore::JSDOMGlobalObject::moduleLoaderEvaluate):

  • bindings/js/JSDOMGlobalObject.h:
  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::evaluateModule):

  • bindings/js/ScriptController.h:
  • bindings/js/ScriptModuleLoader.cpp:

(WebCore::ScriptModuleLoader::evaluate):

  • bindings/js/ScriptModuleLoader.h:
  • workers/WorkerOrWorkletScriptController.cpp:

(WebCore::WorkerOrWorkletScriptController::evaluateModule):

  • workers/WorkerOrWorkletScriptController.h:
Location:
trunk/Source/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

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

    r273135 r273225  
    3232#include "BytecodeGenerator.h"
    3333
     34#include "AbstractModuleRecord.h"
    3435#include "BuiltinExecutables.h"
    3536#include "BuiltinNames.h"
     
    280281   
    281282
    282     if (isGeneratorOrAsyncFunctionBodyParseMode(m_codeBlock->parseMode()))
     283    if (m_isAsync)
    283284        performGeneratorification(*this, m_codeBlock.get(), m_writer, m_generatorFrameSymbolTable.get(), m_generatorFrameSymbolTableIndex);
    284285
     
    386387
    387388    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
     389        m_isAsync = true;
    388390        // Generator and AsyncFunction never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
    389391        needsArguments = false;
     
    435437
    436438    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
    437         m_generatorRegister = &m_parameters[1];
     439        m_generatorRegister = &m_parameters[static_cast<unsigned>(JSGenerator::Argument::Generator)];
    438440
    439441    allocateAndEmitScope();
     
    952954    };
    953955
     956    if (moduleProgramNode->usesAwait()) {
     957        m_isAsync = true;
     958        initializeNextParameter(); // |this|
     959        for (unsigned i = 0; i < JSGenerator::Argument::NumberOfArguments; ++i)
     960            initializeNextParameter();
     961        m_generatorRegister = &m_parameters[static_cast<unsigned>(AbstractModuleRecord::Argument::Generator)];
     962    }
     963
    954964    emitEnter();
    955965
     
    960970    m_calleeRegister.setIndex(CallFrameSlot::callee);
    961971
    962     m_codeBlock->setNumParameters(1); // Allocate space for "this"
     972    m_codeBlock->setNumParameters(static_cast<unsigned>(AbstractModuleRecord::Argument::NumberOfArguments) + 1); // Allocate space for "this" + async module arguments.
    963973
    964974    // Now declare all variables.
     
    984994    // We keep the symbol table in the constant pool.
    985995    RegisterID* constantSymbolTable = nullptr;
    986     if (shouldEmitTypeProfilerHooks())
     996    if (shouldEmitTypeProfilerHooks() || moduleProgramNode->usesAwait())
    987997        constantSymbolTable = addConstantValue(moduleEnvironmentSymbolTable);
    988998    else
    989999        constantSymbolTable = addConstantValue(moduleEnvironmentSymbolTable->cloneScopePart(m_vm));
     1000
     1001    if (moduleProgramNode->usesAwait()) {
     1002        m_generatorFrameSymbolTable.set(m_vm, moduleEnvironmentSymbolTable);
     1003        m_generatorFrameSymbolTableIndex = constantSymbolTable->index();
     1004        emitPutInternalField(generatorRegister(), static_cast<unsigned>(AbstractModuleRecord::Field::Frame), generatorFrameRegister());
     1005    }
    9901006
    9911007    pushTDZVariables(lexicalVariables, TDZCheckOptimization::Optimize, TDZRequirement::UnderTDZ);
     
    37303746void BytecodeGenerator::emitWillLeaveCallFrameDebugHook()
    37313747{
    3732     RELEASE_ASSERT(m_scopeNode->isFunctionNode());
    37333748    emitDebugHook(WillLeaveCallFrame, m_scopeNode->lastLine(), m_scopeNode->startOffset(), m_scopeNode->lineStartOffset());
    37343749}
     
    41814196    bool isForAwait = forLoopNode ? forLoopNode->isForAwait() : false;
    41824197    auto shouldEmitAwait = isForAwait ? EmitAwait::Yes : EmitAwait::No;
    4183     ASSERT(!isForAwait || isAsyncFunctionParseMode(parseMode()));
     4198    ASSERT(!isForAwait || (isAsyncFunctionParseMode(parseMode()) || isModuleParseMode(parseMode())));
    41844199
    41854200    RefPtr<RegisterID> subject = newTemporary();
     
    47414756        OpNop::emit<OpcodeSize::Narrow>(this);
    47424757#endif
    4743     OpYield::emit(this, generatorFrameRegister(), yieldPointIndex, argument);
     4758    OpYield::emit(this, yieldPointIndex, argument);
    47444759
    47454760    // Restore the try contexts, which start offset is updated to the merge point.
     
    47544769    Ref<Label> normalLabel = newLabel();
    47554770    RefPtr<RegisterID> condition = newTemporary();
    4756     emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
     4771    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::NormalMode))));
    47574772    emitJumpIfTrue(condition.get(), normalLabel.get());
    47584773
    47594774    Ref<Label> throwLabel = newLabel();
    4760     emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ThrowMode))));
     4775    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::ThrowMode))));
    47614776    emitJumpIfTrue(condition.get(), throwLabel.get());
    47624777    // Return.
     
    49424957                {
    49434958                    RefPtr<RegisterID> condition = newTemporary();
    4944                     emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
     4959                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::NormalMode))));
    49454960                    emitJumpIfTrue(condition.get(), normalLabel.get());
    49464961
    4947                     emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ReturnMode))));
     4962                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::ReturnMode))));
    49484963                    emitJumpIfTrue(condition.get(), returnLabel.get());
    49494964
     
    50495064void BytecodeGenerator::emitGeneratorStateChange(int32_t state)
    50505065{
     5066    // FIXME: It seems like this will create a lot of constants if there are many yield points. Maybe we should op_inc the old state. https://bugs.webkit.org/show_bug.cgi?id=222254
    50515067    RegisterID* completedState = emitLoad(nullptr, jsNumber(state));
    50525068    static_assert(static_cast<unsigned>(JSGenerator::Field::State) == static_cast<unsigned>(JSAsyncGenerator::Field::State));
    5053     emitPutInternalField(generatorRegister(), static_cast<unsigned>(JSGenerator::Field::State), completedState);
     5069    emitPutInternalField(generatorRegister(), isModuleParseMode(parseMode()) ? static_cast<unsigned>(AbstractModuleRecord::Field::State) : static_cast<unsigned>(JSGenerator::Field::State), completedState);
    50545070}
    50555071
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r273135 r273225  
    10591059        RegisterID* emitYield(RegisterID* argument, JSAsyncGenerator::AsyncGeneratorSuspendReason = JSAsyncGenerator::AsyncGeneratorSuspendReason::Yield);
    10601060        RegisterID* emitDelegateYield(RegisterID* argument, ThrowableExpressionData*);
    1061         RegisterID* generatorStateRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::State)]; }
    1062         RegisterID* generatorValueRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Value)]; }
    1063         RegisterID* generatorResumeModeRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::ResumeMode)]; }
    1064         RegisterID* generatorFrameRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Frame)]; }
     1061        RegisterID* generatorStateRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::Argument::State)]; }
     1062        RegisterID* generatorValueRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::Argument::Value)]; }
     1063        RegisterID* generatorResumeModeRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::Argument::ResumeMode)]; }
     1064        RegisterID* generatorFrameRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::Argument::Frame)]; }
    10651065
    10661066        CodeType codeType() const { return m_codeType; }
     
    13281328        Vector<TryContext> m_tryContextStack;
    13291329        unsigned m_yieldPoints { 0 };
     1330        bool m_isAsync { false };
    13301331
    13311332        Strong<SymbolTable> m_generatorFrameSymbolTable;
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r273135 r273225  
    2929#include "NodeConstructors.h"
    3030
     31#include "AbstractModuleRecord.h"
    3132#include "BuiltinNames.h"
    3233#include "BytecodeGenerator.h"
     
    13901391}
    13911392
     1393static AbstractModuleRecord::Field abstractModuleRecordInternalFieldIndex(BytecodeIntrinsicNode* node)
     1394{
     1395    ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
     1396    if (node->entry().emitter() == &BytecodeIntrinsicNode::emit_intrinsic_abstractModuleRecordFieldState)
     1397        return AbstractModuleRecord::Field::State;
     1398    RELEASE_ASSERT_NOT_REACHED();
     1399    return AbstractModuleRecord::Field::State;
     1400}
     1401
    13921402static JSArrayIterator::Field arrayIteratorInternalFieldIndex(BytecodeIntrinsicNode* node)
    13931403{
     
    14701480    unsigned index = static_cast<unsigned>(asyncGeneratorInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
    14711481    ASSERT(index < JSAsyncGenerator::numberOfInternalFields);
     1482    ASSERT(!node->m_next);
     1483
     1484    return generator.emitGetInternalField(generator.finalDestination(dst), base.get(), index);
     1485}
     1486
     1487RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getAbstractModuleRecordInternalField(BytecodeGenerator& generator, RegisterID* dst)
     1488{
     1489    ArgumentListNode* node = m_args->m_listNode;
     1490    RefPtr<RegisterID> base = generator.emitNode(node);
     1491    node = node->m_next;
     1492    RELEASE_ASSERT(node->m_expr->isBytecodeIntrinsicNode());
     1493    unsigned index = static_cast<unsigned>(abstractModuleRecordInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
     1494    ASSERT(index < AbstractModuleRecord::numberOfInternalFields);
    14721495    ASSERT(!node->m_next);
    14731496
     
    49414964        generator.move(args.argumentRegister(argumentCount++), generator.promiseRegister());
    49424965        generator.emitLoad(args.argumentRegister(argumentCount++), jsUndefined());
    4943         generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode)));
     4966        generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::NormalMode)));
    49444967        // JSTextPosition(int _line, int _offset, int _lineStartOffset)
    49454968        JSTextPosition divot(firstLine(), startOffset(), lineStartOffset());
     
    49584981        {
    49594982            RefPtr<RegisterID> condition = generator.newTemporary();
    4960             generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
     4983            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::NormalMode))));
    49614984            generator.emitJumpIfTrue(condition.get(), generatorBodyLabel.get());
    49624985
    49634986            Ref<Label> throwLabel = generator.newLabel();
    4964             generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ThrowMode))));
     4987            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::ResumeMode::ThrowMode))));
    49654988            generator.emitJumpIfTrue(condition.get(), throwLabel.get());
    49664989
Note: See TracChangeset for help on using the changeset viewer.