[MERGE #6108 @LouisLaf] Fix ChakraFull CI
Merge pull request #6108 from LouisLaf:ophelper
When coalesing this pattern:
L1: <helper>
L2:
Mark the remaining label as non-helper.
diff --git a/lib/Backend/BackwardPass.cpp b/lib/Backend/BackwardPass.cpp
index 6b4c9f9..7e749a5 100644
--- a/lib/Backend/BackwardPass.cpp
+++ b/lib/Backend/BackwardPass.cpp
@@ -2659,11 +2659,17 @@
BVSparse<JitArenaAllocator>* tmpBv = nullptr;
if (instr->IsBranchInstr())
{
- IR::LabelInstr* target = instr->AsBranchInstr()->GetTarget();
+ IR::BranchInstr* branchInstr = instr->AsBranchInstr();
+ IR::LabelInstr* target = branchInstr->GetTarget();
uint32 targetOffset = target->GetByteCodeOffset();
- if (targetOffset == instr->GetByteCodeOffset())
+
+ // If the instr's label has the same bytecode offset as the instr then move the targetOffset
+ // to the next bytecode instr. This condition can be true on conditional branches, ex: a
+ // while loop with no body (passing the loop's condition would branch the IP back to executing
+ // the loop's condition), in these cases do not move the targetOffset.
+ if (targetOffset == instr->GetByteCodeOffset() && branchInstr->IsUnconditional())
{
- // This can happen if the target is an break or airlock block
+ // This can happen if the target is a break or airlock block.
Assert(
target->GetBasicBlock()->isAirLockBlock ||
target->GetBasicBlock()->isAirLockCompensationBlock ||
@@ -2673,11 +2679,12 @@
);
targetOffset = target->GetNextByteCodeInstr()->GetByteCodeOffset();
}
- BVSparse<JitArenaAllocator>* branchTargetUpdwardExposed = target->m_func->GetByteCodeOffsetUses(targetOffset);
- if (branchTargetUpdwardExposed)
+ BVSparse<JitArenaAllocator>* branchTargetUpwardExposed = target->m_func->GetByteCodeOffsetUses(targetOffset);
+ if (branchTargetUpwardExposed)
{
- // The bailout should restore both the bailout destination and the branch target since we don't know where we'll end up
- trackingByteCodeUpwardExposedUsed = tmpBv = trackingByteCodeUpwardExposedUsed->OrNew(branchTargetUpdwardExposed);
+ // The bailout should restore both the bailout destination and
+ // the branch target since we don't know where we'll end up.
+ trackingByteCodeUpwardExposedUsed = tmpBv = trackingByteCodeUpwardExposedUsed->OrNew(branchTargetUpwardExposed);
}
}
Assert(trackingByteCodeUpwardExposedUsed);
@@ -3857,7 +3864,7 @@
this->tag == Js::DeadStorePhase
// We don't do the masking in simplejit due to reduced perf concerns and the issues
// with handling try/catch structures with late-added blocks
- && !this->func->IsSimpleJit()
+ && this->func->DoGlobOpt()
// We don't need the masking blocks in asmjs/wasm mode
&& !block->GetFirstInstr()->m_func->GetJITFunctionBody()->IsAsmJsMode()
&& !block->GetFirstInstr()->m_func->GetJITFunctionBody()->IsWasmFunction()
@@ -7865,7 +7872,8 @@
if (instr->m_opcode == Js::OpCode::ArgIn_A)
{
- //Ignore tracking ArgIn for "this", as argInsCount only tracks other params - unless it is a asmjs function(which doesn't have a "this").
+ // Ignore tracking ArgIn for "this" as argInsCount only tracks other
+ // params, unless it is a AsmJS function (which doesn't have a "this").
if (instr->GetSrc1()->AsSymOpnd()->m_sym->AsStackSym()->GetParamSlotNum() != 1 || func->GetJITFunctionBody()->IsAsmJsMode())
{
Assert(this->func->argInsCount > 0);
@@ -8845,7 +8853,11 @@
opCode = Js::OpCode::Sub_I4;
}
Func *localFunc = loop->GetFunc();
- StackSym *sym = localFunc->m_symTable->FindStackSym(symId)->GetInt32EquivSym(localFunc);
+ StackSym *sym = localFunc->m_symTable->FindStackSym(symId);
+ if (!sym->IsInt32())
+ {
+ sym = sym->GetInt32EquivSym(localFunc);
+ }
IR::Opnd *inductionVariableOpnd = IR::RegOpnd::New(sym, IRType::TyInt32, localFunc);
IR::Opnd *tempInductionVariableOpnd = IR::RegOpnd::New(IRType::TyInt32, localFunc);
@@ -8929,7 +8941,7 @@
{
Assert(instr->GetDst());
if (instr->GetDst()->GetStackSym()
- && loop->memOpInfo->inductionVariablesUsedAfterLoop->Test(globOpt->GetVarSymID(instr->GetDst()->GetStackSym())))
+ && loop->memOpInfo->inductionVariablesUsedAfterLoop->Test(instr->GetDst()->GetStackSym()->m_id))
{
// We have use after the loop for a variable defined inside the loop. So the loop can't be removed.
return false;
diff --git a/lib/Backend/BailOut.cpp b/lib/Backend/BailOut.cpp
index 11361de..a6c6d76 100644
--- a/lib/Backend/BailOut.cpp
+++ b/lib/Backend/BailOut.cpp
@@ -1178,7 +1178,7 @@
bool * hasBailedOutBitPtr = layout->functionObject->GetScriptContext()->GetThreadContext()->GetHasBailedOutBitPtr();
Assert(!bailOutRecord->ehBailoutData || hasBailedOutBitPtr ||
bailOutRecord->ehBailoutData->ht == Js::HandlerType::HT_Finally /* When we bailout from inlinee in non exception finally, we maynot see hasBailedOutBitPtr*/);
- if (hasBailedOutBitPtr && bailOutRecord->ehBailoutData)
+ if (hasBailedOutBitPtr && bailOutRecord->ehBailoutData && bailOutRecord->ehBailoutData->ht != Js::HandlerType::HT_Finally)
{
*hasBailedOutBitPtr = true;
}
diff --git a/lib/Backend/FlowGraph.cpp b/lib/Backend/FlowGraph.cpp
index efe194f..fb6b9be 100644
--- a/lib/Backend/FlowGraph.cpp
+++ b/lib/Backend/FlowGraph.cpp
@@ -1137,9 +1137,9 @@
// We have to update region info for blocks whose predecessors changed
if (assignRegionsBeforeGlobopt)
{
- UpdateRegionForBlockFromEHPred(dstPredBlock, true);
- UpdateRegionForBlockFromEHPred(blockStart, true);
- UpdateRegionForBlockFromEHPred(srcNextBlock, true);
+ UpdateRegionForBlock(dstPredBlock);
+ UpdateRegionForBlock(blockStart);
+ UpdateRegionForBlock(srcNextBlock);
}
}
@@ -1871,30 +1871,6 @@
this->func->isFlowGraphValid = false;
}
-bool FlowGraph::IsEHTransitionInstr(IR::Instr *instr)
-{
- Js::OpCode op = instr->m_opcode;
- return (op == Js::OpCode::TryCatch || op == Js::OpCode::TryFinally || op == Js::OpCode::Leave || op == Js::OpCode::LeaveNull);
-}
-
-BasicBlock * FlowGraph::GetPredecessorForRegionPropagation(BasicBlock *block)
-{
- BasicBlock *ehPred = nullptr;
- FOREACH_PREDECESSOR_BLOCK(predBlock, block)
- {
- Region * predRegion = predBlock->GetFirstInstr()->AsLabelInstr()->GetRegion();
- if (IsEHTransitionInstr(predBlock->GetLastInstr()) && predRegion)
- {
- // MGTODO : change this to return, once you know there can exist only one eh transitioning pred
- Assert(ehPred == nullptr);
- ehPred = predBlock;
- }
- AssertMsg(predBlock->GetBlockNum() < this->blockCount, "Misnumbered block at teardown time?");
- }
- NEXT_PREDECESSOR_BLOCK;
- return ehPred;
-}
-
// Propagate the region forward from the block's predecessor(s), tracking the effect
// of the flow transition. Record the region in the block-to-region map provided
// and on the label at the entry to the block (if any).
@@ -1958,7 +1934,6 @@
}
}
- Assert(region || block->GetPredList()->Count() == 0);
if (region && !region->ehBailoutData)
{
region->AllocateEHBailoutData(this->func, tryInstr);
@@ -1997,106 +1972,6 @@
}
}
-void
-FlowGraph::UpdateRegionForBlockFromEHPred(BasicBlock * block, bool reassign)
-{
- Region *region = nullptr;
- Region * predRegion = nullptr;
- IR::Instr * tryInstr = nullptr;
- IR::Instr * firstInstr = block->GetFirstInstr();
- if (!reassign && firstInstr->IsLabelInstr() && firstInstr->AsLabelInstr()->GetRegion())
- {
- Assert(this->func->HasTry() && (this->func->DoOptimizeTry() || (this->func->IsSimpleJit() && this->func->hasBailout)));
- return;
- }
- if (block->isDead || block->isDeleted)
- {
- // We can end up calling this function with such blocks, return doing nothing
- // See test5() in tryfinallytests.js
- return;
- }
-
- if (block == this->blockList)
- {
- // Head of the graph: create the root region.
- region = Region::New(RegionTypeRoot, nullptr, this->func);
- }
- else if (block->GetPredList()->Count() == 1)
- {
- BasicBlock *predBlock = block->GetPredList()->Head()->GetPred();
- AssertMsg(predBlock->GetBlockNum() < this->blockCount, "Misnumbered block at teardown time?");
- predRegion = predBlock->GetFirstInstr()->AsLabelInstr()->GetRegion();
- Assert(predRegion);
- region = this->PropagateRegionFromPred(block, predBlock, predRegion, tryInstr);
- }
- else
- {
- // Propagate the region forward by finding a predecessor we've already processed.
- // Since we do break block remval after region propagation, we cannot pick the first predecessor which has an assigned region
- // If there is a eh transitioning pred, we pick that
- // There cannot be more than one eh transitioning pred (?)
- BasicBlock *ehPred = this->GetPredecessorForRegionPropagation(block);
- if (ehPred)
- {
- predRegion = ehPred->GetFirstInstr()->AsLabelInstr()->GetRegion();
- Assert(predRegion != nullptr);
- region = this->PropagateRegionFromPred(block, ehPred, predRegion, tryInstr);
- }
- else
- {
- FOREACH_PREDECESSOR_BLOCK(predBlock, block)
- {
- predRegion = predBlock->GetFirstInstr()->AsLabelInstr()->GetRegion();
- if (predRegion != nullptr)
- {
- if ((predBlock->GetLastInstr()->m_opcode == Js::OpCode::BrOnException || predBlock->GetLastInstr()->m_opcode == Js::OpCode::BrOnNoException) &&
- predBlock->GetLastInstr()->AsBranchInstr()->m_brFinallyToEarlyExit)
- {
- Assert(predRegion->IsNonExceptingFinally());
- // BrOnException from finally region to early exit
- // Skip this edge
- continue;
- }
- if (predBlock->GetLastInstr()->m_opcode == Js::OpCode::Br &&
- predBlock->GetLastInstr()->GetPrevRealInstr()->m_opcode == Js::OpCode::BrOnNoException)
- {
- Assert(predBlock->GetLastInstr()->GetPrevRealInstr()->AsBranchInstr()->m_brFinallyToEarlyExit);
- Assert(predRegion->IsNonExceptingFinally());
- // BrOnException from finally region to early exit changed to BrOnNoException and Br during break block removal
- continue;
- }
- region = this->PropagateRegionFromPred(block, predBlock, predRegion, tryInstr);
- break;
- }
- }
- NEXT_PREDECESSOR_BLOCK;
- }
- }
-
- Assert(region || block->GetPredList()->Count() == 0 || block->firstInstr->AsLabelInstr()->GetRegion());
-
- if (region)
- {
- if (!region->ehBailoutData)
- {
- region->AllocateEHBailoutData(this->func, tryInstr);
- }
-
- Assert(firstInstr->IsLabelInstr());
- if (firstInstr->IsLabelInstr())
- {
- // Record the region on the label and make sure it stays around as a region
- // marker if we're entering a region at this point.
- IR::LabelInstr * labelInstr = firstInstr->AsLabelInstr();
- labelInstr->SetRegion(region);
- if (region != predRegion)
- {
- labelInstr->m_hasNonBranchRef = true;
- }
- }
- }
-}
-
Region *
FlowGraph::PropagateRegionFromPred(BasicBlock * block, BasicBlock * predBlock, Region * predRegion, IR::Instr * &tryInstr)
{
@@ -2488,7 +2363,7 @@
if (assignRegionsBeforeGlobopt)
{
- UpdateRegionForBlockFromEHPred(compBlock);
+ UpdateRegionForBlock(compBlock);
}
}
else
diff --git a/lib/Backend/FlowGraph.h b/lib/Backend/FlowGraph.h
index f05fc56..87c1f8e 100644
--- a/lib/Backend/FlowGraph.h
+++ b/lib/Backend/FlowGraph.h
@@ -201,10 +201,7 @@
void BuildLoop(BasicBlock *headBlock, BasicBlock *tailBlock, Loop *parentLoop = nullptr);
void WalkLoopBlocks(BasicBlock *block, Loop *loop, JitArenaAllocator *tempAlloc);
void AddBlockToLoop(BasicBlock *block, Loop *loop);
- bool IsEHTransitionInstr(IR::Instr *instr);
- BasicBlock * GetPredecessorForRegionPropagation(BasicBlock *block);
void UpdateRegionForBlock(BasicBlock *block);
- void UpdateRegionForBlockFromEHPred(BasicBlock *block, bool reassign = false);
Region * PropagateRegionFromPred(BasicBlock *block, BasicBlock *predBlock, Region *predRegion, IR::Instr * &tryInstr);
IR::Instr * PeepCm(IR::Instr *instr);
IR::Instr * PeepTypedCm(IR::Instr *instr);
diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp
index d5a28f0..2bc30f7 100644
--- a/lib/Backend/GlobOpt.cpp
+++ b/lib/Backend/GlobOpt.cpp
@@ -165,7 +165,13 @@
GlobOpt::Optimize()
{
this->objectTypeSyms = nullptr;
- this->func->argInsCount = this->func->GetInParamsCount() - 1; //Don't include "this" pointer in the count.
+
+ this->func->argInsCount = this->func->GetInParamsCount();
+ if (!func->GetJITFunctionBody()->IsAsmJsMode())
+ {
+ // Don't include "this" pointer in the count when not in AsmJs mode (AsmJS does not have "this").
+ this->func->argInsCount--;
+ }
if (!func->DoGlobOpt())
{
@@ -2216,10 +2222,20 @@
if (!loop->memOpInfo->inductionVariableChangeInfoMap->ContainsKey(inductionSymID))
{
loop->memOpInfo->inductionVariableChangeInfoMap->Add(inductionSymID, inductionVariableChangeInfo);
+ if (sym->m_id != inductionSymID)
+ {
+ // Backwards pass uses this bit-vector to lookup upwardExposedUsed/bytecodeUpwardExposedUsed symbols, which are not necessarily vars. Just add both.
+ loop->memOpInfo->inductionVariableChangeInfoMap->Add(sym->m_id, inductionVariableChangeInfo);
+ }
}
else
{
loop->memOpInfo->inductionVariableChangeInfoMap->Item(inductionSymID, inductionVariableChangeInfo);
+ if (sym->m_id != inductionSymID)
+ {
+ // Backwards pass uses this bit-vector to lookup upwardExposedUsed/bytecodeUpwardExposedUsed symbols, which are not necessarily vars. Just add both.
+ loop->memOpInfo->inductionVariableChangeInfoMap->Item(sym->m_id, inductionVariableChangeInfo);
+ }
}
}
else
@@ -2228,6 +2244,11 @@
{
Loop::InductionVariableChangeInfo inductionVariableChangeInfo = { 1, isIncr };
loop->memOpInfo->inductionVariableChangeInfoMap->Add(inductionSymID, inductionVariableChangeInfo);
+ if (sym->m_id != inductionSymID)
+ {
+ // Backwards pass uses this bit-vector to lookup upwardExposedUsed/bytecodeUpwardExposedUsed symbols, which are not necessarily vars. Just add both.
+ loop->memOpInfo->inductionVariableChangeInfoMap->Add(sym->m_id, inductionVariableChangeInfo);
+ }
}
else
{
@@ -2242,6 +2263,11 @@
}
inductionVariableChangeInfo.isIncremental = isIncr;
loop->memOpInfo->inductionVariableChangeInfoMap->Item(inductionSymID, inductionVariableChangeInfo);
+ if (sym->m_id != inductionSymID)
+ {
+ // Backwards pass uses this bit-vector to lookup upwardExposedUsed/bytecodeUpwardExposedUsed symbols, which are not necessarily vars. Just add both.
+ loop->memOpInfo->inductionVariableChangeInfoMap->Item(sym->m_id, inductionVariableChangeInfo);
+ }
}
}
break;
@@ -6660,7 +6686,8 @@
{
return undefinedCmp;
}
- return val1->GetValueInfo()->IsPrimitive() && val1->GetValueInfo()->IsNotFloat();
+ ValueInfo * valInfo = val1->GetValueInfo();
+ return !valInfo->HasBeenUndefined() && valInfo->IsPrimitive() && valInfo->IsNotFloat();
}
return false;
};
@@ -6960,7 +6987,20 @@
{
return false;
}
- *result = !src1ValueInfo->IsPrimitive();
+
+ if (src1ValueInfo->IsPrimitive())
+ {
+ *result = false;
+ }
+ else
+ {
+ if (src1ValueInfo->HasBeenPrimitive())
+ {
+ return false;
+ }
+ *result = true;
+ }
+
break;
}
default:
diff --git a/lib/Backend/Inline.cpp b/lib/Backend/Inline.cpp
index cbc44dd..00fddd0 100644
--- a/lib/Backend/Inline.cpp
+++ b/lib/Backend/Inline.cpp
@@ -2215,7 +2215,7 @@
StackSym * sym = argInstr->GetSrc1()->GetStackSym();
if (!sym->m_isSingleDef || !sym->m_instrDef->GetSrc1() || !sym->m_instrDef->GetSrc1()->IsConstOpnd())
{
- if (!sym->IsFromByteCodeConstantTable())
+ if (!sym->IsFromByteCodeConstantTable() && sym->GetByteCodeRegSlot() != callInstrDst->GetStackSym()->GetByteCodeRegSlot())
{
byteCodeUsesInstr->Set(argInstr->GetSrc1());
}
diff --git a/lib/Runtime/Base/CharStringCache.cpp b/lib/Runtime/Base/CharStringCache.cpp
index adcce77..f41cb54 100644
--- a/lib/Runtime/Base/CharStringCache.cpp
+++ b/lib/Runtime/Base/CharStringCache.cpp
@@ -78,10 +78,19 @@
{
Assert(c >= 0x10000);
CompileAssert(sizeof(char16) * 2 == sizeof(codepoint_t));
+
+ ScriptContext* scriptContext = JavascriptLibrary::FromCharStringCache(this)->GetScriptContext();
+
+ // #sec - string.fromcodepoint: "If nextCP < 0 or nextCP > 0x10FFFF, throw a RangeError exception"
+ if (c > 0x10FFFF)
+ {
+ JavascriptError::ThrowRangeError(scriptContext, JSERR_InvalidCodePoint, scriptContext->GetIntegerString(c));
+ }
+
char16 buffer[2];
Js::NumberUtilities::CodePointAsSurrogatePair(c, buffer, buffer + 1);
- JavascriptString* str = JavascriptString::NewCopyBuffer(buffer, 2, JavascriptLibrary::FromCharStringCache(this)->GetScriptContext());
+ JavascriptString* str = JavascriptString::NewCopyBuffer(buffer, 2, scriptContext);
// TODO: perhaps do some sort of cache for supplementary characters
return str;
}
diff --git a/lib/Runtime/Library/JavascriptArray.cpp b/lib/Runtime/Library/JavascriptArray.cpp
index 6d0578b..14a977d 100644
--- a/lib/Runtime/Library/JavascriptArray.cpp
+++ b/lib/Runtime/Library/JavascriptArray.cpp
@@ -11917,6 +11917,7 @@
SparseArraySegment<typename T::TElement>* src = SparseArraySegment<typename T::TElement>::From(instance->head);
SparseArraySegment<typename T::TElement>* dst;
+ uint32 sourceSize = src->size;
if (IsInlineSegment(src, instance))
{
// Copy head segment data between inlined head segments
@@ -11925,6 +11926,7 @@
dst->length = src->length;
uint inlineChunkSize = SparseArraySegmentBase::INLINE_CHUNK_SIZE;
dst->size = min(src->size, inlineChunkSize);
+ sourceSize = dst->size;
}
else
{
@@ -11939,8 +11941,7 @@
Assert(IsInlineSegment(src, instance) == IsInlineSegment(dst, static_cast<T*>(this)));
- AssertOrFailFast(dst->size <= src->size);
- CopyArray(dst->elements, dst->size, src->elements, dst->size);
+ CopyArray(dst->elements, dst->size, src->elements, sourceSize);
if (!deepCopy)
{
diff --git a/test/EH/hasBailedOutBug3.js b/test/EH/hasBailedOutBug3.js
new file mode 100644
index 0000000..ac7908a
--- /dev/null
+++ b/test/EH/hasBailedOutBug3.js
@@ -0,0 +1,35 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+WScript.Echo = function (n) {
+ formatOutput(n.toString());
+};
+function formatOutput(n) {
+ return n.replace(/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g, function () {
+ });
+}
+function test0() {
+ var GiantPrintArray = [];
+ var protoObj0 = {};
+ try {
+ function func36() {
+ try {
+ }
+ finally {
+ WScript.Echo('' + b);
+ GiantPrintArray.push(protoObj0);
+ }
+ }
+ func36();
+ __loopSecondaryVar3_0;
+ } catch (ex) {
+ b = ex;
+ }
+}
+test0();
+test0();
+test0();
+print("Passed\n");
+
diff --git a/test/EH/regionBugSpecHoisting.js b/test/EH/regionBugSpecHoisting.js
new file mode 100644
index 0000000..6fb079b
--- /dev/null
+++ b/test/EH/regionBugSpecHoisting.js
@@ -0,0 +1,28 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function test0() {
+ var ui8 = new Uint8Array(1);
+ try {
+ try {
+ for (var _strvar28 in ui8) {
+ try {
+ return '';
+ } catch (ex) {
+ }
+ try {
+ } catch (ex) {
+ }
+ }
+ } catch(ex) {
+ }
+ } finally {
+ }
+}
+test0();
+test0();
+test0();
+test0();
+print("Passed\n");
diff --git a/test/EH/rlexe.xml b/test/EH/rlexe.xml
index 4be81de..0e0e042 100644
--- a/test/EH/rlexe.xml
+++ b/test/EH/rlexe.xml
@@ -191,6 +191,11 @@
</test>
<test>
<default>
+ <files>hasBailedOutBug3.js</files>
+ </default>
+ </test>
+ <test>
+ <default>
<files>StackOverflow.js</files>
</default>
</test>
@@ -210,4 +215,10 @@
<compile-flags>-args summary -endargs</compile-flags>
</default>
</test>
+ <test>
+ <default>
+ <files>regionBugSpecHoisting.js</files>
+ <compile-flags>-mic:1 -off:simplejit</compile-flags>
+ </default>
+ </test>
</regress-exe>
diff --git a/test/Optimizer/bugconstfoldobject.baseline b/test/Optimizer/bugconstfoldobject.baseline
new file mode 100644
index 0000000..b24310a
--- /dev/null
+++ b/test/Optimizer/bugconstfoldobject.baseline
@@ -0,0 +1,3 @@
+[object Object]
+[object Object]
+[object Object]
diff --git a/test/Optimizer/bugconstfoldobject.js b/test/Optimizer/bugconstfoldobject.js
new file mode 100644
index 0000000..989aef1
--- /dev/null
+++ b/test/Optimizer/bugconstfoldobject.js
@@ -0,0 +1,19 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function test0() {
+ class class3 {
+ constructor() {
+ return '9'.match(/^(?=[a7])$/gim);
+ }
+ }
+ strvar0 = new class3();
+ new class3();
+ WScript.Echo(strvar0);
+}
+test0();
+test0();
+test0();
+
diff --git a/test/Optimizer/bugconstfoldundefined.baseline b/test/Optimizer/bugconstfoldundefined.baseline
new file mode 100644
index 0000000..f7caf94
--- /dev/null
+++ b/test/Optimizer/bugconstfoldundefined.baseline
@@ -0,0 +1 @@
+1,6333966881283110000
diff --git a/test/Optimizer/bugconstfoldundefined.js b/test/Optimizer/bugconstfoldundefined.js
new file mode 100644
index 0000000..0143fb0
--- /dev/null
+++ b/test/Optimizer/bugconstfoldundefined.js
@@ -0,0 +1,38 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+var obj1 = {};
+var litObj1 = {};
+var func1 = function () {
+ if (ary.push(arguments[0])) {
+ }
+};
+obj1.method0 = func1;
+var ary = Array();
+var FloatArr0 = [
+ 6333966881283110000,
+ 1
+];
+var VarArr0 = Array();
+var v3 = 0;
+function v4() {
+ return caller1_bar();
+}
+function v5() {
+ return v4();
+}
+function caller1_bar() {
+ v3++;
+ if (v3 < 10) {
+ v4();
+ var id33 = {} instanceof Boolean;
+ }
+ if (ary.shift(), (obj1.method0.call(litObj1, FloatArr0), id33 <= id33 ? VarArr0 : FloatArr0.reverse())) {
+ }
+}
+v5();
+WScript.Echo(ary.slice().reduce(function () {
+}));
+
diff --git a/test/Optimizer/rlexe.xml b/test/Optimizer/rlexe.xml
index ce553dd..8882aa3 100644
--- a/test/Optimizer/rlexe.xml
+++ b/test/Optimizer/rlexe.xml
@@ -1569,6 +1569,14 @@
</test>
<test>
<default>
+ <files>bugconstfoldundefined.js</files>
+ <baseline>bugconstfoldundefined.baseline</baseline>
+ <compile-flags>-maxinterpretcount:6 -maxsimplejitruncount:4 -werexceptionsupport -oopjit- -mic:1 -off:simplejit -forcejitloopbody</compile-flags>
+ <tags>exclude_dynapogo,exclude_nonative</tags>
+ </default>
+ </test>
+ <test>
+ <default>
<files>bcebug.js</files>
<compile-flags>-mic:1 -off:simplejit -bgjit- -lic:1</compile-flags>
</default>
diff --git a/test/Strings/fromCodePoint.js b/test/Strings/fromCodePoint.js
new file mode 100644
index 0000000..fe8943f
--- /dev/null
+++ b/test/Strings/fromCodePoint.js
@@ -0,0 +1,18 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function f() {
+ var var_0 = new Array(1024);
+ for (var var_1 = 0; ; var_1 += 1024) {
+ var_0[var_1] = String.fromCodePoint(var_1);
+ }
+}
+
+try {
+ f();
+}
+catch(e) {
+ WScript.Echo("pass");
+}
diff --git a/test/Strings/rlexe.xml b/test/Strings/rlexe.xml
index fc5b3aa..9a44d07 100644
--- a/test/Strings/rlexe.xml
+++ b/test/Strings/rlexe.xml
@@ -14,6 +14,11 @@
</test>
<test>
<default>
+ <files>fromCodePoint.js</files>
+ </default>
+ </test>
+ <test>
+ <default>
<files>charCodeAt.js</files>
<baseline>charCodeAt.baseline</baseline>
</default>