Просмотр исходного кода

[1.4>2.0] [MERGE #2697 @MikeHolman] 17-03 ChakraCore servicing release

Merge pull request #2697 from MikeHolman:release/1703

Fixes the following CVEs impacting ChakraCore:
CVE-2017-0067
CVE-2017-0150
CVE-2017-0138
CVE-2017-0094
CVE-2017-0132
CVE-2017-0133
CVE-2017-0134
CVE-2017-0137
CVE-2017-0071
CVE-2017-0151
CVE-2017-0141
CVE-2017-0196
CVE-2017-0136
CVE-2017-0152
CVE-2017-0010
CVE-2017-0035
CVE-2017-0015
CVE-2017-0028
Michael Holman 9 лет назад
Родитель
Сommit
e5d41078cb
50 измененных файлов с 928 добавлено и 600 удалено
  1. 2 0
      lib/Backend/BackwardPass.cpp
  2. 0 2
      lib/Backend/GlobOptFields.cpp
  3. 1 0
      lib/Backend/IR.h
  4. 9 15
      lib/Backend/IRBuilder.cpp
  5. 1 1
      lib/Backend/IRBuilderAsmJs.cpp
  6. 5 4
      lib/Backend/Lower.cpp
  7. 2 2
      lib/Backend/LowerMDShared.cpp
  8. 1 1
      lib/Backend/LowerMDShared.h
  9. 36 5
      lib/Backend/amd64/LowererMDArch.cpp
  10. 1 1
      lib/Backend/amd64/LowererMDArch.h
  11. 30 3
      lib/Backend/arm/LowerMD.cpp
  12. 1 1
      lib/Backend/arm/LowerMD.h
  13. 1 1
      lib/Backend/arm64/LowerMD.h
  14. 36 6
      lib/Backend/i386/LowererMDArch.cpp
  15. 1 1
      lib/Backend/i386/LowererMDArch.h
  16. 33 0
      lib/Parser/Parse.cpp
  17. 3 3
      lib/Runtime/Base/Debug.cpp
  18. 181 168
      lib/Runtime/Base/FunctionBody.cpp
  19. 5 1
      lib/Runtime/Base/ScriptContext.cpp
  20. 6 3
      lib/Runtime/ByteCode/ByteCodeEmitter.cpp
  21. 1 1
      lib/Runtime/ByteCode/FuncInfo.cpp
  22. 2 1
      lib/Runtime/ByteCode/FuncInfo.h
  23. 9 1
      lib/Runtime/Language/AsmJs.cpp
  24. 2 0
      lib/Runtime/Language/AsmJsByteCodeGenerator.cpp
  25. 8 3
      lib/Runtime/Language/AsmJsModule.cpp
  26. 7 4
      lib/Runtime/Language/InterpreterStackFrame.cpp
  27. 26 17
      lib/Runtime/Language/JavascriptStackWalker.cpp
  28. 2 2
      lib/Runtime/Language/JavascriptStackWalker.h
  29. 1 0
      lib/Runtime/Language/ProfilingHelpers.cpp
  30. 3 2
      lib/Runtime/Language/StackTraceArguments.cpp
  31. 3 3
      lib/Runtime/Library/ArgumentsObject.cpp
  32. 6 0
      lib/Runtime/Library/ArrayBuffer.cpp
  33. 5 6
      lib/Runtime/Library/GlobalObject.cpp
  34. 32 7
      lib/Runtime/Library/JavascriptArray.cpp
  35. 3 2
      lib/Runtime/Library/JavascriptFunction.cpp
  36. 0 1
      lib/Runtime/Library/JavascriptLibrary.cpp
  37. 8 1
      lib/Runtime/Library/JavascriptProxy.cpp
  38. 27 0
      test/Array/Array_TypeConfusion_bugs.js
  39. 36 0
      test/Array/array_conv_src.js
  40. 5 0
      test/Array/rlexe.xml
  41. 2 0
      test/AsmJs/nested.baseline
  42. 12 0
      test/AsmJs/nested.js
  43. 2 2
      test/AsmJs/qmarkbug.baseline
  44. 32 30
      test/AsmJs/qmarkbug.js
  45. 7 0
      test/AsmJs/rlexe.xml
  46. 4 4
      test/AsmJs/shadowingBug.baseline
  47. 3 3
      test/AsmJs/shadowingBug.js
  48. 16 0
      test/es6/default-splitscope.js
  49. 8 1
      test/es6/lambda-params-shadow.js
  50. 301 291
      test/es6/proxybugs.js

+ 2 - 0
lib/Backend/BackwardPass.cpp

@@ -2535,6 +2535,8 @@ BackwardPass::ProcessBlock(BasicBlock * block)
         }
 #endif
 
+        AssertOrFailFastMsg(!instr->IsLowered(), "Lowered instruction detected in pre-lower context!");
+
         this->currentInstr = instr;
         this->currentRegion = this->currentBlock->GetFirstInstr()->AsLabelInstr()->GetRegion();
         

+ 0 - 2
lib/Backend/GlobOptFields.cpp

@@ -3194,8 +3194,6 @@ GlobOpt::UpdateObjPtrValueType(IR::Opnd * opnd, IR::Instr * instr)
             }
             break;
         case Js::TypeIds_Array:
-        case Js::TypeIds_NativeFloatArray:
-        case Js::TypeIds_NativeIntArray:
             // Because array can change type id, we can only make it definite if we are doing array check hoist
             // so that implicit call will be installed between the array checks.
             if (!DoArrayCheckHoist() ||

+ 1 - 0
lib/Backend/IR.h

@@ -486,6 +486,7 @@ public:
     bool            dstIsAlwaysConvertedToNumber : 1;
     bool            isCallInstrProtectedByNoProfileBailout : 1;
     bool            hasSideEffects : 1; // The instruction cannot be dead stored
+    bool            isNonFastPathFrameDisplay : 1;
 protected:
     bool            isCloned:1;
     bool            hasBailOutInfo:1;

+ 9 - 15
lib/Backend/IRBuilder.cpp

@@ -704,7 +704,7 @@ IRBuilder::Build()
             }
         }
 #endif
-        AssertMsg(Js::OpCodeUtil::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
+        AssertOrFailFastMsg(Js::OpCodeUtil::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
 
         uint layoutAndSize = layoutSize * Js::OpLayoutType::Count + Js::OpCodeUtil::GetOpCodeLayout(newOpcode);
         switch(layoutAndSize)
@@ -6824,22 +6824,16 @@ IRBuilder::BuildEmpty(Js::OpCode newOpcode, uint32 offset)
                     Js::Constants::NoByteCodeOffset);
             }
 
-            IR::RegOpnd* tempRegOpnd = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
+            IR::Instr* lfd = IR::Instr::New(
+                Js::OpCode::LdFrameDisplay,
+                this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
+                this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
+                this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
+                this->m_func);
             this->AddInstr(
-                IR::Instr::New(
-                    Js::OpCode::LdFrameDisplay,
-                    tempRegOpnd,
-                    this->BuildSrcOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
-                    this->BuildSrcOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
-                    this->m_func),
-                Js::Constants::NoByteCodeOffset);
-            this->AddInstr(
-                IR::Instr::New(
-                    Js::OpCode::MOV,
-                    this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
-                    tempRegOpnd,
-                    this->m_func),
+                lfd,
                 Js::Constants::NoByteCodeOffset);
+            lfd->isNonFastPathFrameDisplay = true;
         }
         break;
 

+ 1 - 1
lib/Backend/IRBuilderAsmJs.cpp

@@ -144,7 +144,7 @@ IRBuilderAsmJs::Build()
     {
         Assert(newOpcode != Js::OpCodeAsmJs::EndOfBlock);
 
-        AssertMsg(Js::OpCodeUtilAsmJs::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
+        AssertOrFailFastMsg(Js::OpCodeUtilAsmJs::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
 
         uint layoutAndSize = layoutSize * Js::OpLayoutTypeAsmJs::Count + Js::OpCodeUtilAsmJs::GetOpCodeLayout(newOpcode);
         switch (layoutAndSize)

+ 5 - 4
lib/Backend/Lower.cpp

@@ -12884,13 +12884,13 @@ void Lowerer::LowerBoundCheck(IR::Instr *const instr)
         //     jo   $bailOut
         // $bailOut: (insertBeforeInstr)
         Assert(!offsetOpnd || offsetOpnd->GetValue() == offset);
-        IR::RegOpnd *const addResultOpnd = IR::RegOpnd::New(TyMachReg, func);
+        IR::RegOpnd *const addResultOpnd = IR::RegOpnd::New(TyInt32, func);
         autoReuseAddResultOpnd.Initialize(addResultOpnd, func);
         InsertAdd(
             true,
             addResultOpnd,
             rightOpnd,
-            offsetOpnd ? offsetOpnd->UseWithNewType(TyMachReg, func) : IR::IntConstOpnd::New(offset, TyMachReg, func, true),
+            offsetOpnd ? offsetOpnd->UseWithNewType(TyInt32, func) : IR::IntConstOpnd::New(offset, TyInt32, func, true),
             insertBeforeInstr);
         InsertBranch(LowererMD::MDOverflowBranchOpcode, bailOutLabel, insertBeforeInstr);
 
@@ -17114,7 +17114,8 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
 
                     // Convert reg to int32
                     // Note: ToUint32 is implemented as (uint32)ToInt32()
-                    m_lowererMD.EmitLoadInt32(instr, true /*conversionFromObjectAllowed*/);
+                    bool bailOutOnHelperCall = (stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall));
+                    m_lowererMD.EmitLoadInt32(instr, true /*conversionFromObjectAllowed*/, bailOutOnHelperCall, labelHelper);
 
                     // MOV indirOpnd, reg
                     InsertMove(indirOpnd, reg, stElem);
@@ -23522,7 +23523,7 @@ void Lowerer::LowerLdFrameDisplay(IR::Instr *instr, bool doStackFrameDisplay)
     // If the dst opnd is a byte code temp, that indicates we're prepending a block scope or some such and
     // shouldn't attempt to do this.
     if (envDepth == (uint16)-1 ||
-        (!doStackFrameDisplay && instr->GetDst()->AsRegOpnd()->m_sym->IsTempReg(instr->m_func)) ||
+        (!doStackFrameDisplay && (instr->isNonFastPathFrameDisplay || instr->GetDst()->AsRegOpnd()->m_sym->IsTempReg(instr->m_func))) ||
         PHASE_OFF(Js::FrameDisplayFastPathPhase, func))
     {
         if (isStrict)

+ 2 - 2
lib/Backend/LowerMDShared.cpp

@@ -7999,9 +7999,9 @@ LowererMD::EmitLoadVar(IR::Instr *instrLoad, bool isFromUint32, bool isHelper)
 }
 
 bool
-LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
+LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOutOnHelper, IR::LabelInstr * labelBailOut)
 {
-    return lowererMDArch.EmitLoadInt32(instrLoad, conversionFromObjectAllowed);
+    return lowererMDArch.EmitLoadInt32(instrLoad, conversionFromObjectAllowed, bailOutOnHelper, labelBailOut);
 }
 
 void

+ 1 - 1
lib/Backend/LowerMDShared.h

@@ -211,7 +211,7 @@ public:
      static void            EmitPtrInstr(IR::Instr *instr);
             void            EmitLoadVar(IR::Instr *instr, bool isFromUint32 = false, bool isHelper = false);
             void            EmitLoadVarNoCheck(IR::RegOpnd * dst, IR::RegOpnd * src, IR::Instr *instrLoad, bool isFromUint32, bool isHelper);
-            bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed);
+            bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed, bool bailOutOnHelper = false, IR::LabelInstr * labelBailOut = nullptr);
             void            EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void            EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void            EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);

+ 36 - 5
lib/Backend/amd64/LowererMDArch.cpp

@@ -1183,7 +1183,9 @@ LowererMDArch::LowerAsmJsLdElemHelper(IR::Instr * instr, bool isSimdLoad /*= fal
             // MOV tmp, cmpOnd
             Lowerer::InsertMove(tmp, cmpOpnd, helperLabel);
             // ADD tmp, dataWidth
-            Lowerer::InsertAdd(false, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+            Lowerer::InsertAdd(true, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+            // JB helper
+            Lowerer::InsertBranch(Js::OpCode::JB, helperLabel, helperLabel);
             // CMP tmp, size
             // JG  $helper
             lowererMD->m_lowerer->InsertCompareBranch(tmp, instr->UnlinkSrc2(), Js::OpCode::BrGt_A, true, helperLabel, helperLabel);
@@ -1259,7 +1261,9 @@ LowererMDArch::LowerAsmJsStElemHelper(IR::Instr * instr, bool isSimdStore /*= fa
             // MOV tmp, cmpOnd
             Lowerer::InsertMove(tmp, cmpOpnd, helperLabel);
             // ADD tmp, dataWidth
-            Lowerer::InsertAdd(false, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+            Lowerer::InsertAdd(true, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+            // JB helper
+            Lowerer::InsertBranch(Js::OpCode::JB, helperLabel, helperLabel);
             // CMP tmp, size
             // JG  $helper
             lowererMD->m_lowerer->InsertCompareBranch(tmp, instr->UnlinkSrc2(), Js::OpCode::BrGt_A, true, helperLabel, helperLabel);
@@ -2611,7 +2615,7 @@ LowererMDArch::EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrIns
 }
 
 bool
-LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
+LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOutOnHelper, IR::LabelInstr * labelBailOut)
 {
     //
     //    r1 = MOV src1
@@ -2664,8 +2668,29 @@ LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllo
         (src1ValueType.IsLikelyFloat() || src1ValueType.IsLikelyUntaggedInt()) &&
                 !(instrLoad->HasBailOutInfo() && (instrLoad->GetBailOutKind() == IR::BailOutIntOnly || instrLoad->GetBailOutKind() == IR::BailOutExpectingInteger));
 
-    if (!isNotInt)
+    if (isNotInt)
     {
+        // Known to be non-integer. If we are required to bail out on helper call, just re-jit.
+        if (!doFloatToIntFastPath && bailOutOnHelper)
+        {
+            if(!GlobOpt::DoAggressiveIntTypeSpec(this->m_func))
+            {
+                // Aggressive int type specialization is already off for some reason. Prevent trying to rejit again
+                // because it won't help and the same thing will happen again. Just abort jitting this function.
+                if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
+                {
+                    Output::Print(_u("    Aborting JIT because AggressiveIntTypeSpec is already off\n"));
+                    Output::Flush();
+                }
+                throw Js::OperationAbortedException();
+            }
+
+            throw Js::RejitException(RejitReason::AggressiveIntTypeSpecDisabled);
+        }
+    }
+    else
+    {
+        // It could be an integer in this case.
         if (!isInt)
         {
             if(doFloatToIntFastPath)
@@ -2753,7 +2778,13 @@ LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllo
             return true;
         }
 
-        if (conversionFromObjectAllowed)
+        if (bailOutOnHelper)
+        {
+            Assert(labelBailOut);
+            lowererMD->m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrLoad);
+            instrLoad->Remove();
+        }
+        else if (conversionFromObjectAllowed)
         {
             lowererMD->m_lowerer->LowerUnaryHelperMem(instrLoad, IR::HelperConv_ToInt32);
         }

+ 1 - 1
lib/Backend/amd64/LowererMDArch.h

@@ -97,7 +97,7 @@ public:
     void                EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
     void                EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
     void                EmitLongToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
-    bool                EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed);
+    bool                EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOnHelperCall, IR::LabelInstr * labelBailOut);
 
     IR::Instr *         LoadCheckedFloat(IR::RegOpnd *opndOrig, IR::RegOpnd *opndFloat, IR::LabelInstr *labelInline, IR::LabelInstr *labelHelper, IR::Instr *instrInsert, const bool checkForNullInLoopBody = false);
 

+ 30 - 3
lib/Backend/arm/LowerMD.cpp

@@ -7342,7 +7342,7 @@ LowererMD::EmitLoadVarNoCheck(IR::RegOpnd * dst, IR::RegOpnd * src, IR::Instr *i
 }
 
 bool
-LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
+LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOutOnHelper, IR::LabelInstr * labelBailOut)
 {
     // isInt:
     //   dst = ASR r1, AtomTag
@@ -7386,8 +7386,29 @@ LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
             (src1ValueType.IsLikelyFloat() || src1ValueType.IsLikelyUntaggedInt()) &&
             !(instrLoad->HasBailOutInfo() && (instrLoad->GetBailOutKind() == IR::BailOutIntOnly || instrLoad->GetBailOutKind() == IR::BailOutExpectingInteger));
 
-        if (!isNotInt)
+        if (isNotInt)
         {
+            // Known to be non-integer. If we are required to bail out on helper call, just re-jit.
+            if (!doFloatToIntFastPath && bailOutOnHelper)
+            {
+                if(!GlobOpt::DoAggressiveIntTypeSpec(this->m_func))
+                {
+                    // Aggressive int type specialization is already off for some reason. Prevent trying to rejit again
+                    // because it won't help and the same thing will happen again. Just abort jitting this function.
+                    if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
+                    {
+                        Output::Print(_u("    Aborting JIT because AggressiveIntTypeSpec is already off\n"));
+                        Output::Flush();
+                    }
+                    throw Js::OperationAbortedException();
+                }
+
+                throw Js::RejitException(RejitReason::AggressiveIntTypeSpecDisabled);
+            }
+        }
+        else
+        {
+            // Could be an integer in this case.
             if (!isInt)
             {
                 if(doFloatToIntFastPath)
@@ -7444,7 +7465,13 @@ LowererMD::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
             return true;
         }
 
-        if (conversionFromObjectAllowed)
+        if (bailOutOnHelper)
+        {
+            Assert(labelBailOut);
+            this->m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrLoad);
+            instrLoad->Remove();
+        }
+        else if (conversionFromObjectAllowed)
         {
             this->m_lowerer->LowerUnaryHelperMem(instrLoad, IR::HelperConv_ToInt32);
         }

+ 1 - 1
lib/Backend/arm/LowerMD.h

@@ -144,7 +144,7 @@ public:
      static void            EmitInt4Instr(IR::Instr *instr);
      static void            EmitPtrInstr(IR::Instr *instr);
             void            EmitLoadVar(IR::Instr *instr, bool isFromUint32 = false, bool isHelper = false);
-            bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed);
+            bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed, bool bailOutOnHelper = false, IR::LabelInstr * labelBailOut = nullptr);
             IR::Instr *     LowerInt64Assign(IR::Instr * instr) { Assert(UNREACHED); return nullptr; }
 
      static void            LowerInt4NegWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel);

+ 1 - 1
lib/Backend/arm64/LowerMD.h

@@ -140,7 +140,7 @@ public:
        static void            EmitInt4Instr(IR::Instr *instr) { __debugbreak(); }
        static void            EmitPtrInstr(IR::Instr *instr) { __debugbreak(); }
               void            EmitLoadVar(IR::Instr *instr, bool isFromUint32 = false, bool isHelper = false) { __debugbreak(); }
-              bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed) { __debugbreak(); return 0; }
+              bool            EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed, bool bailOutOnHelper = false, IR::LabelInstr * labelBailOut = nullptr) { __debugbreak(); return 0; }
               IR::Instr *     LowerInt64Assign(IR::Instr * instr) { __debugbreak(); return nullptr; }
 
        static void            LowerInt4NegWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel) { __debugbreak(); }

+ 36 - 6
lib/Backend/i386/LowererMDArch.cpp

@@ -1027,7 +1027,9 @@ LowererMDArch::LowerAsmJsLdElemHelper(IR::Instr * instr, bool isSimdLoad /*= fal
         // MOV tmp, cmpOnd
         Lowerer::InsertMove(tmp, cmpOpnd, helperLabel);
         // ADD tmp, dataWidth
-        Lowerer::InsertAdd(false, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+        Lowerer::InsertAdd(true, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+        // JB helper
+        Lowerer::InsertBranch(Js::OpCode::JB, helperLabel, helperLabel);
         // CMP tmp, size
         // JG  $helper
         lowererMD->m_lowerer->InsertCompareBranch(tmp, instr->UnlinkSrc2(), Js::OpCode::BrGt_A, true, helperLabel, helperLabel);
@@ -1087,7 +1089,9 @@ LowererMDArch::LowerAsmJsStElemHelper(IR::Instr * instr, bool isSimdStore /*= fa
         // MOV tmp, cmpOnd
         Lowerer::InsertMove(tmp, cmpOpnd, helperLabel);
         // ADD tmp, dataWidth
-        Lowerer::InsertAdd(false, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+        Lowerer::InsertAdd(true, tmp, tmp, IR::IntConstOpnd::New((uint32)dataWidth, tmp->GetType(), m_func, true), helperLabel);
+        // JB helper
+        Lowerer::InsertBranch(Js::OpCode::JB, helperLabel, helperLabel);
         // CMP tmp, size
         // JG  $helper
         lowererMD->m_lowerer->InsertCompareBranch(tmp, instr->UnlinkSrc2(), Js::OpCode::BrGt_A, true, helperLabel, helperLabel);
@@ -2605,7 +2609,7 @@ LowererMDArch::EmitLongToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInser
 }
 
 bool
-LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed)
+LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOutOnHelper, IR::LabelInstr * labelBailOut)
 {
     // if(doShiftFirst)
     // {
@@ -2663,9 +2667,29 @@ LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllo
         instrLoad->InsertBefore(instr);
     }
 
-    // It could be an integer in this case
-    if (!isNotInt)
+    if (isNotInt)
     {
+        // Known to be non-integer. If we are required to bail out on helper call, just re-jit.
+        if (!doFloatToIntFastPath && bailOutOnHelper)
+        {
+            if(!GlobOpt::DoAggressiveIntTypeSpec(this->m_func))
+            {
+                // Aggressive int type specialization is already off for some reason. Prevent trying to rejit again
+                // because it won't help and the same thing will happen again. Just abort jitting this function.
+                if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
+                {
+                    Output::Print(_u("    Aborting JIT because AggressiveIntTypeSpec is already off\n"));
+                    Output::Flush();
+                }
+                throw Js::OperationAbortedException();
+            }
+
+            throw Js::RejitException(RejitReason::AggressiveIntTypeSpecDisabled);
+        }
+    }
+    else
+    {
+        // It could be an integer in this case
         if(doShiftFirst)
         {
             // r1 = SAR r1, VarTag_Shift (move last-shifted bit into CF)
@@ -2781,7 +2805,13 @@ LowererMDArch::EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllo
             return true;
         }
 
-        if (conversionFromObjectAllowed)
+        if (bailOutOnHelper)
+        {
+            Assert(labelBailOut);
+            lowererMD->m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrLoad);
+            instrLoad->Remove();
+        }
+        else if (conversionFromObjectAllowed)
         {
             lowererMD->m_lowerer->LowerUnaryHelperMem(instrLoad, IR::HelperConv_ToInt32);
         }

+ 1 - 1
lib/Backend/i386/LowererMDArch.h

@@ -85,7 +85,7 @@ public:
             void                EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void                EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void                EmitLongToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
-            bool                EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed);
+            bool                EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed, bool bailOutOnHelper = false, IR::LabelInstr * labelBailOut = nullptr);
 
             IR::Instr *         LoadCheckedFloat(IR::RegOpnd *opndOrig, IR::RegOpnd *opndFloat, IR::LabelInstr *labelInline, IR::LabelInstr *labelHelper, IR::Instr *instrInsert, const bool checkForNullInLoopBody = false);
 

+ 33 - 0
lib/Parser/Parse.cpp

@@ -2863,6 +2863,7 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
     _Inout_opt_ charcount_t *plastRParen /*= nullptr*/)
 {
     ParseNodePtr pnode = nullptr;
+    PidRefStack *savedTopAsyncRef = nullptr;
     charcount_t ichMin = 0;
     size_t iecpMin = 0;
     size_t iuMin;
@@ -2915,6 +2916,13 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
                 isLambdaExpr = true;
                 goto LFunction;
             }
+            else if (m_token.tk == tkLParen)
+            {
+                // This is potentially an async arrow function. Save the state of the async references
+                // in case it needs to be restored. (Note that the case of a single parameter with no ()'s
+                // is detected upstream and need not be handled here.)
+                savedTopAsyncRef = pid->GetTopRef();
+            }
         }
 
         // Don't push a reference if this is a single lambda parameter, because we'll reparse with
@@ -3269,6 +3277,18 @@ LFunction :
 
     pnode = ParsePostfixOperators<buildAST>(pnode, fAllowCall, fInNew, isAsyncExpr, &fCanAssign, &term, pfIsDotOrIndex);
 
+    if (savedTopAsyncRef != nullptr &&
+        this->m_token.tk == tkDArrow)
+    {
+        // This is an async arrow function; we're going to back up and reparse it.
+        // Make sure we don't leave behind a bogus reference to the 'async' identifier.
+        for (IdentPtr pid = wellKnownPropertyPids.async; pid->GetTopRef() != savedTopAsyncRef;)
+        {
+            Assert(pid->GetTopRef() != nullptr);
+            pid->RemovePrevPidRef(nullptr);
+        }
+    }
+
     // Pass back identifier if requested
     if (pToken && term.tk == tkID)
     {
@@ -5178,6 +5198,19 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
                         paramScope->SetCannotMergeWithBodyScope();
                     }
                 }
+                if (paramScope->GetCanMergeWithBodyScope() && !fDeclaration && pnodeFnc->sxFnc.pnodeName != nullptr)
+                {
+                    Symbol* funcSym = pnodeFnc->sxFnc.pnodeName->sxVar.sym;
+                    if (funcSym->GetPid()->GetTopRef()->GetFuncScopeId() > pnodeFnc->sxFnc.functionId)
+                    {
+                        // This is a function expression with name captured in the param scope. In non-eval, non-split cases the function
+                        // name symbol is added to the body scope to make it accessible in the body. But if there is a function or var
+                        // declaration with the same name in the body then adding to the body will fail. So in this case we have to add
+                        // the name symbol to the param scope by splitting it.
+                        paramScope->SetCannotMergeWithBodyScope();
+                    }
+                }
+
             }
         }
 

+ 3 - 3
lib/Runtime/Base/Debug.cpp

@@ -32,16 +32,16 @@ WCHAR* DumpCallStackFull(uint frameCount, bool print)
             Js::JavascriptFunction *jsFunc = walker.GetCurrentFunction();
 
             Js::FunctionBody * jsBody = jsFunc->GetFunctionBody();
-            Js::CallInfo const * callInfo = walker.GetCallInfo();
+            const Js::CallInfo callInfo = walker.GetCallInfo();
             const WCHAR* sourceFileName = _u("NULL");
             ULONG line = 0; LONG column = 0;
             walker.GetSourcePosition(&sourceFileName, &line, &column);
 
             StringCchPrintf(buffer, _countof(buffer), _u("%s [%s] (0x%p, Args=%u"), jsBody->GetDisplayName(), jsBody->GetDebugNumberSet(debugStringBuffer), jsFunc,
-                callInfo->Count);
+                callInfo.Count);
             sb.AppendSz(buffer);
 
-            for (uint i = 0; i < callInfo->Count; i++)
+            for (uint i = 0; i < callInfo.Count; i++)
             {
                 StringCchPrintf(buffer, _countof(buffer), _u(", 0x%p"), walker.GetJavascriptArgs()[i]);
                 sb.AppendSz(buffer);

+ 181 - 168
lib/Runtime/Base/FunctionBody.cpp

@@ -2146,6 +2146,7 @@ namespace Js
             return GetFunctionBody();
         }
 
+        bool asmjsParseFailed = false;
         BOOL fParsed = FALSE;
         FunctionBody* returnFunctionBody = nullptr;
         ENTER_PINNED_SCOPE(Js::PropertyRecordList, propertyRecordList);
@@ -2155,227 +2156,232 @@ namespace Js
         bool isDebugOrAsmJsReparse = false;
         FunctionBody* funcBody = nullptr;
 
-        AutoRestoreFunctionInfo autoRestoreFunctionInfo(this, DefaultEntryThunk);
-
-        // If m_hasBeenParsed = true, one of the following things happened:
-        // - We had multiple function objects which were all defer-parsed, but with the same function body and one of them
-        //   got the body to be parsed before another was called
-        // - We are in debug mode and had our thunks switched to DeferParseThunk
-        // - This is an already parsed asm.js module, which has been invalidated at link time and must be reparsed as a non-asm.js function
-        if (!this->m_hasBeenParsed)
         {
+            AutoRestoreFunctionInfo autoRestoreFunctionInfo(this, DefaultEntryThunk);
+            
+
+            // If m_hasBeenParsed = true, one of the following things happened things happened:
+            // - We had multiple function objects which were all defer-parsed, but with the same function body and one of them
+            //   got the body to be parsed before another was called
+            // - We are in debug mode and had our thunks switched to DeferParseThunk
+            // - This is an already parsed asm.js module, which has been invalidated at link time and must be reparsed as a non-asm.js function
+            if (!this->m_hasBeenParsed)
+            {
             this->GetUtf8SourceInfo()->StopTrackingDeferredFunction(this->GetLocalFunctionId());
             funcBody = FunctionBody::NewFromParseableFunctionInfo(this, propertyRecordList);
-            autoRestoreFunctionInfo.funcBody = funcBody;
+                autoRestoreFunctionInfo.funcBody = funcBody;
 
-            PERF_COUNTER_DEC(Code, DeferredFunction);
-
-            if (!this->GetSourceContextInfo()->IsDynamic())
-            {
-                PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d; Is Top Level: %s; Source Url: %s\n"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"), this->GetSourceContextInfo()->url);
-            }
-            else
-            {
-                PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d\n; Is Top Level: %s;"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(),  this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"));
-            }
+                PERF_COUNTER_DEC(Code, DeferredFunction);
 
-            if (!this->GetIsTopLevel() &&
-                !this->GetSourceContextInfo()->IsDynamic() &&
-                this->m_scriptContext->DoUndeferGlobalFunctions())
-            {
-                this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](const Utf8SourceInfo::DeferredFunctionsDictionary::EntryType& func)
+                if (!this->GetSourceContextInfo()->IsDynamic())
+                {
+                    PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d; Is Top Level: %s; Source Url: %s\n"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"), this->GetSourceContextInfo()->url);
+                }
+                else
                 {
-                    Js::ParseableFunctionInfo *nextFunc = func.Value();
-                    JavascriptExceptionObject* pExceptionObject = nullptr;
+                    PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d\n; Is Top Level: %s;"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(),  this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"));
+                }
 
-                    if (nextFunc != nullptr && this != nextFunc)
+                if (!this->GetIsTopLevel() &&
+                    !this->GetSourceContextInfo()->IsDynamic() &&
+                    this->m_scriptContext->DoUndeferGlobalFunctions())
+                {
+                    this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](const Utf8SourceInfo::DeferredFunctionsDictionary::EntryType& func)
                     {
-                        try
-                        {
-                            nextFunc->Parse();
-                        }
-                        catch (OutOfMemoryException) {}
-                        catch (StackOverflowException) {}
-                        catch (const Js::JavascriptException& err)
-                        {
-                            pExceptionObject = err.GetAndClear();
-                        }
+                        Js::ParseableFunctionInfo *nextFunc = func.Value();
+                        JavascriptExceptionObject* pExceptionObject = nullptr;
 
-                        // Do not do anything with an OOM or SOE, returning true is fine, it will then be undeferred (or attempted to again when called)
-                        if(pExceptionObject)
+                        if (nextFunc != nullptr && this != nextFunc)
                         {
-                            if(pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingOOMErrorObject() &&
-                                pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingSOErrorObject())
+                            try
                             {
-                                JavascriptExceptionOperators::DoThrow(pExceptionObject, /*scriptContext*/nullptr);
+                                nextFunc->Parse();
+                            }
+                            catch (OutOfMemoryException) {}
+                            catch (StackOverflowException) {}
+                            catch (const Js::JavascriptException& err)
+                            {
+                                pExceptionObject = err.GetAndClear();
+                            }
+
+                            // Do not do anything with an OOM or SOE, returning true is fine, it will then be undeferred (or attempted to again when called)
+                            if (pExceptionObject)
+                            {
+                                if (pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingOOMErrorObject() &&
+                                    pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingSOErrorObject())
+                                {
+                                    JavascriptExceptionOperators::DoThrow(pExceptionObject, /*scriptContext*/nullptr);
+                                }
                             }
                         }
-                    }
 
-                    return true;
-                });
+                        return true;
+                    });
+                }
             }
-        }
-        else
-        {
-            bool isDebugReparse = m_scriptContext->IsScriptContextInSourceRundownOrDebugMode() && !this->GetUtf8SourceInfo()->GetIsLibraryCode();
-            bool isAsmJsReparse = m_isAsmjsMode && !isDebugReparse;
-
-            isDebugOrAsmJsReparse = isAsmJsReparse || isDebugReparse;
+            else
+            {
+                bool isDebugReparse = m_scriptContext->IsScriptContextInSourceRundownOrDebugMode() && !this->GetUtf8SourceInfo()->GetIsLibraryCode();
+                bool isAsmJsReparse = m_isAsmjsMode && !isDebugReparse;
 
-            funcBody = this->GetFunctionBody();
+                isDebugOrAsmJsReparse = isAsmJsReparse || isDebugReparse;
 
-            if (isDebugOrAsmJsReparse)
-            {
-    #if ENABLE_DEBUG_CONFIG_OPTIONS
-                char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-    #endif
-    #if DBG
-                Assert(
-                    funcBody->IsReparsed()
-                    || m_scriptContext->IsScriptContextInSourceRundownOrDebugMode()
-                    || m_isAsmjsMode);
-    #endif
-                OUTPUT_TRACE(Js::DebuggerPhase, _u("Full nested reparse of function: %s (%s)\n"), funcBody->GetDisplayName(), funcBody->GetDebugNumberSet(debugStringBuffer));
+                funcBody = this->GetFunctionBody();
 
-                if (funcBody->GetByteCode())
+                if (isDebugOrAsmJsReparse)
                 {
-                    // The current function needs to be cleaned up before getting generated in the debug mode.
-                    funcBody->CleanupToReparse();
-                }
+#if ENABLE_DEBUG_CONFIG_OPTIONS
+                    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+#endif
+#if DBG
+                    Assert(
+                        funcBody->IsReparsed()
+                        || m_scriptContext->IsScriptContextInSourceRundownOrDebugMode()
+                        || m_isAsmjsMode);
+#endif
+                    OUTPUT_TRACE(Js::DebuggerPhase, _u("Full nested reparse of function: %s (%s)\n"), funcBody->GetDisplayName(), funcBody->GetDebugNumberSet(debugStringBuffer));
 
+                    if (funcBody->GetByteCode())
+                    {
+                        // The current function needs to be cleaned up before getting generated in the debug mode.
+                        funcBody->CleanupToReparse();
+                    }
+
+                }
             }
-        }
 
-        // Note that we may be trying to re-gen an already-completed function. (This can happen, for instance,
-        // in the case of named function expressions inside "with" statements in compat mode.)
-        // In such a case, there's no work to do.
-        if (funcBody->GetByteCode() == nullptr)
-        {
+            // Note that we may be trying to re-gen an already-completed function. (This can happen, for instance,
+            // in the case of named function expressions inside "with" statements in compat mode.)
+            // In such a case, there's no work to do.
+            if (funcBody->GetByteCode() == nullptr)
+            {
 #if ENABLE_PROFILE_INFO
-            Assert(!funcBody->HasExecutionDynamicProfileInfo());
+                Assert(!funcBody->HasExecutionDynamicProfileInfo());
 #endif
-            // In debug or asm.js mode, the scriptlet will be asked to recompile again.
-            AssertMsg(isDebugOrAsmJsReparse || funcBody->GetGrfscr() & fscrGlobalCode || CONFIG_FLAG(DeferNested), "Deferred parsing of non-global procedure?");
-
-            HRESULT hr = NO_ERROR;
-            HRESULT hrParser = NO_ERROR;
-            HRESULT hrParseCodeGen = NO_ERROR;
+                // In debug or asm.js mode, the scriptlet will be asked to recompile again.
+                AssertMsg(isDebugOrAsmJsReparse || funcBody->GetGrfscr() & fscrGlobalCode || CONFIG_FLAG(DeferNested), "Deferred parsing of non-global procedure?");
 
-            BEGIN_LEAVE_SCRIPT_INTERNAL(m_scriptContext)
-            {
-                bool isCesu8 = m_scriptContext->GetSource(funcBody->GetSourceIndex())->IsCesu8();
-
-                size_t offset = this->StartOffset();
-                charcount_t charOffset = this->StartInDocument();
-                size_t length = this->LengthInBytes();
-
-                LPCUTF8 pszStart = this->GetStartOfDocument();
-
-                uint32 grfscr = funcBody->GetGrfscr() | fscrDeferredFnc;
+                HRESULT hr = NO_ERROR;
+                HRESULT hrParser = NO_ERROR;
+                HRESULT hrParseCodeGen = NO_ERROR;
 
-                // For the global function we want to re-use the glo functionbody which is already created in the non-debug mode
-                if (!funcBody->GetIsGlobalFunc())
+                BEGIN_LEAVE_SCRIPT_INTERNAL(m_scriptContext)
                 {
-                    grfscr &= ~fscrGlobalCode;
-                }
+                    bool isCesu8 = m_scriptContext->GetSource(funcBody->GetSourceIndex())->IsCesu8();
 
-                if (!funcBody->GetIsDeclaration() && !funcBody->GetIsGlobalFunc()) // No refresh may reparse global function (e.g. eval code)
-                {
-                    // Notify the parser that the top-level function was defined in an expression,
-                    // (not a function declaration statement).
-                    grfscr |= fscrDeferredFncExpression;
-                }
-                if (!CONFIG_FLAG(DeferNested) || isDebugOrAsmJsReparse)
-                {
-                    grfscr &= ~fscrDeferFncParse; // Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
-                }
+                    size_t offset = this->StartOffset();
+                    charcount_t charOffset = this->StartInDocument();
+                    size_t length = this->LengthInBytes();
 
-                if (isDebugOrAsmJsReparse)
-                {
-                    grfscr |= fscrNoAsmJs; // Disable asm.js when debugging or if linking failed
-                }
+                    LPCUTF8 pszStart = this->GetStartOfDocument();
 
-                BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
-                {
-                    CompileScriptException se;
-                    Parser ps(m_scriptContext, funcBody->GetIsStrictMode() ? TRUE : FALSE);
-                    ParseNodePtr parseTree;
+                    uint32 grfscr = funcBody->GetGrfscr() | fscrDeferredFnc;
 
-                    uint nextFunctionId = funcBody->GetLocalFunctionId();
-                    hrParser = ps.ParseSourceWithOffset(&parseTree, pszStart, offset, length, charOffset, isCesu8, grfscr, &se,
-                        &nextFunctionId, funcBody->GetRelativeLineNumber(), funcBody->GetSourceContextInfo(),
-                        funcBody);
-//                    Assert(FAILED(hrParser) || nextFunctionId == funcBody->deferredParseNextFunctionId || isDebugOrAsmJsReparse || isByteCodeDeserialization);
+                    // For the global function we want to re-use the glo functionbody which is already created in the non-debug mode
+                    if (!funcBody->GetIsGlobalFunc())
+                    {
+                        grfscr &= ~fscrGlobalCode;
+                    }
 
-                    if (FAILED(hrParser))
+                    if (!funcBody->GetIsDeclaration() && !funcBody->GetIsGlobalFunc()) // No refresh may reparse global function (e.g. eval code)
                     {
-                        hrParseCodeGen = MapDeferredReparseError(hrParser, se); // Map certain errors like OOM/SOE
-                        AssertMsg(FAILED(hrParseCodeGen) && SUCCEEDED(hrParser), "Syntax errors should never be detected on deferred re-parse");
+                        // Notify the parser that the top-level function was defined in an expression,
+                        // (not a function declaration statement).
+                        grfscr |= fscrDeferredFncExpression;
                     }
-                    else
+                    if (!CONFIG_FLAG(DeferNested) || isDebugOrAsmJsReparse)
                     {
-                        TRACE_BYTECODE(_u("\nDeferred parse %s\n"), funcBody->GetDisplayName());
-                        Js::AutoDynamicCodeReference dynamicFunctionReference(m_scriptContext);
+                        grfscr &= ~fscrDeferFncParse; // Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
+                    }
 
-                        bool forceNoNative = isDebugOrAsmJsReparse ? this->GetScriptContext()->IsInterpreted() : false;
+                    if (isDebugOrAsmJsReparse)
+                    {
+                        grfscr |= fscrNoAsmJs; // Disable asm.js when debugging or if linking failed
+                    }
 
-                        ParseableFunctionInfo* rootFunc = funcBody->GetParseableFunctionInfo();
-                        hrParseCodeGen = GenerateByteCode(parseTree, grfscr, m_scriptContext,
-                            &rootFunc, funcBody->GetSourceIndex(),
-                            forceNoNative, &ps, &se, funcBody->GetScopeInfo(), functionRef);
-                        funcBody->SetParseableFunctionInfo(rootFunc);
+                    BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
+                    {
+                        CompileScriptException se;
+                        Parser ps(m_scriptContext, funcBody->GetIsStrictMode() ? TRUE : FALSE);
+                        ParseNodePtr parseTree;
 
-                        if (se.ei.scode == JSERR_AsmJsCompileError)
-                        {
-                            // if asm.js compilation failed, reparse without asm.js
-                            m_grfscr |= fscrNoAsmJs;
-                            se.Clear();
-                            return Parse(functionRef, isByteCodeDeserialization);
-                        }
+                        uint nextFunctionId = funcBody->GetLocalFunctionId();
+                        hrParser = ps.ParseSourceWithOffset(&parseTree, pszStart, offset, length, charOffset, isCesu8, grfscr, &se,
+                            &nextFunctionId, funcBody->GetRelativeLineNumber(), funcBody->GetSourceContextInfo(),
+                            funcBody);
+                        // Assert(FAILED(hrParser) || nextFunctionId == funcBody->deferredParseNextFunctionId || isDebugOrAsmJsReparse || isByteCodeDeserialization);
 
-                        if (SUCCEEDED(hrParseCodeGen))
+                        if (FAILED(hrParser))
                         {
-                            fParsed = TRUE;
+                            hrParseCodeGen = MapDeferredReparseError(hrParser, se); // Map certain errors like OOM/SOE
+                            AssertMsg(FAILED(hrParseCodeGen) && SUCCEEDED(hrParser), "Syntax errors should never be detected on deferred re-parse");
                         }
                         else
                         {
-                            Assert(hrParseCodeGen == SCRIPT_E_RECORDED);
-                            hrParseCodeGen = se.ei.scode;
+                            TRACE_BYTECODE(_u("\nDeferred parse %s\n"), funcBody->GetDisplayName());
+                            Js::AutoDynamicCodeReference dynamicFunctionReference(m_scriptContext);
+
+                            bool forceNoNative = isDebugOrAsmJsReparse ? this->GetScriptContext()->IsInterpreted() : false;
+
+                            ParseableFunctionInfo* rootFunc = funcBody->GetParseableFunctionInfo();
+                            hrParseCodeGen = GenerateByteCode(parseTree, grfscr, m_scriptContext,
+                                &rootFunc, funcBody->GetSourceIndex(),
+                                forceNoNative, &ps, &se, funcBody->GetScopeInfo(), functionRef);
+                            funcBody->SetParseableFunctionInfo(rootFunc);
+
+                            if (SUCCEEDED(hrParseCodeGen))
+                            {
+                                fParsed = TRUE;
+                            }
+                            else
+                            {
+                                Assert(hrParseCodeGen == SCRIPT_E_RECORDED);
+                                hrParseCodeGen = se.ei.scode;
+                            }
                         }
                     }
+                    END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
                 }
-                END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
-            }
-            END_LEAVE_SCRIPT_INTERNAL(m_scriptContext);
+                END_LEAVE_SCRIPT_INTERNAL(m_scriptContext);
 
-            THROW_KNOWN_HRESULT_EXCEPTIONS(hr, m_scriptContext);
+                THROW_KNOWN_HRESULT_EXCEPTIONS(hr, m_scriptContext);
 
-            Assert(hr == NO_ERROR);
+                Assert(hr == NO_ERROR);
 
-            if (!SUCCEEDED(hrParser))
+                if (!SUCCEEDED(hrParser))
+                {
+                    JavascriptError::ThrowError(m_scriptContext, VBSERR_InternalError);
+                }
+                else if (!SUCCEEDED(hrParseCodeGen))
+                {
+                    /*
+                     * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
+                     * overflow occurs. To keep the behavior consistent I'm special casing it here.
+                     */
+                    if (hrParseCodeGen == VBSERR_OutOfStack)
+                    {
+                        JavascriptError::ThrowStackOverflowError(m_scriptContext);
+                    }
+                    else if (hrParseCodeGen == JSERR_AsmJsCompileError)
+                    {
+                        asmjsParseFailed = true;
+                    }
+                    else
+                    {
+                        JavascriptError::MapAndThrowError(m_scriptContext, hrParseCodeGen);
+                    }
+                }
+            }
+            else
             {
-                JavascriptError::ThrowError(m_scriptContext, VBSERR_InternalError);
+                fParsed = FALSE;
             }
-            else if (!SUCCEEDED(hrParseCodeGen))
+
+            if (!asmjsParseFailed)
             {
-                /*
-                    * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
-                    * overflow occurs. To keep the behavior consistent I'm special casing it here.
-                    */
-                if (hrParseCodeGen == VBSERR_OutOfStack)
-                {
-                    JavascriptError::ThrowStackOverflowError(m_scriptContext);
-                }
-                JavascriptError::MapAndThrowError(m_scriptContext, hrParseCodeGen);
+                autoRestoreFunctionInfo.Clear();
             }
         }
-        else
-        {
-            fParsed = FALSE;
-        }
-
-        autoRestoreFunctionInfo.Clear();
 
         if (fParsed == TRUE)
         {
@@ -2385,13 +2391,20 @@ namespace Js
             this->m_hasBeenParsed = true;
             returnFunctionBody = funcBody;
         }
-        else
+        else if(!asmjsParseFailed)
         {
             returnFunctionBody = this->GetFunctionBody();
         }
 
         LEAVE_PINNED_SCOPE();
 
+        if (asmjsParseFailed)
+        {
+            // disable asm.js and reparse on failure
+            m_grfscr |= fscrNoAsmJs;
+            return Parse(functionRef, isByteCodeDeserialization);
+        }
+
         return returnFunctionBody;
     }
 

+ 5 - 1
lib/Runtime/Base/ScriptContext.cpp

@@ -293,7 +293,7 @@ namespace Js
         CleanupDocumentContext = nullptr;
 #endif
 
-        // Do this after all operations that may cause potential exceptions
+        // Do this after all operations that may cause potential exceptions. Note: InitialAllocations may still throw!
         threadContext->RegisterScriptContext(this);
         numberAllocator.Initialize(this->GetRecycler());
 
@@ -468,6 +468,10 @@ namespace Js
             }
         }
 
+        // Normally the JavascriptLibraryBase will unregister the scriptContext from the threadContext.
+        // In cases where we don't finish initialization e.g. OOM, manually unregister the scriptContext.
+        threadContext->UnregisterScriptContext(this);
+
 #if ENABLE_BACKGROUND_PARSING
         if (this->backgroundParser != nullptr)
         {

+ 6 - 3
lib/Runtime/ByteCode/ByteCodeEmitter.cpp

@@ -3320,6 +3320,7 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
         {
             // Emit bytecode to copy the initial values from param names to their corresponding body bindings.
             // We have to do this after the rest param is marked as false for need declaration.
+            Symbol* funcSym = funcInfo->root->sxFnc.GetFuncSymbol();
             paramScope->ForEachSymbol([&](Symbol* param) {
                 Symbol* varSym = funcInfo->GetBodyScope()->FindLocalSymbol(param->GetName());
                 Assert(varSym || pnode->sxFnc.pnodeName->sxVar.sym == param);
@@ -3328,7 +3329,9 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
                 {
                     // Do not copy the arguments to the body if it is not used
                 }
-                else if (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister))
+                else if ((funcSym == nullptr || funcSym != param)    // Do not copy the symbol over to body as the function expression symbol
+                                                                     // is expected to stay inside the function expression scope
+                    && (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister)))
                 {
                     // Simulating EmitPropLoad here. We can't directly call the method as we have to use the param scope specifically.
                     // Walking the scope chain is not possible at this time.
@@ -3634,9 +3637,9 @@ void ByteCodeGenerator::EmitScopeList(ParseNode *pnode, ParseNode *breakOnBodySc
                 {
                     exit(JSERR_AsmJsCompileError);
                 }
-                else if (!(flags & fscrDeferFncParse))
+                else
                 {
-                    // If deferral is not allowed, throw and reparse everything with asm.js disabled.
+                    // if asm.js parse error happened, reparse with asm.js disabled.
                     throw Js::AsmJsParseException();
                 }
             }

+ 1 - 1
lib/Runtime/ByteCode/FuncInfo.cpp

@@ -13,7 +13,7 @@ FuncInfo::FuncInfo(
     Js::ParseableFunctionInfo* byteCodeFunction)
     : alloc(alloc),
     varRegsCount(0),
-    constRegsCount(2),
+    constRegsCount(InitialConstRegsCount),
     inArgsCount(0),
     innerScopeCount(0),
     currentInnerScopeIndex((uint)-1),

+ 2 - 1
lib/Runtime/ByteCode/FuncInfo.h

@@ -83,6 +83,8 @@ private:
     uint        nextForInLoopLevel;
     uint        maxForInLoopLevel;
 public:
+    static const Js::RegSlot InitialConstRegsCount = 2; // constRegsCount is set to 2 because R0 is the return register, and R1 is the root object
+
     ArenaAllocator *alloc;
     // set in Bind/Assign pass
     Js::RegSlot varRegsCount; // number of registers used for non-constants
@@ -192,7 +194,6 @@ public:
     Symbol *innerArgumentsSymbol;
     JsUtil::List<Js::RegSlot, ArenaAllocator> nonUserNonTempRegistersToInitialize;
 
-    // constRegsCount is set to 2 because R0 is the return register, and R1 is the root object.
     FuncInfo(
         const char16 *name,
         ArenaAllocator *alloc,

+ 9 - 1
lib/Runtime/Language/AsmJs.cpp

@@ -919,7 +919,11 @@ varDeclEnd:
     {
         ParseNode* endStmt = m.GetCurrentParserNode();
 
-        Assert( endStmt->nop == knopList );
+        if (endStmt->nop != knopList)
+        {
+            return m.Fail(endStmt, _u("Module must have a return"));
+        }
+
         ParseNode* node = ParserWrapper::GetBinaryLeft( endStmt );
         ParseNode* endNode = ParserWrapper::GetBinaryRight( endStmt );
 
@@ -961,6 +965,10 @@ varDeclEnd:
         }
 
         ParseNode* objectElement = ParserWrapper::GetUnaryNode(objNode);
+        if (!objectElement)
+        {
+            return m.Fail(node, _u("Return object must not be empty"));
+        }
         while( objectElement )
         {
             ParseNode* member = nullptr;

+ 2 - 0
lib/Runtime/Language/AsmJsByteCodeGenerator.cpp

@@ -3324,6 +3324,8 @@ namespace Js
         byteCodeGen->Writer()->EndStatement(functionNode);
         byteCodeGen->Writer()->End();
 
+        functionBody->CheckAndSetConstantCount(FuncInfo::InitialConstRegsCount);
+
         autoCleanup.Done();
     }
 

+ 8 - 3
lib/Runtime/Language/AsmJsModule.cpp

@@ -1091,9 +1091,14 @@ namespace Js
         {
             if( DefineIdentifier( name, func ) )
             {
-                func->SetFunctionIndex( pnodeFnc->sxFnc.nestedIndex );
-                // Add extra check to make sure all the slots between 0 - Count are filled with func;
-                mFunctionArray.SetItem( func->GetFunctionIndex(), func );
+                uint index = (uint)mFunctionArray.Count();
+                if (pnodeFnc->sxFnc.nestedIndex != index)
+                {
+                    return nullptr;
+                }
+                func->SetFunctionIndex( (RegSlot)index );
+                mFunctionArray.Add( func );
+                Assert(index + 1 == (uint)mFunctionArray.Count());
                 return func;
             }
             // Error adding function

+ 7 - 4
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -2768,16 +2768,18 @@ namespace Js
 
                 AsmJsScriptFunction* scriptFuncObj = (AsmJsScriptFunction*)ScriptFunction::OP_NewScFunc(pDisplay, functionInfo);
                 localModuleFunctions[modFunc.location] = scriptFuncObj;
+
+                if (scriptFuncObj->GetDynamicType()->GetEntryPoint() == DefaultDeferredDeserializeThunk)
+                {
+                    JavascriptFunction::DeferredDeserialize(scriptFuncObj);
+                }
+
                 if (i == 0 && info->GetUsesChangeHeap())
                 {
                     scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsChangeHeapBuffer);
                 }
                 else
                 {
-                    if (scriptFuncObj->GetDynamicType()->GetEntryPoint() == DefaultDeferredDeserializeThunk)
-                    {
-                        JavascriptFunction::DeferredDeserialize(scriptFuncObj);
-                    }
                     scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint);
                     scriptFuncObj->GetFunctionBody()->GetAsmJsFunctionInfo()->SetModuleFunctionBody(asmJsModuleFunctionBody);
                 }
@@ -6342,6 +6344,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
                 PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
                 outArgsSize = outArgs.Info.Count * sizeof(Var);
                 outArgs.Values = (Var*)_alloca(outArgsSize);
+                ZeroMemory(outArgs.Values, outArgsSize);
             }
             else
             {

+ 26 - 17
lib/Runtime/Language/JavascriptStackWalker.cpp

@@ -154,7 +154,7 @@ namespace Js
         Assert(IsJavascriptFrame());
         AssertMsg(this->GetCurrentFunction()->IsScriptFunction(), "GetPermanentArguments should not be called for non-script function as there is no slot allocated for it.");
 
-        const uint32 paramCount = GetCallInfo()->Count;
+        const uint32 paramCount = GetCallInfo().Count;
         if (paramCount == 0)
         {
             // glob function doesn't allocate ArgumentsObject slot on stack
@@ -206,8 +206,8 @@ namespace Js
         else
 #endif
         {
-            CallInfo const *callInfo = this->GetCallInfo();
-            if (callInfo->Count == 0)
+            const CallInfo callInfo = this->GetCallInfo();
+            if (callInfo.Count == 0)
             {
                 *pVarThis = JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), moduleId, scriptContext);
                 return false;
@@ -218,14 +218,14 @@ namespace Js
         }
     }
 
-    BOOL IsEval(const CallInfo* callInfo)
+    BOOL IsEval(CallInfo callInfo)
     {
-        return (callInfo->Flags & CallFlags_Eval) != 0;
+        return (callInfo.Flags & CallFlags_Eval) != 0;
     }
 
     BOOL JavascriptStackWalker::IsCallerGlobalFunction() const
     {
-        CallInfo const* callInfo = this->GetCallInfo();
+        const CallInfo callInfo = this->GetCallInfo();
 
         JavascriptFunction* function = this->GetCurrentFunction();
         if (IsLibraryStackFrameEnabled(this->scriptContext) && !function->IsScriptFunction())
@@ -241,14 +241,14 @@ namespace Js
         else
         {
             AssertMsg(FALSE, "Here we should only have script functions which were already parsed/deserialized.");
-            return callInfo->Count == 0 || IsEval(callInfo);
+            return callInfo.Count == 0 || IsEval(callInfo);
         }
     }
 
     BOOL JavascriptStackWalker::IsEvalCaller() const
     {
-        CallInfo const* callInfo = this->GetCallInfo();
-        return (callInfo->Flags & CallFlags_Eval) != 0;
+        const CallInfo callInfo = this->GetCallInfo();
+        return (callInfo.Flags & CallFlags_Eval) != 0;
     }
 
     Var JavascriptStackWalker::GetCurrentNativeArgumentsObject() const
@@ -831,7 +831,7 @@ namespace Js
             if (this->IsJavascriptFrame() && this->GetCurrentFunction() == funcTarget)
             {
                 // Skip internal names
-                Assert( !(this->GetCallInfo()->Flags & CallFlags_InternalFrame) );
+                Assert( !(this->GetCallInfo().Flags & CallFlags_InternalFrame) );
                 return true;
             }
         }
@@ -1008,32 +1008,41 @@ namespace Js
         return GetCurrentFunction(false);
     }
 
-    CallInfo const * JavascriptStackWalker::GetCallInfo(bool includeInlinedFrames /* = true */) const
+    CallInfo JavascriptStackWalker::GetCallInfo(bool includeInlinedFrames /* = true */) const
     {
         Assert(this->IsJavascriptFrame());
+        CallInfo callInfo;
         if (includeInlinedFrames && inlinedFramesBeingWalked)
         {
             // Since we don't support inlining constructors yet, its questionable if we should handle the
             // hidden frame display here?
-            return (CallInfo const *)&inlinedFrameCallInfo;
+            callInfo = inlinedFrameCallInfo;
         }
         else if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine())
         {
             JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]);
-            return &gen->GetArguments().Info;
+            callInfo = gen->GetArguments().Info;
         }
         else if (this->isNativeLibraryFrame)
         {
             // Return saved callInfo. Do not read from stack as compiler may stackpack/optimize args.
-            return &this->prevNativeLibraryEntry->callInfo;
+            callInfo = this->prevNativeLibraryEntry->callInfo;
         }
         else
         {
-            return (CallInfo const *)&this->GetCurrentArgv()[JavascriptFunctionArgIndex_CallInfo];
+            callInfo = *(CallInfo const *)&this->GetCurrentArgv()[JavascriptFunctionArgIndex_CallInfo];
         }
+
+        if (callInfo.Flags & Js::CallFlags_ExtraArg)
+        {
+            callInfo.Flags = (CallFlags)(callInfo.Flags & ~Js::CallFlags_ExtraArg);
+            callInfo.Count--;
+        }
+
+        return callInfo;
     }
 
-    CallInfo const *JavascriptStackWalker::GetCallInfoFromPhysicalFrame() const
+    CallInfo JavascriptStackWalker::GetCallInfoFromPhysicalFrame() const
     {
         return GetCallInfo(false);
     }
@@ -1076,7 +1085,7 @@ namespace Js
 
     bool JavascriptStackWalker::IsCurrentPhysicalFrameForLoopBody() const
     {
-        return !!(this->GetCallInfoFromPhysicalFrame()->Flags & CallFlags_InternalFrame);
+        return !!(this->GetCallInfoFromPhysicalFrame().Flags & CallFlags_InternalFrame);
     }
 
     bool JavascriptStackWalker::IsWalkable(ScriptContext *scriptContext)

+ 2 - 2
lib/Runtime/Language/JavascriptStackWalker.h

@@ -212,8 +212,8 @@ namespace Js
 
         JavascriptFunction *GetCurrentFunction(bool includeInlinedFrames = true) const;
         void SetCurrentFunction(JavascriptFunction *  function);
-        CallInfo const *GetCallInfo(bool includeInlinedFrames = true) const;
-        CallInfo const *GetCallInfoFromPhysicalFrame() const;
+        CallInfo GetCallInfo(bool includeInlinedFrames = true) const;
+        CallInfo GetCallInfoFromPhysicalFrame() const;
         bool GetThis(Var *pThis, int moduleId) const;
         Js::Var * GetJavascriptArgs() const;
         void **GetCurrentArgv() const;

+ 1 - 0
lib/Runtime/Language/ProfilingHelpers.cpp

@@ -487,6 +487,7 @@ namespace Js
                 PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
                 outArgsSize = outArgs.Info.Count * sizeof(Var);
                 outArgs.Values = (Var*)_alloca(outArgsSize);
+                ZeroMemory(outArgs.Values, outArgsSize);
             }
             else
             {

+ 3 - 2
lib/Runtime/Language/StackTraceArguments.cpp

@@ -68,9 +68,10 @@ namespace Js {
         types = 0;
         if (!walker.IsCallerGlobalFunction())
         {
-            int64 numberOfArguments = walker.GetCallInfo()->Count;
+            const CallInfo callInfo = walker.GetCallInfo();
+            int64 numberOfArguments = callInfo.Count;
             if (numberOfArguments > 0) numberOfArguments --; // Don't consider 'this'
-            if (walker.GetCallInfo()->Flags & Js::CallFlags_ExtraArg)
+            if (callInfo.Flags & Js::CallFlags_ExtraArg)
             {
                 Assert(numberOfArguments > 0 );
                 // skip the last FrameDisplay argument.

+ 3 - 3
lib/Runtime/Library/ArgumentsObject.cpp

@@ -67,9 +67,9 @@ namespace Js
 
         AssertMsg(JavascriptOperators::GetTypeId(funcCaller) == TypeIds_Function, "non function caller");
 
-        CallInfo const *callInfo = walker->GetCallInfo();
-        uint32 paramCount = callInfo->Count;
-        CallFlags flags = callInfo->Flags;
+        const CallInfo callInfo = walker->GetCallInfo();
+        uint32 paramCount = callInfo.Count;
+        CallFlags flags = callInfo.Flags;
 
         if (paramCount == 0 || (flags & CallFlags_Eval))
         {

+ 6 - 0
lib/Runtime/Library/ArrayBuffer.cpp

@@ -297,6 +297,12 @@ namespace Js
         if (args.Info.Count >= 3)
         {
             newBufferLength = ToIndex(args[2], JSERR_ArrayLengthConstructIncorrect, scriptContext, MaxArrayBufferLength);
+
+            // ToIndex above can call user script (valueOf) which can detach the buffer
+            if (arrayBuffer->IsDetached())
+            {
+                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, _u("ArrayBuffer.transfer"));
+            }
         }
 
         return arrayBuffer->TransferInternal(newBufferLength);

+ 5 - 6
lib/Runtime/Library/GlobalObject.cpp

@@ -952,17 +952,16 @@ namespace Js
             {
                 JavascriptError::ThrowStackOverflowError(scriptContext);
             }
-            JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
-        }
-        else
-        {
-            if (se.ei.scode == JSERR_AsmJsCompileError)
+            else if (hrCodeGen == JSERR_AsmJsCompileError)
             {
                 // if asm.js compilation succeeded, retry with asm.js disabled
                 grfscr |= fscrNoAsmJs;
-                se.Clear();
                 return DefaultEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr, pszTitle, registerDocument, isIndirect, strictMode);
             }
+            JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
+        }
+        else
+        {
 
             Assert(funcBody != nullptr);
             funcBody->SetDisplayName(pszTitle);

+ 32 - 7
lib/Runtime/Library/JavascriptArray.cpp

@@ -477,6 +477,11 @@ namespace Js
 
     bool JavascriptArray::IsMissingItem(uint32 index)
     {
+        if (this->length <= index)
+        {
+            return false;
+        }
+
         bool isIntArray = false, isFloatArray = false;
         this->GetArrayTypeAndConvert(&isIntArray, &isFloatArray);
 
@@ -3163,11 +3168,14 @@ namespace Js
 
             if (scriptContext->GetConfig()->IsES6IsConcatSpreadableEnabled())
             {
-                if (JavascriptOperators::IsConcatSpreadable(aItem))
+                spreadableCheckedAndTrue = JavascriptOperators::IsConcatSpreadable(aItem);
+                if (!JavascriptNativeIntArray::Is(pDestArray))
                 {
-                    spreadableCheckedAndTrue = true;
+                    ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest, spreadableCheckedAndTrue);
+                    return pDestArray;
                 }
-                else
+
+                if(!spreadableCheckedAndTrue)
                 {
                     pDestArray->SetItem(idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
                     idxDest = idxDest + 1;
@@ -3236,11 +3244,14 @@ namespace Js
 
             if (scriptContext->GetConfig()->IsES6IsConcatSpreadableEnabled())
             {
-                if (JavascriptOperators::IsConcatSpreadable(aItem))
+                spreadableCheckedAndTrue = JavascriptOperators::IsConcatSpreadable(aItem);
+                if (!JavascriptNativeFloatArray::Is(pDestArray))
                 {
-                    spreadableCheckedAndTrue = true;
+                    ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest, spreadableCheckedAndTrue);
+                    return pDestArray;
                 }
-                else
+
+                if(!spreadableCheckedAndTrue)
                 {
                     pDestArray->SetItem(idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
 
@@ -5320,6 +5331,11 @@ Case0:
                 pArr->SetHasNoMissingValues(false);
             }
 
+            // Above FillFromPrototypes call can change the length of the array. Our segment calculation below will
+            // not work with the stale length. Update the length.
+            // Note : since we are reversing the whole segment below - the functionality is not spec compliant already.
+            length = pArr->length;
+
             SparseArraySegmentBase* seg = pArr->head;
             SparseArraySegmentBase *prevSeg = nullptr;
             SparseArraySegmentBase *nextSeg = nullptr;
@@ -5801,7 +5817,7 @@ Case0:
         // Prototype lookup for missing elements
         if (!pArr->HasNoMissingValues())
         {
-            for (uint32 i = 0; i < newLen; i++)
+            for (uint32 i = 0; i < newLen && (i + start) < pArr->length; i++)
             {
                 // array type might be changed in the below call to DirectGetItemAtFull
                 // need recheck array type before checking array item [i + start]
@@ -10150,6 +10166,9 @@ Case0:
 
                 if (JavascriptArray::Is(newObj))
                 {
+#if ENABLE_COPYONACCESS_ARRAY
+                    JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(newObj);
+#endif
                     newArr = JavascriptArray::FromVar(newObj);
                 }
             }
@@ -10200,6 +10219,9 @@ Case0:
 
                 if (JavascriptArray::Is(newObj))
                 {
+#if ENABLE_COPYONACCESS_ARRAY
+                    JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(newObj);
+#endif
                     newArr = JavascriptArray::FromVar(newObj);
                 }
             }
@@ -10310,6 +10332,9 @@ Case0:
             // If the new object we created is an array, remember that as it will save us time setting properties in the object below
             if (JavascriptArray::Is(newObj))
             {
+#if ENABLE_COPYONACCESS_ARRAY
+                JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(newObj);
+#endif
                 newArr = JavascriptArray::FromVar(newObj);
             }
             else if (TypedArrayBase::Is(newObj))

+ 3 - 2
lib/Runtime/Library/JavascriptFunction.cpp

@@ -1111,6 +1111,7 @@ namespace Js
             PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
             outArgsSize = outArgs.Info.Count * sizeof(Var);
             outArgs.Values = (Var*)_alloca(outArgsSize);
+            ZeroMemory(outArgs.Values, outArgsSize);
         }
         else
         {
@@ -2787,9 +2788,9 @@ LABEL1:
                 Var args = nullptr;
                 //Create a copy of the arguments and return it.
 
-                CallInfo const *callInfo = walker.GetCallInfo();
+                const CallInfo callInfo = walker.GetCallInfo();
                 args = JavascriptOperators::LoadHeapArguments(
-                    this, callInfo->Count - 1,
+                    this, callInfo.Count - 1,
                     walker.GetJavascriptArgs(),
                     scriptContext->GetLibrary()->GetNull(),
                     scriptContext->GetLibrary()->GetNull(),

+ 0 - 1
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -1053,7 +1053,6 @@ namespace Js
             // during PostCollectCallBack before Dispose deleting the script context.
             scriptContext->ResetWeakReferenceDictionaryList();
             scriptContext->SetIsFinalized();
-            scriptContext->GetThreadContext()->UnregisterScriptContext(scriptContext);
             scriptContext->MarkForClose();
         }
     }

+ 8 - 1
lib/Runtime/Library/JavascriptProxy.cpp

@@ -1821,8 +1821,15 @@ namespace Js
                 return  JavascriptOperators::SetItem(receiver, targetObj, indexVal, newValue, scriptContext, PropertyOperationFlags::PropertyOperation_None, skipPrototypeCheck);
             }
             case SetPropertyTrapKind::SetPropertyWPCacheKind:
+            {
+                Var name = GetName(requestContext, propertyId);
+                if (!JavascriptString::Is(name) || !VirtualTableInfo<Js::PropertyString>::HasVirtualTable(JavascriptString::FromVar(name)))
+                {
+                    name = nullptr;
+                }
                 return JavascriptOperators::SetPropertyWPCache(receiver, targetObj, propertyId, newValue, requestContext,
-                    static_cast<PropertyString*>(GetName(requestContext, propertyId)), PropertyOperationFlags::PropertyOperation_None);
+                    static_cast<Js::PropertyString*>(name), PropertyOperationFlags::PropertyOperation_None);
+            }
             default:
                 Assert(FALSE);
             }

+ 27 - 0
test/Array/Array_TypeConfusion_bugs.js

@@ -593,5 +593,32 @@ var tests = [
             assert.areEqual(101, arr.length);
         }
     },
+    {
+        name: "Heap overread when splice mutates the array when executing slice",
+        body: function ()
+        {
+            var getterCalled = false;
+            var a = [1, 2];
+            for (var i = 0; i < 100 * 1024; i++) {
+                a.push(i);
+            }
+            delete a[0]; // Make a missing item
+            var protoObj = [11];
+            Object.defineProperty(protoObj, '0', {
+                get : function () {
+                    getterCalled = true;
+                    Object.setPrototypeOf(a, Array.prototype);
+                    a.splice(0); // head seg is now length=0
+                    return 42;
+                },
+                configurable : true
+            });
+            Object.setPrototypeOf(a, protoObj);
+            var b = a.slice();
+            assert.isTrue(getterCalled);
+            assert.areEqual(0, a.length, "Getter will splice the array to zero length");
+            assert.areEqual(100 * 1024 + 2, b.length, "Validating that slice will return the full array even though splice is deleting the whole array");
+        }
+    },
 ];
 testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 36 - 0
test/Array/array_conv_src.js

@@ -0,0 +1,36 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+"use strict";
+
+function func(a, b, c) {
+    a[0] = 1.2;
+    b[0] = c;
+    a[1] = 2.2;
+    a[0] = 2.3023e-320;
+}
+
+function main() {
+    var a = [1.1, 2.2];
+    var b = new Uint32Array(100);
+
+    // force to optimize
+    for (var i = 0; i < 0x10000; i++)
+        func(a, b, i);
+
+    func(a, b, {
+        valueOf: function () {
+            a[0] = {};
+
+            return 0;
+        }
+    });
+
+    a[0].toString();
+}
+
+main();
+
+WScript.Echo('pass');

+ 5 - 0
test/Array/rlexe.xml

@@ -733,4 +733,9 @@
       <files>bug_9575461.js</files>
     </default>
   </test>
+  <test>
+     <default>
+        <files>array_conv_src.js</files>
+     </default>
+  </test>
 </regress-exe>

+ 2 - 0
test/AsmJs/nested.baseline

@@ -0,0 +1,2 @@
+closure functions are not allowed
+Asm.js compilation failed.

+ 12 - 0
test/AsmJs/nested.js

@@ -0,0 +1,12 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function AsmModule() {
+    "use asm";
+    function f() { 
+        function g() { } 
+    }
+}
+AsmModule();

+ 2 - 2
test/AsmJs/qmarkbug.baseline

@@ -1,11 +1,11 @@
 
-qmarkbug.js(9, 3)
+qmarkbug.js(6, 5)
 	Asm.js Compilation Error function : None::f
 	Conditional expressions must be of type int, double, or float
 
 Asm.js compilation failed.
 
-qmarkbug.js(25, 3)
+qmarkbug.js(6, 5)
 	Asm.js Compilation Error function : None::f
 	Conditional expressions must be of type int, double, or float
 

+ 32 - 30
test/AsmJs/qmarkbug.js

@@ -3,34 +3,36 @@
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
-var asmModule = 
-(function(stdlib, foreign, heap) { 'use asm';   var Uint8ArrayView = new stdlib.Uint8Array(heap);
-  var Int16ArrayView = new stdlib.Int16Array(heap);
-  function f(d0, i1)
-  {
-    d0 = +d0;
-    i1 = i1|0;
-    var i4 = 0;
-    i4 = ((0) ? 0 : ((Uint8ArrayView[0])));
-    return +((-7.555786372591432e+22));
-  }
-  return f; })
+eval(`
+(function(stdlib, foreign, heap) {
+    'use asm';
+    var Uint8ArrayView = new stdlib.Uint8Array(heap);
+    var Int16ArrayView = new stdlib.Int16Array(heap);
+    function f(d0, i1)
+    {
+        d0 = +d0;
+        i1 = i1|0;
+        var i4 = 0;
+        i4 = ((0) ? 0 : ((Uint8ArrayView[0])));
+        return +((-7.555786372591432e+22));
+    }
+    return f;
+})(this, {}, new ArrayBuffer(1<<24));
+`);
 
-  var asmHeap = new ArrayBuffer(1<<24);
-  var asmFun = asmModule(this, {}, asmHeap);
-  asmFun();
-  var asmModule = 
-(function(stdlib, foreign, heap) { 'use asm';   var Uint8ArrayView = new stdlib.Uint8Array(heap);
-  var Int16ArrayView = new stdlib.Int16Array(heap);
-  function f(d0, i1)
-  {
-    d0 = +d0;
-    i1 = i1|0;
-    var i4 = 0;
-    i4 = ((0) ? ((Uint8ArrayView[0])): 0 );
-    return +((-7.555786372591432e+22));
-  }
-  return f; })
-
-  var asmFun = asmModule(this, {}, asmHeap);
-  asmFun();
+eval(`
+(function(stdlib, foreign, heap) {
+    'use asm';
+    var Uint8ArrayView = new stdlib.Uint8Array(heap);
+    var Int16ArrayView = new stdlib.Int16Array(heap);
+    function f(d0, i1)
+    {
+        d0 = +d0;
+        i1 = i1|0;
+        var i4 = 0;
+        i4 = ((0) ? ((Uint8ArrayView[0])): 0 );
+        return +((-7.555786372591432e+22));
+    }
+    return f; 
+})(this, {}, new ArrayBuffer(1<<24));
+`);

+ 7 - 0
test/AsmJs/rlexe.xml

@@ -819,4 +819,11 @@
       <files>bugGH2270.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>nested.js</files>
+      <baseline>nested.baseline</baseline>
+      <compile-flags>-forcedeferparse -testtrace:asmjs -simdjs</compile-flags>
+    </default>
+  </test>
 </regress-exe>

+ 4 - 4
test/AsmJs/shadowingBug.baseline

@@ -1,18 +1,18 @@
 
-shadowingBug.js(7, 97)
+shadowingBug.js(1, 97)
 	Asm.js Compilation Error function : None::f1
 	Invalid identifier f64
 
 Asm.js compilation failed.
+0
 
-shadowingBug.js(8, 97)
+shadowingBug.js(1, 97)
 	Asm.js Compilation Error function : None::f1
 	Invalid identifier f64
 
 Asm.js compilation failed.
+NaN
 Var declaration with non-constant
 Asm.js compilation failed.
 0
-NaN
-0
 0

+ 3 - 3
test/AsmJs/shadowingBug.js

@@ -4,9 +4,9 @@
 //-------------------------------------------------------------------------------------------------------
 
 var buffer = new ArrayBuffer(1<<20);
-print((function (stdlib,foreign,buffer) { "use asm"; var f64 = new stdlib.Float64Array(buffer); function f1(){ var f64 = 1.; f64[0] = 0.0;return +0.0;} return f1;})(this,{},buffer)());
-print((function (stdlib,foreign,buffer) { "use asm"; var f64 = new stdlib.Float64Array(buffer); function f1(){ var f64 = 1.; return +f64[0];} return f1;})(this,{},buffer)());
-print((function (stdlib,foreign,buffer) { "use asm"; const a = 10; function f1(){ var a =0; var b = a; return b|0;} return f1;})(this,{},buffer)());
+eval('print((function (stdlib,foreign,buffer) { "use asm"; var f64 = new stdlib.Float64Array(buffer); function f1(){ var f64 = 1.; f64[0] = 0.0;return +0.0;} return f1;})(this,{},buffer)())');
+eval('print((function (stdlib,foreign,buffer) { "use asm"; var f64 = new stdlib.Float64Array(buffer); function f1(){ var f64 = 1.; return +f64[0];} return f1;})(this,{},buffer)())');
+eval('print((function (stdlib,foreign,buffer) { "use asm"; const a = 10; function f1(){ var a =0; var b = a; return b|0;} return f1;})(this,{},buffer)())');
 
 var f64Arr = new Float64Array(buffer);
 print(f64Arr[0]);

+ 16 - 0
test/es6/default-splitscope.js

@@ -159,6 +159,22 @@ var tests = [
             return a;
         }
         assert.areEqual(10, f11()(), "Recursive call to the function from the body scope returns the right value when eval is there in the body");
+
+        function f13() {
+            var a = function jnvgfg(sfgnmj = function ccunlk() { jnvgfg(undefined, 1); }, b) {
+                if (b) {
+                    assert.areEqual(undefined, jnvgfg, "This refers to the instance in the body and the value of the function expression is not copied over");
+                }
+                var jnvgfg = 10;
+                if (!b) {
+                    sfgnmj();
+                    return 100;
+                }
+            };
+            assert.areEqual(100, a(), "After the recursion the right value is returned by the split scoped function");
+        };
+        f13();
+
     } 
  }, 
  { 

+ 8 - 1
test/es6/lambda-params-shadow.js

@@ -18,7 +18,14 @@ class B extends A {
     }
 }
 let b = new B();
-if (count !== 3) {
+class async extends A {
+    constructor() {
+        super();
+        let Q = async A => { A };
+    }
+}
+let a = new async();
+if (count !== 4) {
     WScript.Echo('fail');
 }
 

+ 301 - 291
test/es6/proxybugs.js

@@ -1,107 +1,117 @@
-//-------------------------------------------------------------------------------------------------------
-// Copyright (C) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
-//-------------------------------------------------------------------------------------------------------
-
-WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
-
-var tests = [
-    {
-        name: "Setting proxy object on Map and WeakMap",
-        body() {
-            [WeakMap, Map].forEach(function(ctor) {
-                var target = {};
-                let p = new Proxy(target, {});
-                let map = new ctor();
-                map.set(p, 101);
-                assert.areEqual(map.get(p), 101, ctor.name + " map should be able to set and get the proxy object");
-                p.x = 20;
-                assert.areEqual(target.x, 20, "target object should work as expected even after proxy object is added to map");
-            });
-        }
-    },
-    {
-        name: "Setting proxy object on Map and WeakMap - multiple sets and delete",
-        body() {
-            [WeakMap, Map].forEach(function(ctor) {
-                var target = {};
-                let p = new Proxy(target, {});
-                let map = new ctor();
-                map.set(p, 101);
-                assert.areEqual(map.get(p), 101);
-                map.delete(p);
-                assert.areEqual(map.get(p), undefined, ctor.name + " map can remove the proxy object properly");
-                map.set(p, 102);
-                assert.areEqual(map.get(p), 102, ctor.name + " proxy object can be set again and it returns 102");
-                p.x = 20;
-                assert.areEqual(target.x, 20, "target object should work as expected even after proxy object is added to map");
-            });
-        }
-    },
-    {
-        name: "Assertion validation : returning descriptor during getOwnPropertyDescriptor should not pollute the descriptor",
-        body() {
-            var target = {};
-            var handler = {};
-            var getOwnPropertyDescriptorCalled = false;
-            handler['defineProperty'] = function () {
-                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add accessor");
-            };
-            
-            handler['getOwnPropertyDescriptor'] = function (t, property) {
-                getOwnPropertyDescriptorCalled = true;
-                Object.defineProperty(t, 'abc', { set: function () { } });
-                return Reflect.getOwnPropertyDescriptor(t, property);
-            };
-            
-            var proxy = new Proxy(target, handler);
-            proxy.abc = undefined;
-            assert.isTrue(getOwnPropertyDescriptorCalled);
-        }
-    },
-    {
-        name: "Assertion validation : returning descriptor with writable false should not defineProperty again.",
-        body() {
-            var target = {};
-            var handler = {};
-            var getOwnPropertyDescriptorCalled = false;
-            handler['defineProperty'] = function () {
-                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add property with writable false");
-            };
-            
-            handler['getOwnPropertyDescriptor'] = function (t, property) {
-                getOwnPropertyDescriptorCalled = true;
-                Object.defineProperty(t, 'abc', { value : 1, writable : false });
-                return Reflect.getOwnPropertyDescriptor(t, property);
-            };
-            
-            var proxy = new Proxy(target, handler);
-            proxy.abc = undefined;
-            assert.isTrue(getOwnPropertyDescriptorCalled);
-        }
-    },
-    {
-        name: "No property found at getOwnPropertyDescriptor will call defineProperty",
-        body() {
-            var target = {};
-            var handler = {};
-            var definePropertyCalled = false;
-            var getOwnPropertyDescriptorCalled = false;
-            handler['defineProperty'] = function () {
-                definePropertyCalled = true;
-            };
-            
-            handler['getOwnPropertyDescriptor'] = function (t, property) {
-                getOwnPropertyDescriptorCalled = true;
-                return Reflect.getOwnPropertyDescriptor(t, property);
-            };
-            
-            var proxy = new Proxy(target, handler);
-            proxy.abc = undefined;
-            assert.isTrue(definePropertyCalled);
-            assert.isTrue(getOwnPropertyDescriptorCalled);
-        }
-    },
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+
+var tests = [
+    {
+        name: "Setting proxy object on Map and WeakMap",
+        body() {
+            [WeakMap, Map].forEach(function(ctor) {
+                var target = {};
+                let p = new Proxy(target, {});
+                let map = new ctor();
+                map.set(p, 101);
+                assert.areEqual(map.get(p), 101, ctor.name + " map should be able to set and get the proxy object");
+                p.x = 20;
+                assert.areEqual(target.x, 20, "target object should work as expected even after proxy object is added to map");
+            });
+        }
+    },
+    {
+        name: "Setting proxy object on Map and WeakMap - multiple sets and delete",
+        body() {
+            [WeakMap, Map].forEach(function(ctor) {
+                var target = {};
+                let p = new Proxy(target, {});
+                let map = new ctor();
+                map.set(p, 101);
+                assert.areEqual(map.get(p), 101);
+                map.delete(p);
+                assert.areEqual(map.get(p), undefined, ctor.name + " map can remove the proxy object properly");
+                map.set(p, 102);
+                assert.areEqual(map.get(p), 102, ctor.name + " proxy object can be set again and it returns 102");
+                p.x = 20;
+                assert.areEqual(target.x, 20, "target object should work as expected even after proxy object is added to map");
+            });
+        }
+    },
+    {
+        name: "Assertion validation : returning descriptor during getOwnPropertyDescriptor should not pollute the descriptor",
+        body() {
+            var target = {};
+            var handler = {};
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add accessor");
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                Object.defineProperty(t, 'abc', { set: function () { } });
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
+    },
+    {
+        name: "Assertion validation : returning descriptor with writable false should not defineProperty again.",
+        body() {
+            var target = {};
+            var handler = {};
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                assert.fail("This function will not be called as 'getOwnPropertyDescriptor' will add property with writable false");
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                Object.defineProperty(t, 'abc', { value : 1, writable : false });
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
+    },
+    {
+        name: "No property found at getOwnPropertyDescriptor will call defineProperty",
+        body() {
+            var target = {};
+            var handler = {};
+            var definePropertyCalled = false;
+            var getOwnPropertyDescriptorCalled = false;
+            handler['defineProperty'] = function () {
+                definePropertyCalled = true;
+            };
+            
+            handler['getOwnPropertyDescriptor'] = function (t, property) {
+                getOwnPropertyDescriptorCalled = true;
+                return Reflect.getOwnPropertyDescriptor(t, property);
+            };
+            
+            var proxy = new Proxy(target, handler);
+            proxy.abc = undefined;
+            assert.isTrue(definePropertyCalled);
+            assert.isTrue(getOwnPropertyDescriptorCalled);
+        }
+    },
+    {
+        name: "Type confusion in JavascriptProxy::SetPropertyTrap when using a Symbol",
+        body: function () {
+            try{ Reflect.set((new Proxy({}, {has: function(){ return true; }})), 'abc', 0x44444444, new Uint32Array); } catch(e){}
+            try{ Reflect.set((new Proxy({}, {has: function(){ return true; }})), 'abc', 0x44444444, new Uint32Array); } catch(e){}
+
+            var obj1 = Object.create(new Proxy({}, {}));
+            obj1[Symbol.species] = 0;
+        }
+    },
     {
         name: "Assertion validation : revoking the proxy in getPrototypeOf trap",
         body() {
@@ -119,190 +129,190 @@ var tests = [
             assert.isTrue(trapCalled);
         }
     },
-    {
-        name: "Assertion validation : revoking the proxy in setPrototypeOf trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                setPrototypeOf : function(a, b) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return true;
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            var ret = Object.setPrototypeOf(obj.proxy, {});
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in isExtensible trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                isExtensible : function(a, b) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return true;
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            var ret = Object.isExtensible(obj.proxy);
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in preventExtensions trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                preventExtensions : function(a, b) {
-                    trapCalled = true;
-                    obj.revoke();
-               }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            Object.preventExtensions(obj.proxy);
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in getOwnPropertyDescriptor trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                getOwnPropertyDescriptor : function(a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            assert.throws( () => { Object.getOwnPropertyDescriptor(obj.proxy, 'a'); }, TypeError);
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in has trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                has : function(a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return false;
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            'a' in obj.proxy;
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in get trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                get : function (a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return {};
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            var ret = obj.proxy.a;
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in set trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                set : function (a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return {};
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            obj.proxy.a = 10;
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in deleteProperty trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                deleteProperty : function (a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return {};
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            delete obj.proxy.a;
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in ownKeys trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                ownKeys : function (a, b, c) {
-                    trapCalled = true;
-                    obj.revoke();
-                    return {};
-                }
-            };
-            
-            var obj = Proxy.revocable({}, handler);
-            Object.keys(obj.proxy);
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in apply trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                get apply () {
-                    trapCalled = true;
-                    obj.revoke();
-                }
-            };
-            
-            var obj = Proxy.revocable(() => {}, handler);
-            obj.proxy();
-            assert.isTrue(trapCalled);
-        }
-    },
-    {
-        name: "Assertion validation : revoking the proxy in construct trap",
-        body() {
-            var trapCalled = false;
-            var handler = {
-                get construct () {
-                    trapCalled = true;
-                    obj.revoke();
-                    return () => { return {}; };
-                }
-            };
-            
-            var obj = Proxy.revocable(() => {}, handler);
-            new obj.proxy();
-            assert.isTrue(trapCalled);
-        }
-    },
-];
-
-testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
+    {
+        name: "Assertion validation : revoking the proxy in setPrototypeOf trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                setPrototypeOf : function(a, b) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return true;
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            var ret = Object.setPrototypeOf(obj.proxy, {});
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in isExtensible trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                isExtensible : function(a, b) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return true;
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            var ret = Object.isExtensible(obj.proxy);
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in preventExtensions trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                preventExtensions : function(a, b) {
+                    trapCalled = true;
+                    obj.revoke();
+               }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            Object.preventExtensions(obj.proxy);
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in getOwnPropertyDescriptor trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                getOwnPropertyDescriptor : function(a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            assert.throws( () => { Object.getOwnPropertyDescriptor(obj.proxy, 'a'); }, TypeError);
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in has trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                has : function(a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return false;
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            'a' in obj.proxy;
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in get trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                get : function (a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return {};
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            var ret = obj.proxy.a;
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in set trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                set : function (a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return {};
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            obj.proxy.a = 10;
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in deleteProperty trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                deleteProperty : function (a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return {};
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            delete obj.proxy.a;
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in ownKeys trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                ownKeys : function (a, b, c) {
+                    trapCalled = true;
+                    obj.revoke();
+                    return {};
+                }
+            };
+            
+            var obj = Proxy.revocable({}, handler);
+            Object.keys(obj.proxy);
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in apply trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                get apply () {
+                    trapCalled = true;
+                    obj.revoke();
+                }
+            };
+            
+            var obj = Proxy.revocable(() => {}, handler);
+            obj.proxy();
+            assert.isTrue(trapCalled);
+        }
+    },
+    {
+        name: "Assertion validation : revoking the proxy in construct trap",
+        body() {
+            var trapCalled = false;
+            var handler = {
+                get construct () {
+                    trapCalled = true;
+                    obj.revoke();
+                    return () => { return {}; };
+                }
+            };
+            
+            var obj = Proxy.revocable(() => {}, handler);
+            new obj.proxy();
+            assert.isTrue(trapCalled);
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });