Skip to content

Commit

Permalink
[MERGE #6385 @pleath] ChakraCore Servicing Update for 2020.03B
Browse files Browse the repository at this point in the history
  • Loading branch information
pleath committed Mar 10, 2020
2 parents 42485b9 + 48f74e6 commit fdf0aeb
Show file tree
Hide file tree
Showing 27 changed files with 29,116 additions and 29,059 deletions.
2 changes: 1 addition & 1 deletion lib/Backend/BackwardPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5891,7 +5891,7 @@ BackwardPass::InsertTypeTransitionsAtPotentialKills()
// This is the sym we're tracking. No aliasing to worry about.
return false;
}
if (propertySymOpnd->IsMono() && data->GetInitialType() != propertySymOpnd->GetType())
if (propertySymOpnd->NeedsMonoCheck() && data->GetInitialType() != propertySymOpnd->GetType())
{
// Type mismatch in a monomorphic case -- no aliasing.
return false;
Expand Down
7 changes: 6 additions & 1 deletion lib/Backend/GlobOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2903,7 +2903,12 @@ GlobOpt::OptTagChecks(IR::Instr *instr)
// the byteCodeUse fields...
TrackByteCodeUsesForInstrAddedInOptInstr(bailOutInstr, [&]()
{
TryHoistInvariant(bailOutInstr, this->currentBlock, nullptr, value, nullptr, true, false, false, IR::BailOutOnTaggedValue);
if (TryHoistInvariant(bailOutInstr, this->currentBlock, nullptr, value, nullptr, true, false, false, IR::BailOutOnTaggedValue))
{
Value* landingPadValue = this->currentBlock->loop->landingPad->globOptData.FindValue(stackSym);
ValueType newLandingPadValueType = landingPadValue->GetValueInfo()->Type().SetCanBeTaggedValue(false);
ChangeValueType(nullptr, landingPadValue, newLandingPadValueType, false);
}
});
}
if (symOpnd)
Expand Down
21 changes: 18 additions & 3 deletions lib/Backend/GlobOptArrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ void GlobOpt::ArraySrcOpt::CheckLoops()
if (doArrayChecks)
{
hoistChecksOutOfLoop = loop;

// If BailOnNotObject isn't hoisted, the value may still be tagged in the landing pad
if (baseValueInLoopLandingPad->GetValueInfo()->Type().CanBeTaggedValue())
{
baseValueType = baseValueType.SetCanBeTaggedValue(true);
baseOpnd->SetValueType(baseValueType);
}
}

if (isLikelyJsArray && loopKills.KillsArrayHeadSegments())
Expand Down Expand Up @@ -1704,9 +1711,7 @@ void GlobOpt::ArraySrcOpt::Optimize()

baseOpnd->SetValueType(baseValueType);

if (!baseValueType.IsLikelyAnyOptimizedArray() ||
!globOpt->DoArrayCheckHoist(baseValueType, globOpt->currentBlock->loop, instr) ||
(baseOwnerIndir && !globOpt->ShouldExpectConventionalArrayIndexValue(baseOwnerIndir)))
if (!baseValueType.IsLikelyAnyOptimizedArray())
{
return;
}
Expand All @@ -1721,6 +1726,16 @@ void GlobOpt::ArraySrcOpt::Optimize()
return;
}

if (!globOpt->DoArrayCheckHoist(baseValueType, globOpt->currentBlock->loop, instr) ||
(baseOwnerIndir && !globOpt->ShouldExpectConventionalArrayIndexValue(baseOwnerIndir)))
{
if (!globOpt->IsLoopPrePass() && baseValueType.IsAnyOptimizedArray())
{
globOpt->ProcessNoImplicitCallArrayUses(baseOpnd, nullptr, instr, isLikelyJsArray, isLoad || isStore || instr->m_opcode == Js::OpCode::IsIn);
}
return;
}

isLikelyVirtualTypedArray = baseValueType.IsLikelyOptimizedVirtualTypedArray();
Assert(!(isLikelyJsArray && isLikelyVirtualTypedArray));

Expand Down
26 changes: 13 additions & 13 deletions lib/Backend/GlobOptFields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,19 +1123,6 @@ GlobOpt::ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd
Assert(opnd->IsTypeCheckSeqCandidate());
Assert(opnd->HasObjectTypeSym());

if (opnd->HasTypeMismatch())
{
if (emitsTypeCheckOut != nullptr)
{
*emitsTypeCheckOut = false;
}
if (changesTypeValueOut != nullptr)
{
*changesTypeValueOut = false;
}
return false;
}

bool isStore = opnd == instr->GetDst();
bool isTypeDead = opnd->IsTypeDead();
bool consumeType = makeChanges && !IsLoopPrePass();
Expand Down Expand Up @@ -1175,6 +1162,19 @@ GlobOpt::ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd
opnd->SetTypeAvailable(true);
}

if (opnd->HasTypeMismatch())
{
if (emitsTypeCheckOut != nullptr)
{
*emitsTypeCheckOut = false;
}
if (changesTypeValueOut != nullptr)
{
*changesTypeValueOut = false;
}
return false;
}

bool doEquivTypeCheck = opnd->HasEquivalentTypeSet() && !opnd->NeedsMonoCheck();
if (!doEquivTypeCheck)
{
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/IRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,10 @@ IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::Re
this->AddInstr(instr, offset);
return;
}
case Js::OpCode::InitConst:
// Don't use InitConst in the JIT, as some dataflow tracking is missing, and we don't currently optimize for it.
newOpcode = Js::OpCode::Ld_A;
break;
}

IR::RegOpnd * dstOpnd = this->BuildDstOpnd(R0);
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/LinearScan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2933,9 +2933,9 @@ LinearScan::ProcessEHRegionBoundary(IR::Instr * instr)
}

// Spill everything upon entry to the try region and upon a Leave.
IR::Instr* insertionInstr = instr->m_opcode != Js::OpCode::Leave ? instr : instr->m_prev;
FOREACH_SLIST_ENTRY_EDITING(Lifetime *, lifetime, this->activeLiveranges, iter)
{
IR::Instr* insertionInstr = instr->m_opcode != Js::OpCode::Leave ? instr : instr->m_prev;
this->activeRegs.Clear(lifetime->reg);
if (lifetime->IsInt())
{
Expand Down
39 changes: 26 additions & 13 deletions lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13739,6 +13739,23 @@ Lowerer::GenerateObjectTestAndTypeLoad(IR::Instr *instrLdSt, IR::RegOpnd *opndBa
InsertMove(opndType, opndIndir, instrLdSt);
}

void Lowerer::InsertMoveForPolymorphicCacheIndex(IR::Instr * instr, BailOutInfo * bailOutInfo, int bailOutRecordOffset, uint polymorphicCacheIndexValue)
{
IR::Opnd * indexOpnd = nullptr;

if (this->m_func->IsOOPJIT())
{
indexOpnd = IR::IndirOpnd::New(IR::RegOpnd::New(m_func->GetTopFunc()->GetNativeCodeDataSym(), TyVar, m_func), (int)(bailOutRecordOffset + BailOutRecord::GetOffsetOfPolymorphicCacheIndex()), TyUint32, m_func);
}
else
{
indexOpnd = IR::MemRefOpnd::New((BYTE*)bailOutInfo->bailOutRecord + BailOutRecord::GetOffsetOfPolymorphicCacheIndex(), TyUint32, this->m_func);
}

InsertMove(
indexOpnd, IR::IntConstOpnd::New(polymorphicCacheIndexValue, TyUint32, this->m_func), instr, false);
}

IR::LabelInstr *
Lowerer::GenerateBailOut(IR::Instr * instr, IR::BranchInstr * branchInstr, IR::LabelInstr *bailOutLabel, IR::LabelInstr * collectRuntimeStatsLabel)
{
Expand Down Expand Up @@ -13800,23 +13817,19 @@ Lowerer::GenerateBailOut(IR::Instr * instr, IR::BranchInstr * branchInstr, IR::L
// Generate code to write the cache index into the bailout record before we jump to the call site.
Assert(bailOutInfo->polymorphicCacheIndex != (uint)-1);
Assert(bailOutInfo->bailOutRecord);
IR::Opnd * indexOpnd = nullptr;

if (this->m_func->IsOOPJIT())
{
indexOpnd = IR::IndirOpnd::New(IR::RegOpnd::New(m_func->GetTopFunc()->GetNativeCodeDataSym(), TyVar, m_func), (int)(bailOutRecordOffset + BailOutRecord::GetOffsetOfPolymorphicCacheIndex()), TyUint32, m_func);
}
else
{
indexOpnd = IR::MemRefOpnd::New((BYTE*)bailOutInfo->bailOutRecord + BailOutRecord::GetOffsetOfPolymorphicCacheIndex(), TyUint32, this->m_func);
}

InsertMove(
indexOpnd, IR::IntConstOpnd::New(bailOutInfo->polymorphicCacheIndex, TyUint32, this->m_func), instr, false);
InsertMoveForPolymorphicCacheIndex(instr, bailOutInfo, bailOutRecordOffset, bailOutInfo->polymorphicCacheIndex);
}

if (bailOutInfo->bailOutRecord->IsShared())
{
// The polymorphicCacheIndex value should be relevant only for field type check bailouts.
// In case of a shared bailout record, the polymorphicCacheIndex sticks regardless of the bailout kind being different
// from field type check. Therefore, it results in an out-of-bound write while trying to recrod a field access update.
if (instr->GetBailOutKind() != IR::BailOutFailedTypeCheck && instr->GetBailOutKind() != IR::BailOutFailedFixedFieldTypeCheck)
{
InsertMoveForPolymorphicCacheIndex(instr, bailOutInfo, bailOutRecordOffset, (uint)-1);
}

IR::Opnd *functionBodyOpnd;
if (this->m_func->IsOOPJIT())
{
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/Lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ class Lowerer
void PreserveSourcesForBailOnResultCondition(IR::Instr *const instr, IR::LabelInstr *const skipBailOutLabel) const;
void LowerInstrWithBailOnResultCondition(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel) const;
void GenerateObjectTestAndTypeLoad(IR::Instr *instrLdSt, IR::RegOpnd *opndBase, IR::RegOpnd *opndType, IR::LabelInstr *labelHelper);
void InsertMoveForPolymorphicCacheIndex(IR::Instr * instr, BailOutInfo * bailOutInfo, int bailOutRecordOffset, uint polymorphicCacheIndexValue);
IR::LabelInstr *GenerateBailOut(IR::Instr * instr, IR::BranchInstr * branchInstr = nullptr, IR::LabelInstr * labelBailOut = nullptr, IR::LabelInstr * collectRuntimeStatsLabel = nullptr);
void GenerateJumpToEpilogForBailOut(BailOutInfo * bailOutInfo, IR::Instr *instrAfter);
void GenerateThrow(IR::Opnd* errorCode, IR::Instr * instr);
Expand Down
7 changes: 4 additions & 3 deletions lib/Common/DataStructures/EvalMapString.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ namespace Js
template <bool fastHash>
struct EvalMapStringInternal
{
FinalizableObject* owningVar; // This is the Var that originally owns the character buffer corresponding to this EvalMap key.
JsUtil::CharacterBuffer<char16> str;
hash_t hash;
ModuleID moduleID;
BOOL strict;
BOOL isLibraryCode;

EvalMapStringInternal() : str(), moduleID(0), strict(FALSE), isLibraryCode(FALSE), hash(0) {};
EvalMapStringInternal(__in_ecount(charLength) char16 const* content, int charLength, ModuleID moduleID, BOOL strict, BOOL isLibraryCode)
: str(content, charLength), moduleID(moduleID), strict(strict), isLibraryCode(isLibraryCode)
EvalMapStringInternal() : owningVar(nullptr), str(), moduleID(0), strict(FALSE), isLibraryCode(FALSE), hash(0) {};
EvalMapStringInternal(FinalizableObject* obj, __in_ecount(charLength) char16 const* content, int charLength, ModuleID moduleID, BOOL strict, BOOL isLibraryCode)
: owningVar(obj), str(content, charLength), moduleID(moduleID), strict(strict), isLibraryCode(isLibraryCode)
{
// NOTE: this hash is not equivalent to the character buffer hash
// Don't use a CharacteBuffer to do a map lookup on the EvalMapString.
Expand Down
4 changes: 2 additions & 2 deletions lib/Parser/Parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,9 +1744,9 @@ void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint max
Assert(funcExprScope->GetScopeType() == ScopeType_FuncExpr);

ParseNodeBlock* bodyScope = m_currentNodeFunc->pnodeBodyScope;
Assert(bodyScope->blockType == PnodeBlockType::Function);
Assert(bodyScope == nullptr || bodyScope->blockType == PnodeBlockType::Function);

if (ref->GetScopeId() < bodyScope->blockId && ref->GetScopeId() > blockId)
if (bodyScope && ref->GetScopeId() < bodyScope->blockId && ref->GetScopeId() > blockId)
{
funcExprScope->SetIsObject();
}
Expand Down
14 changes: 12 additions & 2 deletions lib/Runtime/Base/ScriptContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2808,7 +2808,7 @@ namespace Js
return success;
}

void ScriptContext::AddToEvalMap(FastEvalMapString const& key, BOOL isIndirect, ScriptFunction *pfuncScript)
void ScriptContext::AddToEvalMap(FastEvalMapString & key, BOOL isIndirect, ScriptFunction *pfuncScript)
{
Assert(!pfuncScript->GetFunctionInfo()->IsGenerator());

Expand All @@ -2831,7 +2831,7 @@ namespace Js
#endif
}

void ScriptContext::AddToEvalMapHelper(FastEvalMapString const& key, BOOL isIndirect, ScriptFunction *pFuncScript)
void ScriptContext::AddToEvalMapHelper(FastEvalMapString & key, BOOL isIndirect, ScriptFunction *pFuncScript)
{
EvalCacheDictionary *dict = isIndirect ? this->Cache()->indirectEvalCacheDictionary : this->Cache()->evalCacheDictionary;
if (dict == nullptr)
Expand All @@ -2848,6 +2848,15 @@ namespace Js
}
}

if (key.owningVar == nullptr)
{
// We need to copy buffer because in this case the buffer could have come from the host e.g. through IActiveScriptDirect::Parse
JavascriptString* copiedString = JavascriptString::NewCopyBuffer(key.str.GetBuffer(), key.str.GetLength(), this);
key.owningVar = copiedString;
Assert(key.str.GetLength() == copiedString->GetLength());
key.str = JsUtil::CharacterBuffer<char16>(copiedString->GetString(), copiedString->GetLength());
}

dict->Add(key, pFuncScript);
}

Expand Down Expand Up @@ -5725,6 +5734,7 @@ ScriptContext::GetJitFuncRangeCache()

void ConvertKey(const FastEvalMapString& src, EvalMapString& dest)
{
dest.owningVar = src.owningVar;
dest.str = src.str;
dest.strict = src.strict;
dest.moduleID = src.moduleID;
Expand Down
4 changes: 2 additions & 2 deletions lib/Runtime/Base/ScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ namespace Js
void EnsureSourceContextInfoMap();
void EnsureDynamicSourceContextInfoMap();

void AddToEvalMapHelper(FastEvalMapString const& key, BOOL isIndirect, ScriptFunction *pFuncScript);
void AddToEvalMapHelper(FastEvalMapString & key, BOOL isIndirect, ScriptFunction *pFuncScript);

uint moduleSrcInfoCount;
#ifdef RUNTIME_DATA_COLLECTION
Expand Down Expand Up @@ -1096,7 +1096,7 @@ namespace Js
static const int MaxEvalSourceSize = 400;

bool IsInEvalMap(FastEvalMapString const& key, BOOL isIndirect, ScriptFunction **ppFuncScript);
void AddToEvalMap(FastEvalMapString const& key, BOOL isIndirect, ScriptFunction *pFuncScript);
void AddToEvalMap(FastEvalMapString & key, BOOL isIndirect, ScriptFunction *pFuncScript);

template <typename TCacheType>
void CleanDynamicFunctionCache(TCacheType* cacheType);
Expand Down
19 changes: 10 additions & 9 deletions lib/Runtime/ByteCode/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2226,7 +2226,7 @@ void ByteCodeGenerator::LoadSuperObject(FuncInfo *funcInfo)
m_writer.Reg1(Js::OpCode::LdHomeObj, superSym->GetLocation());
}

void ByteCodeGenerator::EmitSuperCall(FuncInfo* funcInfo, ParseNodeSuperCall * pnodeSuperCall, BOOL fReturnValue)
void ByteCodeGenerator::EmitSuperCall(FuncInfo* funcInfo, ParseNodeSuperCall * pnodeSuperCall, BOOL fReturnValue, BOOL fEvaluateComponents)
{
FuncInfo* nonLambdaFunc = funcInfo;
bool isResultUsed = pnodeSuperCall->isUsed;
Expand Down Expand Up @@ -2292,7 +2292,7 @@ void ByteCodeGenerator::EmitSuperCall(FuncInfo* funcInfo, ParseNodeSuperCall * p
this->Writer()->MarkLabel(useNewTargetForThisLabel);
this->Writer()->Reg2(Js::OpCode::Ld_A, thisForSuperCall, pnodeSuperCall->pnodeNewTarget->location);
this->Writer()->MarkLabel(makeCallLabel);
EmitCall(pnodeSuperCall, this, funcInfo, fReturnValue, /*fEvaluateComponents*/ true, thisForSuperCall, pnodeSuperCall->pnodeNewTarget->location);
EmitCall(pnodeSuperCall, this, funcInfo, fReturnValue, fEvaluateComponents, thisForSuperCall, pnodeSuperCall->pnodeNewTarget->location);

// We have to use another temp for the this value before assigning to this register.
// This is because IRBuilder does not expect us to use the value of a temp after potentially assigning to that same temp.
Expand Down Expand Up @@ -6969,7 +6969,7 @@ void EmitLoad(
{
funcInfo->AcquireLoc(pnodeCallLhs);
EmitReference(pnodeCallLhs, byteCodeGenerator, funcInfo);
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCallLhs->AsParseNodeSuperCall(), /*fReturnValue=*/ false);
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCallLhs->AsParseNodeSuperCall(), /*fReturnValue=*/ false, /*fEvaluateComponents=*/ false);
}
else if (pnodeCallLhs->pnodeTarget->nop == knopImport)
{
Expand Down Expand Up @@ -7890,6 +7890,7 @@ void EmitCallI(
void EmitCallInstrNoEvalComponents(
ParseNodeCall *pnodeCall,
BOOL fIsEval,
BOOL fHasNewTarget,
Js::RegSlot thisLocation,
Js::RegSlot callObjLocation,
uint32 actualArgCount,
Expand All @@ -7913,14 +7914,14 @@ void EmitCallInstrNoEvalComponents(
Js::PropertyId propertyId = pnodeTarget->AsParseNodeBin()->pnode2->AsParseNodeName()->PropertyIdFromNameNode();

EmitMethodFld(pnodeTarget, callObjLocation, propertyId, byteCodeGenerator, funcInfo);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, /*fHasNewTarget*/ FALSE, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, fHasNewTarget, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
}
break;

case knopIndex:
{
EmitMethodElem(pnodeTarget, pnodeTarget->AsParseNodeBin()->pnode1->location, pnodeTarget->AsParseNodeBin()->pnode2->location, byteCodeGenerator);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, /*fHasNewTarget*/ FALSE, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, fHasNewTarget, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
}
break;

Expand All @@ -7937,14 +7938,14 @@ void EmitCallInstrNoEvalComponents(

Js::PropertyId propertyId = pnodeTarget->AsParseNodeName()->PropertyIdFromNameNode();
EmitMethodFld(pnodeTarget, callObjLocation, propertyId, byteCodeGenerator, funcInfo);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, /*fHasNewTarget*/ FALSE, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, fHasNewTarget, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
break;
}
}
// FALL THROUGH

default:
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, /*fHasNewTarget*/ FALSE, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
EmitCallI(pnodeCall, /*fEvaluateComponents*/ FALSE, fIsEval, fHasNewTarget, actualArgCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
break;
}
}
Expand Down Expand Up @@ -8183,7 +8184,7 @@ void EmitCall(

if (!fEvaluateComponents)
{
EmitCallInstrNoEvalComponents(pnodeCall, fIsEval, thisLocation, callObjLocation, argSlotCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
EmitCallInstrNoEvalComponents(pnodeCall, fIsEval, fHasNewTarget, thisLocation, callObjLocation, argSlotCount, byteCodeGenerator, funcInfo, callSiteId, spreadIndices);
}
else
{
Expand Down Expand Up @@ -10548,7 +10549,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func

if (pnodeCall->isSuperCall)
{
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCall->AsParseNodeSuperCall(), fReturnValue);
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCall->AsParseNodeSuperCall(), fReturnValue, /*fEvaluateComponents=*/ true);
}
else if (pnodeCall->pnodeTarget->nop == knopImport)
{
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/ByteCode/ByteCodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class ByteCodeGenerator
void LoadNewTargetObject(FuncInfo *funcInfo);
void LoadSuperObject(FuncInfo *funcInfo);
void LoadSuperConstructorObject(FuncInfo *funcInfo);
void EmitSuperCall(FuncInfo* funcInfo, ParseNodeSuperCall * pnodeSuperCall, BOOL fReturnValue);
void EmitSuperCall(FuncInfo* funcInfo, ParseNodeSuperCall * pnodeSuperCall, BOOL fReturnValue, BOOL fEvaluateComponents);
void EmitClassConstructorEndCode(FuncInfo *funcInfo);

// TODO: home the 'this' argument
Expand Down

0 comments on commit fdf0aeb

Please sign in to comment.