Skip to content

Commit

Permalink
Remove unnecessary startup yield
Browse files Browse the repository at this point in the history
- Extra yield inserted at the top of Generator functions
- so Params with side effects can be executed upon function call
- then stop at the yield untill .next() is used
- in cases where there are no params with side effets his is not needed
- use a condition to only do it when needed - saves several extra ops
- Had to update TTD code for this (it expected all Gens to have state)
- AsyncGenerator parameters needed copying to heap on call
  previously this was done when executing until the startup yield
  • Loading branch information
rhuanjl committed Mar 23, 2021
1 parent c86df3f commit 72c05da
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 9 deletions.
5 changes: 4 additions & 1 deletion lib/Runtime/Base/FunctionInfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
namespace Js
Expand Down Expand Up @@ -42,7 +43,8 @@ namespace Js
Method = 0x400000, // The function is a method
ComputedName = 0x800000,
ActiveScript = 0x1000000,
HomeObj = 0x2000000
HomeObj = 0x2000000,
GeneratorWithComplexParams = 0x8000000 // Generator function with non-simple params needs startup yield
};
FunctionInfo(JavascriptMethod entryPoint, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = nullptr);
FunctionInfo(JavascriptMethod entryPoint, _no_write_barrier_tag, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = nullptr);
Expand Down Expand Up @@ -136,6 +138,7 @@ namespace Js
bool GetBaseConstructorKind() const { return (attributes & Attributes::BaseConstructorKind) != 0; }
bool IsActiveScript() const { return ((this->attributes & Attributes::ActiveScript) != 0); }
void SetIsActiveScript() { attributes = (Attributes)(attributes | Attributes::ActiveScript); }
bool GetGeneratorWithComplexParams() {return (attributes & Attributes::GeneratorWithComplexParams) != 0; }
protected:
FieldNoBarrier(JavascriptMethod) originalEntryPoint;
FieldWithBarrier(FunctionProxy *) functionBodyImpl; // Implementation of the function- null if the function doesn't have a body
Expand Down
7 changes: 3 additions & 4 deletions lib/Runtime/ByteCode/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3023,10 +3023,9 @@ void ByteCodeGenerator::EmitOneFunction(ParseNodeFnc *pnodeFnc)
}

// If the function has non simple parameter list, the params needs to be evaluated when the generator object is created
// (that is when the function is called). This yield opcode is to mark the begining of the function body.
// TODO: Inserting a yield should have almost no impact on perf as it is a direct return from the function. But this needs
// to be verified. Ideally if the function has simple parameter list then we can avoid inserting the opcode and the additional call.
if (pnodeFnc->IsGenerator())
// (that is when the function is called). So insert an extra yield we can execute up to, to do this.
// In a Module we execute until this yield to hoist functions accross modules.
if (pnodeFnc->IsGenerator() && (pnodeFnc->HasNonSimpleParameterList() || pnodeFnc->IsModule()))
{
EmitStartupYield(this, funcInfo);
}
Expand Down
8 changes: 7 additions & 1 deletion lib/Runtime/ByteCode/ByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeByteCodePch.h"
Expand Down Expand Up @@ -1240,7 +1241,8 @@ static const Js::FunctionInfo::Attributes StableFunctionInfoAttributesMask = (Js
Js::FunctionInfo::Attributes::Generator |
Js::FunctionInfo::Attributes::Module |
Js::FunctionInfo::Attributes::ComputedName |
Js::FunctionInfo::Attributes::HomeObj
Js::FunctionInfo::Attributes::HomeObj |
Js::FunctionInfo::Attributes::GeneratorWithComplexParams
);

static Js::FunctionInfo::Attributes GetFunctionInfoAttributes(ParseNodeFnc * pnodeFnc)
Expand Down Expand Up @@ -1289,6 +1291,10 @@ static Js::FunctionInfo::Attributes GetFunctionInfoAttributes(ParseNodeFnc * pno
if (pnodeFnc->IsGenerator())
{
attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::Generator);
if (pnodeFnc->HasNonSimpleParameterList())
{
attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::GeneratorWithComplexParams);
}
}
if (pnodeFnc->IsAccessor())
{
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Debug/TTSnapObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2324,9 +2324,9 @@ namespace TTD
}
}

generator->SetFrameSlots(generatorInfo->frame_slotCount, frameSlotArray);
if (generatorInfo->byteCodeReader_offset > 0)
{
generator->SetFrameSlots(generatorInfo->frame_slotCount, frameSlotArray);
frame->InitializeClosures();
frame->GetReader()->SetCurrentOffset(generatorInfo->byteCodeReader_offset);
}
Expand Down
16 changes: 14 additions & 2 deletions lib/Runtime/Library/JavascriptAsyncGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,25 @@ JavascriptAsyncGenerator* JavascriptAsyncGenerator::New(
Arguments& args,
ScriptFunction* scriptFunction)
{
// InterpreterStackFrame takes a pointer to the args, so copy them to the recycler
// heap and use that buffer for the asyncgenerator's InterpreterStackFrame
Field(Var)* argValuesCopy = nullptr;

if (args.Info.Count > 0)
{
argValuesCopy = RecyclerNewArray(recycler, Field(Var), args.Info.Count);
CopyArray(argValuesCopy, args.Info.Count, args.Values, args.Info.Count);
}

Arguments heapArgs(args.Info, unsafe_write_barrier_cast<Var*>(argValuesCopy));

auto* requestQueue = RecyclerNew(recycler, JavascriptAsyncGenerator::RequestQueue, recycler);

JavascriptAsyncGenerator* generator = RecyclerNew(
JavascriptAsyncGenerator* generator = RecyclerNewFinalized(
recycler,
JavascriptAsyncGenerator,
generatorType,
args,
heapArgs,
scriptFunction,
requestQueue);

Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/Library/JavascriptAsyncGeneratorFunction.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
Expand Down Expand Up @@ -55,6 +56,7 @@ Var JavascriptAsyncGeneratorFunction::EntryAsyncGeneratorFunctionImplementation(
auto* generator = library->CreateAsyncGenerator(args, scriptFn, prototype);

// Run the generator to execute until the beginning of the body
if (scriptFn->GetFunctionInfo()->GetGeneratorWithComplexParams())
BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
{
generator->CallGenerator(library->GetUndefined(), ResumeYieldKind::Normal);
Expand Down
3 changes: 3 additions & 0 deletions lib/Runtime/Library/JavascriptGeneratorFunction.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
Expand Down Expand Up @@ -120,6 +121,8 @@ using namespace Js;
prototype);

// Call a next on the generator to execute till the beginning of the body
FunctionInfo* funcInfo = generatorFunction->scriptFunction->GetFunctionInfo();
if (funcInfo->GetGeneratorWithComplexParams() || funcInfo->IsModule())
BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
{
generator->CallGenerator(library->GetUndefined(), ResumeYieldKind::Normal);
Expand Down

0 comments on commit 72c05da

Please sign in to comment.