فهرست منبع

JIT: signed integer overflow and other fixes

Address CR comments.

Refactored IntMath classes to share common code and use builtins when
available.

Cleaned up signed integer overflow cases. Added build.sh --sanity=...
support to help future diagnostics. Turned off CLANG signed integer
overflow optimization with `-fwrapv` switch.

Fixed a ICU call bug (found in running Octane/typescript.js).

Implemented another AsmJs thunk. (called by Octane/zlib.js).

Synced to latest and fix merge errors.
Jianchun Xu 9 سال پیش
والد
کامیت
3ab6f3e971

+ 15 - 4
CMakeLists.txt

@@ -253,7 +253,15 @@ if(CLR_CMAKE_PLATFORM_XPLAT)
     add_compile_options(
         -fasm-blocks
         -fms-extensions
+        -fwrapv                 # Treat signed integer overflow as two's complement
     )
+
+    # Clang -fsanitize.
+    if (CLANG_SANITIZE_SH)
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${CLANG_SANITIZE_SH}")
+        set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -fsanitize=${CLANG_SANITIZE_SH}")
+        unset(CLANG_SANITIZE_SH CACHE)      # don't cache
+    endif()
 endif(CLR_CMAKE_PLATFORM_XPLAT)
 
 if(CMAKE_BUILD_TYPE STREQUAL Debug)
@@ -286,16 +294,19 @@ if(CLR_CMAKE_PLATFORM_XPLAT)
    add_definitions(-DFEATURE_PAL)
 endif(CLR_CMAKE_PLATFORM_XPLAT)
 
-if(NO_JIT
+if(NO_JIT_SH
    OR CLR_CMAKE_PLATFORM_DARWIN)  # TODO: JIT for OSX
+    unset(NO_JIT_SH CACHE)      # don't cache
+    unset(BuildJIT CACHE)       # also clear it just in case
     add_definitions(-DDISABLE_JIT=1)
 else()
     set(BuildJIT 1)
 endif()
 
-if(WITHOUT_FEATURES)
-   add_definitions(${WITHOUT_FEATURES})
-endif(WITHOUT_FEATURES)
+if(WITHOUT_FEATURES_SH)
+    unset(WITHOUT_FEATURES_SH CACHE)    # don't cache
+    add_definitions(${WITHOUT_FEATURES_SH})
+endif(WITHOUT_FEATURES_SH)
 
 enable_language(ASM)
 

+ 13 - 3
build.sh

@@ -42,6 +42,8 @@ PRINT_USAGE() {
     echo "      --xcode          Generate XCode project"
     echo "  -t, --test-build     Test build (by default Release build)"
     echo "      --static         Build as static library (by default shared library)"
+    echo "      --sanitize=CHECKS Build with clang -fsanitize checks,"
+    echo "                       e.g. undefined,signed-integer-overflow"
     echo "  -v, --verbose        Display verbose output including all options"
     echo "      --create-deb=V   Create .deb package with given V version"
     echo "      --without=FEATURE,FEATURE,..."
@@ -66,6 +68,7 @@ MULTICORE_BUILD=""
 NO_JIT=
 ICU_PATH="-DICU_SETTINGS_RESET=1"
 STATIC_LIBRARY="-DSHARED_LIBRARY_SH=1"
+SANITIZE=
 WITHOUT_FEATURES=""
 CREATE_DEB=0
 ARCH="-DCC_TARGETS_AMD64_SH=1"
@@ -194,7 +197,7 @@ while [[ $# -gt 0 ]]; do
         ;;
 
     --no-jit)
-        NO_JIT="-DNO_JIT=1"
+        NO_JIT="-DNO_JIT_SH=1"
         ;;
 
     --xcode)
@@ -211,13 +214,19 @@ while [[ $# -gt 0 ]]; do
         STATIC_LIBRARY="-DSTATIC_LIBRARY_SH=1"
         ;;
 
+    --sanitize=*)
+        SANITIZE=$1
+        SANITIZE=${SANITIZE:11}    # value after --sanitize=
+        SANITIZE="-DCLANG_SANITIZE_SH=${SANITIZE}"
+        ;;
+
     --without=*)
         FEATURES=$1
         FEATURES=${FEATURES:10}    # value after --without=
         for x in ${FEATURES//,/ }  # replace comma with space then split
         do
             if [[ "$WITHOUT_FEATURES" == "" ]]; then
-                WITHOUT_FEATURES="-DWITHOUT_FEATURES="
+                WITHOUT_FEATURES="-DWITHOUT_FEATURES_SH="
             else
                 WITHOUT_FEATURES="$WITHOUT_FEATURES;"
             fi
@@ -312,7 +321,8 @@ else
 fi
 
 echo Generating $BUILD_TYPE makefiles
-cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $STATIC_LIBRARY $ARCH -DCMAKE_BUILD_TYPE=$BUILD_TYPE $NO_JIT $WITHOUT_FEATURES ../..
+cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $STATIC_LIBRARY $ARCH \
+    -DCMAKE_BUILD_TYPE=$BUILD_TYPE $SANITIZE $NO_JIT $WITHOUT_FEATURES ../..
 
 _RET=$?
 if [[ $? == 0 ]]; then

+ 2 - 0
lib/Backend/EhFrame.cpp

@@ -119,6 +119,8 @@ void EhFrame::Entry::Begin()
 
 void EhFrame::Entry::End()
 {
+    Assert(beginOffset != -1); // Must have called Begin()
+
     // padding
     size_t padding = (MachPtr - writer->Count() % MachPtr) % MachPtr;
     for (size_t i = 0; i < padding; i++)

+ 1 - 1
lib/Backend/Func.cpp

@@ -1732,7 +1732,7 @@ IR::IndirOpnd * Func::GetConstantAddressIndirOpnd(intptr_t address, IR::AddrOpnd
     {
         Assert(regOpnd->m_sym->IsSingleDef());
         void * curr = regOpnd->m_sym->m_instrDef->GetSrc1()->AsAddrOpnd()->m_address;
-        ptrdiff_t diff = (intptr_t)address - (intptr_t)curr;
+        ptrdiff_t diff = (uintptr_t)address - (uintptr_t)curr;
         if (!Math::FitsInDWord(diff))
         {
             return false;

+ 2 - 2
lib/Backend/GlobOpt.cpp

@@ -8514,7 +8514,7 @@ GlobOpt::PropagateIntRangeBinary(IR::Instr *instr, int32 min1, int32 max1,
         {
             // Turn values like 0x1010 into 0x1111
             max = 1 << Math::Log2(max);
-            max = (max << 1) - 1;
+            max = (uint32)(max << 1) - 1;
             min = 0;
         }
 
@@ -8600,7 +8600,7 @@ GlobOpt::PropagateIntRangeBinary(IR::Instr *instr, int32 min1, int32 max1,
                 if (max1)
                 {
                     max1 = 1 << Math::Log2(max1);
-                    max1 = (max1 << 1) - 1;
+                    max1 = (uint32)(max1 << 1) - 1;
                 }
 
                 if (max1 > 0)

+ 4 - 2
lib/Backend/IntBounds.cpp

@@ -304,7 +304,8 @@ bool IntBounds::IsGreaterThanOrEqualTo(const int constantValue, const int consta
     if(offset == 1)
         return constantValue > constantBoundBase;
 
-    const int constantBound = constantBoundBase + offset;
+    // use unsigned to avoid signed int overflow
+    const int constantBound = (unsigned)constantBoundBase + (unsigned)offset;
     return
         offset >= 0
             ? constantBound >= constantBoundBase && constantValue >= constantBound
@@ -318,7 +319,8 @@ bool IntBounds::IsLessThanOrEqualTo(const int constantValue, const int constantB
     if(offset == -1)
         return constantValue < constantBoundBase;
 
-    const int constantBound = constantBoundBase + offset;
+    // use unsigned to avoid signed int overflow
+    const int constantBound = (unsigned)constantBoundBase + (unsigned)offset;
     return
         offset >= 0
             ? constantBound < constantBoundBase || constantValue <= constantBound

+ 1 - 1
lib/Backend/IntConstantBounds.h

@@ -65,7 +65,7 @@ public:
     IntConstantBounds And_0x1f() const
     {
         const int32 mask = 0x1f;
-        if(static_cast<UIntConstType>(upperBound - lowerBound) >= static_cast<UIntConstType>(mask) ||
+        if(static_cast<UIntConstType>(upperBound) - static_cast<UIntConstType>(lowerBound) >= static_cast<UIntConstType>(mask) ||
             (lowerBound & mask) > (upperBound & mask))
         {
             // The range contains all items in the set {0-mask}, or the range crosses a boundary of {0-mask}. Since we cannot

+ 18 - 18
lib/Backend/Lower.cpp

@@ -254,7 +254,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
         case Js::OpCode::InvalCachedScope:
             this->LowerBinaryHelper(instr, IR::HelperOP_InvalidateCachedScope);
             break;
-        
+
         case Js::OpCode::InitCachedScope:
             instrPrev = this->LowerInitCachedScope(instr);
             break;
@@ -3166,7 +3166,7 @@ Lowerer::LoadOptimizationOverridesValueOpnd(IR::Instr *instr, OptimizationOverri
 
 IR::Opnd *
 Lowerer::LoadNumberAllocatorValueOpnd(IR::Instr *instr, NumberAllocatorValue valueType)
-{    
+{
     ScriptContextInfo *scriptContext = instr->m_func->GetScriptContextInfo();
     bool allowNativeCodeBumpAllocation = scriptContext->GetRecyclerAllowNativeCodeBumpAllocation();
 
@@ -3513,7 +3513,7 @@ Lowerer::LowerNewScObjectLiteral(IR::Instr *newObjInstr)
     propertyArrayOpnd = IR::AddrOpnd::New(propArrayAddr, IR::AddrOpndKindDynamicMisc, this->m_func);
 
     //#if 0 TODO: OOP JIT, obj literal types
-    // should pass in isShared bit through RPC, enable for in-proc jit to see perf impact    
+    // should pass in isShared bit through RPC, enable for in-proc jit to see perf impact
     Js::DynamicType * literalType = func->IsOOPJIT() || !CONFIG_FLAG(OOPJITMissingOpts) ? nullptr : *(Js::DynamicType **)literalTypeRef;
 
     if (literalType == nullptr || !literalType->GetIsShared())
@@ -6832,7 +6832,7 @@ Lowerer::GenerateStFldWithCachedType(IR::Instr *instrStFld, bool* continueAsHelp
 
     if (hasTypeCheckBailout)
     {
-        AssertMsg(PHASE_ON1(Js::ObjTypeSpecIsolatedFldOpsWithBailOutPhase) || !propertySymOpnd->IsTypeDead(), 
+        AssertMsg(PHASE_ON1(Js::ObjTypeSpecIsolatedFldOpsWithBailOutPhase) || !propertySymOpnd->IsTypeDead(),
             "Why does a field store have a type check bailout, if its type is dead?");
 
         if (instrStFld->GetBailOutInfo()->bailOutInstr != instrStFld)
@@ -8590,7 +8590,7 @@ Lowerer::LowerMemset(IR::Instr * instr, IR::RegOpnd * helperRet)
     m_lowererMD.LoadHelperArgument(instr, baseOpnd);
     m_lowererMD.ChangeToHelperCall(instr, helperMethod);
     dst->Free(m_func);
-    
+
     return instrPrev;
 }
 
@@ -8865,10 +8865,10 @@ Lowerer::GenerateFastBrBReturn(IR::Instr * instr)
     // TEST firstPrototypeOpnd, firstPrototypeOpnd
     // JNE $helper
     IR::RegOpnd * firstPrototypeOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
-    InsertMove(firstPrototypeOpnd, 
+    InsertMove(firstPrototypeOpnd,
         IR::IndirOpnd::New(forInEnumeratorOpnd, Js::ForInObjectEnumerator::GetOffsetOfFirstPrototype(), TyMachPtr, this->m_func), instr);
     InsertTestBranch(firstPrototypeOpnd, firstPrototypeOpnd, Js::OpCode::BrNeq_A, labelHelper, instr);
-    
+
     // MOV currentEnumeratorOpnd, forInEnumerator->enumerator.currentEnumerator
     // TEST currentEnumeratorOpnd, currentEnumeratorOpnd
     // JNE $helper
@@ -8883,7 +8883,7 @@ Lowerer::GenerateFastBrBReturn(IR::Instr * instr)
     IR::RegOpnd * objectOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
     InsertMove(objectOpnd,
         IR::IndirOpnd::New(forInEnumeratorOpnd, Js::ForInObjectEnumerator::GetOffsetOfEnumeratorObject(), TyMachPtr, this->m_func), instr);
-    InsertTestBranch(objectOpnd, objectOpnd, Js::OpCode::BrEq_A, labelHelper, instr);   
+    InsertTestBranch(objectOpnd, objectOpnd, Js::OpCode::BrEq_A, labelHelper, instr);
 
     // MOV initialTypeOpnd, forInEnumerator->enumerator.initialType
     // CMP initialTypeOpnd, objectOpnd->type
@@ -8907,7 +8907,7 @@ Lowerer::GenerateFastBrBReturn(IR::Instr * instr)
     InsertCompareBranch(enumeratedCountOpnd,
         IR::IndirOpnd::New(cachedDataOpnd, Js::DynamicObjectPropertyEnumerator::GetOffsetOfCachedDataCachedCount(), TyUint32, this->m_func),
         Js::OpCode::BrGe_A, labelHelper, instr);
-    
+
     // MOV propertyAttributesOpnd, cachedData->attributes
     // MOV objectPropertyAttributesOpnd, propertyAttributesOpnd[enumeratedCount]
     // CMP objectPropertyAttributesOpnd & PropertyEnumerable, PropertyEnumerable
@@ -8923,7 +8923,7 @@ Lowerer::GenerateFastBrBReturn(IR::Instr * instr)
 
     InsertCompareBranch(andPropertyEnumerableInstr->GetDst(), IR::IntConstOpnd::New(PropertyEnumerable, TyUint8, this->m_func),
         Js::OpCode::BrNeq_A, labelHelper, instr);
-    
+
     IR::Opnd * opndDst = instr->GetDst(); // ForIn result propertyString
     Assert(opndDst->IsRegOpnd());
 
@@ -9932,7 +9932,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
     // ...
     //     s2 = assign param2
     // $done:
-    
+
     AnalysisAssert(instrArgIn);
 
     IR::Opnd *restDst = nullptr;
@@ -10086,7 +10086,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
 
 
     BVSparse<JitArenaAllocator> *formalsBv = JitAnew(this->m_alloc, BVSparse<JitArenaAllocator>, this->m_alloc);
-    
+
     while (currArgInCount > 0)
     {
         dstOpnd = instrArgIn->GetDst();
@@ -10104,9 +10104,9 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
         //     BrEq_A $Ln-1
 
         currArgInCount--;
-        
+
         labelInitNext = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
-        
+
 
         // And insert the "normal" initialization before the "done" label
 
@@ -12543,7 +12543,7 @@ Lowerer::GenerateBailOut(IR::Instr * instr, IR::BranchInstr * branchInstr, IR::L
             else
             {
                 indexOpnd = IR::MemRefOpnd::New((BYTE*)bailOutInfo->bailOutRecord + BailOutRecord::GetOffsetOfPolymorphicCacheIndex(), TyUint32, this->m_func);
-            }             
+            }
 
             m_lowererMD.CreateAssign(
                 indexOpnd, IR::IntConstOpnd::New(bailOutInfo->polymorphicCacheIndex, TyUint32, this->m_func), instr);
@@ -14703,7 +14703,7 @@ Lowerer::GenerateFastElemIIntIndexCommon(
     const bool needBailOutOnInvalidLength = !!(bailOutKind & (IR::BailOutOnInvalidatedArrayHeadSegment));
     const bool needBailOutToHelper = !!(bailOutKind & (IR::BailOutOnArrayAccessHelperCall));
     const bool needBailOutOnSegmentLengthCompare = needBailOutToHelper || needBailOutOnInvalidLength;
-    
+
     if(indexIsLessThanHeadSegmentLength || needBailOutOnSegmentLengthCompare)
     {
         if (needBailOutOnSegmentLengthCompare)
@@ -18544,7 +18544,7 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
         ldElem->InsertBefore(labelCreateHeapArgs);
         emittedFastPath = true;
     }
-    
+
     if (!emittedFastPath)
     {
         throw Js::RejitException(RejitReason::DisableStackArgOpt);
@@ -20655,7 +20655,7 @@ Lowerer::GenerateLdHomeObjProto(IR::Instr* instr)
     //
     //  $Err:
     //  ThrowRuntimeReferenceError(JSERR_BadSuperReference);
-    //  
+    //
     //  $NoErr:
     //  instance = ((RecyclableObject*)instance)->GetPrototype();
     //  if (instance == nullptr) goto $Done;

+ 30 - 30
lib/Backend/SccLiveness.cpp

@@ -376,36 +376,36 @@ SCCLiveness::ProcessSrc(IR::Opnd *src, IR::Instr *instr)
     }
     else if (!this->lastCall && src->IsSymOpnd() && src->AsSymOpnd()->m_sym->AsStackSym()->IsParamSlotSym())
     {
-		IR::SymOpnd *symOpnd = src->AsSymOpnd();
-		RegNum reg = LinearScanMD::GetParamReg(symOpnd, this->func);
-
-		if (reg != RegNOREG && PHASE_ON(Js::RegParamsPhase, this->func))
-		{
-			StackSym *stackSym = symOpnd->m_sym->AsStackSym();
-			Lifetime *lifetime = stackSym->scratch.linearScan.lifetime;
-
-			if (lifetime == nullptr)
-			{
-				lifetime = this->InsertLifetime(stackSym, reg, this->func->m_headInstr->m_next);
-				lifetime->region = this->curRegion;
-				lifetime->isFloat = symOpnd->IsFloat();
-				lifetime->isSimd128F4 = symOpnd->IsSimd128F4();
-				lifetime->isSimd128I4 = symOpnd->IsSimd128I4();
-				lifetime->isSimd128I8 = symOpnd->IsSimd128I8();
-				lifetime->isSimd128I16 = symOpnd->IsSimd128I16();
-				lifetime->isSimd128U4 = symOpnd->IsSimd128U4();
-				lifetime->isSimd128U8 = symOpnd->IsSimd128U8();
-				lifetime->isSimd128U16 = symOpnd->IsSimd128U16();
-				lifetime->isSimd128B4 = symOpnd->IsSimd128B4();
-				lifetime->isSimd128B8 = symOpnd->IsSimd128B8();
-				lifetime->isSimd128B16 = symOpnd->IsSimd128B16();
-				lifetime->isSimd128D2 = symOpnd->IsSimd128D2();
-			}
-
-			IR::RegOpnd * newRegOpnd = IR::RegOpnd::New(stackSym, reg, symOpnd->GetType(), this->func);
-			instr->ReplaceSrc(symOpnd, newRegOpnd);
-			this->ProcessRegUse(newRegOpnd, instr);
-		}
+        IR::SymOpnd *symOpnd = src->AsSymOpnd();
+        RegNum reg = LinearScanMD::GetParamReg(symOpnd, this->func);
+
+        if (reg != RegNOREG && PHASE_ON(Js::RegParamsPhase, this->func))
+        {
+            StackSym *stackSym = symOpnd->m_sym->AsStackSym();
+            Lifetime *lifetime = stackSym->scratch.linearScan.lifetime;
+
+            if (lifetime == nullptr)
+            {
+                lifetime = this->InsertLifetime(stackSym, reg, this->func->m_headInstr->m_next);
+                lifetime->region = this->curRegion;
+                lifetime->isFloat = symOpnd->IsFloat();
+                lifetime->isSimd128F4 = symOpnd->IsSimd128F4();
+                lifetime->isSimd128I4 = symOpnd->IsSimd128I4();
+                lifetime->isSimd128I8 = symOpnd->IsSimd128I8();
+                lifetime->isSimd128I16 = symOpnd->IsSimd128I16();
+                lifetime->isSimd128U4 = symOpnd->IsSimd128U4();
+                lifetime->isSimd128U8 = symOpnd->IsSimd128U8();
+                lifetime->isSimd128U16 = symOpnd->IsSimd128U16();
+                lifetime->isSimd128B4 = symOpnd->IsSimd128B4();
+                lifetime->isSimd128B8 = symOpnd->IsSimd128B8();
+                lifetime->isSimd128B16 = symOpnd->IsSimd128B16();
+                lifetime->isSimd128D2 = symOpnd->IsSimd128D2();
+            }
+
+            IR::RegOpnd * newRegOpnd = IR::RegOpnd::New(stackSym, reg, symOpnd->GetType(), this->func);
+            instr->ReplaceSrc(symOpnd, newRegOpnd);
+            this->ProcessRegUse(newRegOpnd, instr);
+        }
     }
 }
 

+ 2 - 4
lib/Backend/amd64/LinearScanMdA.S

@@ -7,13 +7,11 @@
 #include "unixasmmacros.inc"
 
 
-#ifndef __APPLE__
 // BailOutRecord::BailOut(BailOutRecord const * bailOutRecord)
 // .extern _ZN13BailOutRecord7BailOutEPKS_
 
 // BranchBailOutRecord::BailOut(BranchBailOutRecord const * bailOutRecord, BOOL cond)
 // .extern _ZN19BranchBailOutRecord7BailOutEPKS_i
-#endif
 
 
 //------------------------------------------------------------------------------
@@ -103,7 +101,7 @@ NESTED_ENTRY _ZN12LinearScanMD26SaveAllRegistersAndBailOutEP13BailOutRecord, _TE
     sub rsp, 28h        // use the same as Windows x64 so register locations are the same
     .cfi_adjust_cfa_offset 0x28
 
-    call _ZN12LinearScanMD26SaveAllRegistersEP13BailOutRecord
+    call C_FUNC(_ZN12LinearScanMD26SaveAllRegistersEP13BailOutRecord)
 
     add rsp, 28h        // deallocate stack space
     .cfi_adjust_cfa_offset -0x28
@@ -129,7 +127,7 @@ NESTED_ENTRY _ZN12LinearScanMD32SaveAllRegistersAndBranchBailOutEP19BranchBailOu
     sub rsp, 28h        // use the same as Windows x64 so register locations are the same
     .cfi_adjust_cfa_offset 0x28
 
-    call _ZN12LinearScanMD26SaveAllRegistersEP13BailOutRecord
+    call C_FUNC(_ZN12LinearScanMD26SaveAllRegistersEP13BailOutRecord)
 
     add rsp, 28h        // deallocate stack space
     .cfi_adjust_cfa_offset -0x28

+ 1 - 1
lib/Common/BackendApi.h

@@ -37,7 +37,7 @@ struct InlinedFrameLayout;
 
 typedef intptr_t IntConstType;
 typedef uintptr_t  UIntConstType;
-typedef IntMath<intptr_t>::Type IntConstMath;
+typedef IntMath<IntConstType>::Type IntConstMath;
 typedef double  FloatConstType;
 
 #include "EmitBuffer.h"

+ 1 - 0
lib/Common/Common.h

@@ -47,6 +47,7 @@ namespace Js
 #include "EnumClassHelp.h"
 #include "Common/Tick.h"
 
+#include "Common/IntMathCommon.h"
 #include "Common/Int16Math.h"
 #include "Common/Int32Math.h"
 #include "Common/UInt16Math.h"

+ 4 - 0
lib/Common/Common/CommonCommonPch.h

@@ -19,6 +19,10 @@
 // === Common Header Files ===
 #include "Common/NumberUtilitiesBase.h"
 #include "Common/NumberUtilities.h"
+#include "Common/IntMathCommon.h"
+#include "Common/Int16Math.h"
+#include "Common/Int32Math.h"
+#include "Common/Int64Math.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)

+ 3 - 47
lib/Common/Common/Int16Math.h

@@ -2,52 +2,8 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-class Int16Math
-{
-public:
-    template< class Func >
-    static int16 Add(int16 lhs, int16 rhs, __inout Func& overflowFn)
-    {
-        int16 result = lhs + rhs;
-
-        // If the result is smaller than the LHS, then we overflowed
-        if( result < lhs )
-        {
-            overflowFn();
-        }
-
-        return result;
-    }
-
-    template< class Func >
-    static void Inc(int16& lhs, __inout Func& overflowFn)
-    {
-        ++lhs;
+#pragma once
 
-        // If lhs becomes 0, then we overflowed
-        if(!lhs)
-        {
-            overflowFn();
-        }
-    }
-
-    // Convenience function which uses DefaultOverflowPolicy (throws OOM when overflow)
-    static int16 Add(int16 lhs, uint16 rhs)
-    {
-        return Add(lhs, rhs, ::Math::DefaultOverflowPolicy);
-    }
-
-    // Convenience functions which return a bool indicating overflow
-    static bool Add(int16 lhs, int16 rhs, __out int16* result)
-    {
-        ::Math::RecordOverflowPolicy overflowGuard;
-        *result = Add(lhs, rhs, overflowGuard);
-        return overflowGuard.HasOverflowed();
-    }
-
-    // Convenience function which uses DefaultOverflowPolicy (throws OOM when overflow)
-    static void Inc(int16& lhs)
-    {
-        Inc(lhs, ::Math::DefaultOverflowPolicy);
-    }
+class Int16Math: public IntMathCommon<int16>
+{
 };

+ 11 - 123
lib/Common/Common/Int32Math.cpp

@@ -3,27 +3,29 @@
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "CommonCommonPch.h"
-#include "Common/Int32Math.h"
 
 bool
 Int32Math::Add(int32 left, int32 right, int32 *pResult)
 {
-    if (sizeof(void *) == 4)
-    {
-        // Overflow occurs when the result has a different sign from both the left and right operands
-        *pResult = left + right;
-        return ((left ^ *pResult) & (right ^ *pResult)) < 0;
-    }
+#if __has_builtin(__builtin_add_overflow) || TARGET_32
+    return IntMathCommon<int32>::Add(left, right, pResult);
+#else
 
     Assert(sizeof(void *) == 8);
     int64 result64 = (int64)left + (int64)right;
     *pResult = (int32)result64;
     return result64 != (int64)(*pResult);
+
+#endif
 }
 
 bool
 Int32Math::Mul(int32 left, int32 right, int32 *pResult)
 {
+#if __has_builtin(__builtin_mul_overflow)
+    return IntMathCommon<int32>::Mul(left, right, pResult);
+#else
+
     bool fOverflow;
 #if _M_IX86
     __asm
@@ -43,6 +45,8 @@ Int32Math::Mul(int32 left, int32 right, int32 *pResult)
 #endif
 
     return fOverflow;
+
+#endif  // !__has_builtin(__builtin_mul_overflow)
 }
 
 bool
@@ -79,50 +83,6 @@ Int32Math::Shl(int32 left, int32 right, int32 *pResult)
     return (left != (int32)((uint32)*pResult >> right));
 }
 
-bool
-Int32Math::Sub(int32 left, int32 right, int32 *pResult)
-{
-    if(sizeof(void *) == 4)
-    {
-        // Overflow occurs when the result has a different sign from the left operand, and the result has the same sign as the
-        // right operand
-        *pResult = left - right;
-        return ((left ^ *pResult) & ~(right ^ *pResult)) < 0;
-    }
-
-    Assert(sizeof(void *) == 8);
-    int64 result64 = (int64)left - (int64)right;
-    *pResult = (int32)result64;
-    return result64 != (int64)(*pResult);
-}
-
-bool
-Int32Math::Div(int32 left, int32 right, int32 *pResult)
-{
-    AssertMsg(right != 0, "Divide by zero...");
-
-    if (right == -1 && left == INT_MIN)
-    {
-        //Special check for INT_MIN/-1
-        return true;
-    }
-    *pResult = left / right;
-    return false;
-}
-
-bool
-Int32Math::Mod(int32 left, int32 right, int32 *pResult)
-{
-    AssertMsg(right != 0, "Mod by zero...");
-    if (right == -1 && left == INT_MIN)
-    {
-        //Special check for INT_MIN/-1
-        return true;
-    }
-    *pResult = left % right;
-    return false;
-}
-
 bool
 Int32Math::Shr(int32 left, int32 right, int32 *pResult)
 {
@@ -137,75 +97,3 @@ Int32Math::ShrU(int32 left, int32 right, int32 *pResult)
     *pResult = uResult;
     return false;
 }
-
-bool
-Int32Math::And(int32 left, int32 right, int32 *pResult)
-{
-    *pResult = left & right;
-    return false;
-}
-
-bool
-Int32Math::Or(int32 left, int32 right, int32 *pResult)
-{
-    *pResult = left | right;
-    return false;
-}
-
-bool
-Int32Math::Xor(int32 left, int32 right, int32 *pResult)
-{
-    *pResult = left ^ right;
-    return false;
-}
-
-bool
-Int32Math::Neg(int32 val, int32 *pResult)
-{
-    *pResult = -val;
-    return *pResult == INT_MIN;
-}
-
-bool
-Int32Math::Not(int32 val, int32 *pResult)
-{
-    *pResult = ~val;
-    return false;
-}
-
-bool
-Int32Math::Inc(int32 val, int32 *pResult)
-{
-#ifdef _MSC_VER
-    *pResult = val + 1;
-    // Overflow if result ends up less than input
-    return *pResult <= val;
-#elif defined(__APPLE__)
-    *pResult = val + 1;
-    return val == INT32_MAX; // Overflow if val was int max
-#else
-    return __builtin_add_overflow(val, 1, pResult);
-#endif
-}
-
-bool
-Int32Math::Dec(int32 val, int32 *pResult)
-{
-#ifdef _MSC_VER
-    *pResult = val - 1;
-    // Overflow if result ends up greater than input
-    return *pResult >= val;
-#elif defined(__APPLE__)
-    *pResult = val - 1;
-    return val == INT32_MIN; // Overflow if val was int min
-#else
-    return __builtin_sub_overflow(val, 1, pResult);
-#endif
-}
-
-int32
-Int32Math::NearestInRangeTo(const int32 value, const int32 minimum, const int32 maximum) // inclusive
-{
-    Assert(minimum <= maximum);
-    return minimum >= value ? minimum : maximum <= value ? maximum : value;
-}

+ 5 - 14
lib/Common/Common/Int32Math.h

@@ -2,26 +2,17 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-class Int32Math
+#pragma once
+#include "IntMathCommon.h"
+
+class Int32Math: public IntMathCommon<int32>
 {
 public:
     static bool Add(int32 left, int32 right, int32 *pResult);
-    static bool Sub(int32 left, int32 right, int32 *pResult);
     static bool Mul(int32 left, int32 right, int32 *pResult);
     static bool Mul(int32 left, int32 right, int32 *pResult, int32* pOverflowValue);
-    static bool Div(int32 left, int32 right, int32 *pResult);
-    static bool Mod(int32 left, int32 right, int32 *pResult);
+
     static bool Shl(int32 left, int32 right, int32 *pResult);
     static bool Shr(int32 left, int32 right, int32 *pResult);
     static bool ShrU(int32 left, int32 right, int32 *pResult);
-    static bool And(int32 left, int32 right, int32 *pResult);
-    static bool  Or(int32 left, int32 right, int32 *pResult);
-    static bool Xor(int32 left, int32 right, int32 *pResult);
-
-    static bool Neg(int32 val, int32 *pResult);
-    static bool Not(int32 val, int32 *pResult);
-    static bool Inc(int32 val, int32 *pResult);
-    static bool Dec(int32 val, int32 *pResult);
-
-    static int32 NearestInRangeTo(const int32 value, const int32 minimum, const int32 maximum); // inclusive
 };

+ 6 - 112
lib/Common/Common/Int64Math.cpp

@@ -25,18 +25,14 @@
 #endif
 #endif
 
-bool
-Int64Math::Add(int64 left, int64 right, int64 *pResult)
-{
-    // Overflow occurs when the result has a different sign from both the left and right operands
-    *pResult = left + right;
-    return ((left ^ *pResult) & (right ^ *pResult)) < 0;
-}
-
 // Returns true if we overflowed, false if we didn't
 bool
 Int64Math::Mul(int64 left, int64 right, int64 *pResult)
 {
+#if __has_builtin(__builtin_mul_overflow)
+    return IntMathCommon<int64>::Mul(left, right, pResult);
+#else
+
 #if defined(_M_X64)
     int64 high;
     *pResult = _mul128(left, right, &high);
@@ -45,6 +41,8 @@ Int64Math::Mul(int64 left, int64 right, int64 *pResult)
     *pResult = left * right;
     return (left != 0 && right != 0 && (*pResult / left) != right);
 #endif
+
+#endif  // !__has_builtin(__builtin_mul_overflow)
 }
 
 bool
@@ -54,43 +52,6 @@ Int64Math::Shl(int64 left, int64 right, int64 *pResult)
     return (left != (int64)((uint64)*pResult >> right));
 }
 
-bool
-Int64Math::Sub(int64 left, int64 right, int64 *pResult)
-{
-    // Overflow occurs when the result has a different sign from the left operand, and the result has the same sign as the
-    // right operand
-    *pResult = left - right;
-    return ((left ^ *pResult) & ~(right ^ *pResult)) < 0;
-}
-
-bool
-Int64Math::Div(int64 left, int64 right, int64 *pResult)
-{
-    AssertMsg(right != 0, "Divide by zero...");
-
-    if (right == -1 && left == INT64_MIN)
-    {
-        //Special check for INT64_MIN/-1
-        return true;
-    }
-
-    *pResult = left / right;
-    return false;
-}
-
-bool
-Int64Math::Mod(int64 left, int64 right, int64 *pResult)
-{
-    AssertMsg(right != 0, "Mod by zero...");
-    if (right == -1 && left == INT64_MIN)
-    {
-        //Special check for INT64_MIN/-1
-        return true;
-    }
-    *pResult = left % right;
-    return false;
-}
-
 bool
 Int64Math::Shr(int64 left, int64 right, int64 *pResult)
 {
@@ -105,70 +66,3 @@ Int64Math::ShrU(int64 left, int64 right, int64 *pResult)
     *pResult = uResult;
     return false;
 }
-
-bool
-Int64Math::And(int64 left, int64 right, int64 *pResult)
-{
-    *pResult = left & right;
-    return false;
-}
-
-bool
-Int64Math::Or(int64 left, int64 right, int64 *pResult)
-{
-    *pResult = left | right;
-    return false;
-}
-
-bool
-Int64Math::Xor(int64 left, int64 right, int64 *pResult)
-{
-    *pResult = left ^ right;
-    return false;
-}
-
-bool
-Int64Math::Neg(int64 val, int64 *pResult)
-{
-    *pResult = -val;
-    return *pResult == INT64_MIN;
-}
-
-bool
-Int64Math::Not(int64 val, int64 *pResult)
-{
-    *pResult = ~val;
-    return false;
-}
-
-bool
-Int64Math::Inc(int64 val, int64 *pResult)
-{
-    *pResult = val + 1;
-    // Overflow if result ends up less than input
-    return *pResult <= val;
-}
-
-bool
-Int64Math::Dec(int64 val, int64 *pResult)
-{
-    *pResult = val - 1;
-    // Overflow if result ends up greater than input
-    return *pResult >= val;
-}
-
-uint64
-Int64Math::Log2(int64 val)
-{
-    uint64 uval = (uint64)val;
-    uint64 ret;
-    for (ret = 0; uval >>= 1; ret++);
-    return ret;
-}
-
-int64
-Int64Math::NearestInRangeTo(const int64 value, const int64 minimum, const int64 maximum) // inclusive
-{
-    Assert(minimum <= maximum);
-    return minimum >= value ? minimum : maximum <= value ? maximum : value;
-}

+ 3 - 17
lib/Common/Common/Int64Math.h

@@ -2,27 +2,13 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-class Int64Math
+#pragma once
+
+class Int64Math: public IntMathCommon<int64>
 {
 public:
-    static bool Add(int64 left, int64 right, int64 *pResult);
-    static bool Sub(int64 left, int64 right, int64 *pResult);
     static bool Mul(int64 left, int64 right, int64 *pResult);
-    static bool Div(int64 left, int64 right, int64 *pResult);
-    static bool Mod(int64 left, int64 right, int64 *pResult);
     static bool Shl(int64 left, int64 right, int64 *pResult);
     static bool Shr(int64 left, int64 right, int64 *pResult);
     static bool ShrU(int64 left, int64 right, int64 *pResult);
-    static bool And(int64 left, int64 right, int64 *pResult);
-    static bool  Or(int64 left, int64 right, int64 *pResult);
-    static bool Xor(int64 left, int64 right, int64 *pResult);
-
-    static bool Neg(int64 val, int64 *pResult);
-    static bool Not(int64 val, int64 *pResult);
-    static bool Inc(int64 val, int64 *pResult);
-    static bool Dec(int64 val, int64 *pResult);
-
-    static uint64 Log2(int64 val);
-
-    static int64 NearestInRangeTo(const int64 value, const int64 minimum, const int64 maximum); // inclusive
 };

+ 192 - 0
lib/Common/Common/IntMathCommon.h

@@ -0,0 +1,192 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+#pragma once
+
+template <class T>
+struct SignedTypeTraits
+{
+    typedef void UnsignedType;
+};
+
+template <>
+struct SignedTypeTraits<int16>
+{
+    typedef uint16 UnsignedType;
+    static const int16 MinValue = INT16_MIN;
+};
+template <>
+struct SignedTypeTraits<int32>
+{
+    typedef uint32 UnsignedType;
+    static const int32 MinValue = INT32_MIN;
+};
+template <>
+struct SignedTypeTraits<int64>
+{
+    typedef uint64 UnsignedType;
+    static const int64 MinValue = INT64_MIN;
+};
+
+template <class T>
+class IntMathCommon
+{
+public:
+    typedef typename SignedTypeTraits<T>::UnsignedType UnsignedType;
+    static const T MinValue = SignedTypeTraits<T>::MinValue;
+
+    static bool Add(T left, T right, T *pResult);
+    static bool Sub(T left, T right, T *pResult);
+    static bool Mul(T left, T right, T *pResult);
+    static bool Div(T left, T right, T *pResult);
+    static bool Mod(T left, T right, T *pResult);
+    static bool And(T left, T right, T *pResult);
+    static bool  Or(T left, T right, T *pResult);
+    static bool Xor(T left, T right, T *pResult);
+
+    static bool Neg(T val, T *pResult);
+    static bool Not(T val, T *pResult);
+    static bool Inc(T val, T *pResult);
+    static bool Dec(T val, T *pResult);
+
+    static T NearestInRangeTo(const T value, const T minimum, const T maximum); // inclusive
+};
+
+
+template <class T>
+bool IntMathCommon<T>::Add(T left, T right, T *pResult)
+{
+#if __has_builtin(__builtin_add_overflow)
+    return __builtin_add_overflow(left, right, pResult);
+#else
+    // Overflow occurs when the result has a different sign from both the
+    // left and right operands
+    *pResult = static_cast<T>(
+        static_cast<UnsignedType>(left) + static_cast<UnsignedType>(right));
+    return ((left ^ *pResult) & (right ^ *pResult)) < 0;
+#endif
+}
+
+template <class T>
+bool IntMathCommon<T>::Sub(T left, T right, T *pResult)
+{
+#if __has_builtin(__builtin_sub_overflow)
+    return __builtin_sub_overflow(left, right, pResult);
+#else
+    // Overflow occurs when the result has a different sign from the left
+    // operand, and the result has the same sign as the right operand
+    *pResult = static_cast<T>(
+        static_cast<UnsignedType>(left) - static_cast<UnsignedType>(right));
+    return ((left ^ *pResult) & ~(right ^ *pResult)) < 0;
+#endif
+}
+
+#if __has_builtin(__builtin_mul_overflow)
+template <class T>
+bool IntMathCommon<T>::Mul(T left, T right, T *pResult)
+{
+    return __builtin_mul_overflow(left, right, pResult);
+}
+#endif
+
+template <class T>
+bool IntMathCommon<T>::Div(T left, T right, T *pResult)
+{
+    AssertMsg(right != 0, "Divide by zero...");
+
+    if (right == -1 && left == MinValue)
+    {
+        // Special check for MinValue/-1
+        return true;
+    }
+
+    *pResult = left / right;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Mod(T left, T right, T *pResult)
+{
+    AssertMsg(right != 0, "Mod by zero...");
+    if (right == -1 && left == MinValue)
+    {
+        //Special check for MinValue/-1
+        return true;
+    }
+    *pResult = left % right;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::And(T left, T right, T *pResult)
+{
+    *pResult = left & right;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Or(T left, T right, T *pResult)
+{
+    *pResult = left | right;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Xor(T left, T right, T *pResult)
+{
+    *pResult = left ^ right;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Neg(T val, T *pResult)
+{
+    if (val == MinValue)
+    {
+        *pResult = val;
+        return true;
+    }
+    *pResult = - val;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Not(T val, T *pResult)
+{
+    *pResult = ~val;
+    return false;
+}
+
+template <class T>
+bool IntMathCommon<T>::Inc(T val, T *pResult)
+{
+#if __has_builtin(__builtin_add_overflow)
+    return __builtin_add_overflow(val, 1, pResult);
+#else
+    *pResult = static_cast<T>(
+        static_cast<UnsignedType>(val) + static_cast<UnsignedType>(1));
+    // Overflow if result ends up less than input
+    return *pResult <= val;
+#endif
+}
+
+template <class T>
+bool IntMathCommon<T>::Dec(T val, T *pResult)
+{
+#if __has_builtin(__builtin_sub_overflow)
+    return __builtin_sub_overflow(val, 1, pResult);
+#else
+    *pResult = static_cast<T>(
+        static_cast<UnsignedType>(val) - static_cast<UnsignedType>(1));
+    // Overflow if result ends up greater than input
+    return *pResult >= val;
+#endif
+}
+
+template <class T>
+T IntMathCommon<T>::NearestInRangeTo(const T value, const T minimum, const T maximum) // inclusive
+{
+    Assert(minimum <= maximum);
+    return minimum >= value ? minimum : maximum <= value ? maximum : value;
+}

+ 4 - 0
lib/Common/CommonPal.h

@@ -47,6 +47,10 @@
 #define CLANG_WNO_END
 #endif
 
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
 #ifdef _WIN32
 #pragma warning(push)
 #pragma warning(disable: 4995) /* 'function': name was marked as #pragma deprecated */

+ 2 - 3
lib/JITClient/JITManager.h

@@ -124,10 +124,9 @@ public:
         __in intptr_t threadContextInfoAddress)
         { Assert(false); return E_FAIL; }
 
-    HRESULT AddPropertyRecordArray(
+    HRESULT UpdatePropertyRecordMap(
         __in intptr_t threadContextInfoAddress,
-        __in unsigned int count,
-        __in PropertyRecordIDL ** propertyRecordArray)
+        __in UpdatedPropertysIDL * updatedProps)
         { Assert(false); return E_FAIL; }
 
     HRESULT AddDOMFastPathHelper(

+ 1 - 1
lib/Runtime/Language/DynamicProfileStorage.h

@@ -52,7 +52,7 @@ private:
     static DWORD const FileFormatVersion;
 #ifdef _WIN32
     typedef DWORD TimeType;
-	static inline TimeType GetCreationTime() { return _time32(NULL); }
+    static inline TimeType GetCreationTime() { return _time32(NULL); }
 #else
     typedef time_t TimeType;
     static inline TimeType GetCreationTime() { return time(NULL); }

+ 2 - 1
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -6149,7 +6149,8 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             //       and do ISB only for 1st time this entry point is called (potential working set regression though).
             _InstructionSynchronizationBarrier();
 #endif
-            uint newOffset = ::Math::PointerCastToIntegral<uint>(address(function, CallInfo(CallFlags_InternalFrame, 1), this));
+            uint newOffset = ::Math::PointerCastToIntegral<uint>(
+                CALL_ENTRYPOINT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
 
 #ifdef _M_IX86
             _asm

+ 4 - 4
lib/Runtime/Language/TaggedInt.cpp

@@ -515,9 +515,9 @@ LblDone:
 
 #if INT32VAR
         Var result = aValue;
-        (*(int *)&result)++;
+        (*(unsigned int *)&result)++;  // unsigned to avoid signed int overflow
 #else
-        int n = reinterpret_cast<int>(aValue);
+        unsigned int n = reinterpret_cast<unsigned int>(aValue);
         n += 2;
         Var result = reinterpret_cast<Var>(n);
 #endif
@@ -558,9 +558,9 @@ LblDone:
 
 #if INT32VAR
         Var result = aValue;
-        (*(int *)&result)--;
+        (*(unsigned int *)&result)--;  // unsigned to avoid signed int overflow
 #else
-        int n = reinterpret_cast<int>(aValue);
+        unsigned int n = reinterpret_cast<unsigned int>(aValue);
         n -= 2;
         Var result = reinterpret_cast<Var>(n);
 #endif

+ 4 - 4
lib/Runtime/Language/amd64/amd64_Thunks.S

@@ -252,14 +252,14 @@ NESTED_END _ZN2Js21InterpreterStackFrame19InterpreterAsmThunkEPNS_20AsmJsCallSta
 
 //extrn ?GetStackSizeForAsmJsUnboxing@Js@@YAHPEAVScriptFunction@1@@Z: PROC
 //extrn ?UnboxAsmJsArguments@Js@@YAPEAXPEAVScriptFunction@1@PEAPEAXPEADUCallInfo@1@@Z : PROC
-// extrn ?BoxAsmJsReturnValue@Js@@YAPEAXPEAVScriptFunction@1@HNM@Z : PROC
+//extrn ?BoxAsmJsReturnValue@Js@@YAPEAXPEAVScriptFunction@1@HNM@Z : PROC
 //extrn ?BoxAsmJsReturnValue@Js@@YAPEAXPEAVScriptFunction@1@HNMT__m128@@@Z : PROC
 
 //extrn ?GetArgsSizesArray@Js@@YAPEAIPEAVScriptFunction@1@@Z : PROC
 
-// int Js::AsmJsExternalEntryPoint(RecyclableObject* entryObject, CallInfo callInfo, ...)// 
+// int Js::AsmJsExternalEntryPoint(RecyclableObject* entryObject, CallInfo callInfo, ...)
 .balign 16
-NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler        
+NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
         push_nonvol_reg rbp             // push rbp and adjust CFA offset
         lea  rbp, [rsp]
 
@@ -348,7 +348,7 @@ NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfo
         pop r12         // r12: func
         pop r13         // r13: orig stack pointer
 
-        // "home" arg0. other args were read from stack and already homed. 
+        // "home" arg0. other args were read from stack and already homed.
         mov [rsp + 00h], rdi
 
         // call entry point

+ 57 - 68
lib/Runtime/Library/amd64/JavascriptFunctionA.S

@@ -135,135 +135,124 @@ LEAF_END _ZN2Js18JavascriptFunction17CallAsmJsFunctionIdEET_PNS_16RecyclableObje
 // int CallAsmJsFunction<int>(RecyclableObject *function, JavascriptMethod entryPoint, uint argc, Var *argv);
 .balign 16
 NESTED_ENTRY _ZN2Js18JavascriptFunction17CallAsmJsFunctionIiEET_PNS_16RecyclableObjectEPFPvS4_NS_8CallInfoEzEjPS5_, _TEXT, NoHandler
+        push_nonvol_reg rbp
+        mov rbp, rsp
 
-        // save these to stack for interpreter
-        mov qword ptr [rsp + 8h],  rcx
-        mov qword ptr [rsp + 10h], rdx
-        mov qword ptr [rsp + 18h], r8
-        mov qword ptr [rsp + 20h], r9
+        // Set to compute CFA as: rbp + 2 words (RA, rbp)
+        set_cfa_register rbp, (2*8)
 
         push rbx
-        push rsi
-        push rdi
         push r12
         push r13
-        push rbp
-        lea rbp, [rsp]
-
-        // The first 4 QWORD args are passed in rcx, rdx/xmm1, r8/xmm2 and r9/xmm3,
-        // upon entry rcx contains function *.
-        sub rsp, 8h
+        push r15
 
+        // rdi: function
 
+        // rax: entry point
+        mov rax, rsi
 
-        // rbx = argc
-        mov rbx, r8
+        // rbx: argc
+        mov rbx, rdx
 
-        // save entry point into rax.
-        mov rax, rdx
+        // r15: argv
+        mov r15, rcx
+        add r15, 8h
 
-        xor r10d, r10d
-
-        // rsi = argv
-        mov rsi, r9
-        add rsi, 8h
-
-        // get map of args sizes for this function
+        // int GetArgsSizesArray(ScriptFunction* func)
         push rax
-        push rcx
-        sub rsp, 20h
-        call _ZN2Js17GetArgsSizesArrayEPNS_14ScriptFunctionE
+        push rdi
+        call C_FUNC(_ZN2Js17GetArgsSizesArrayEPNS_14ScriptFunctionE)
         mov r12, rax
-        add rsp, 20h
-        pop rcx
+        pop rdi
         pop rax
 
         // int GetStackSizeForAsmJsUnboxing(ScriptFunction* func)
         // This will return 0x20 bytes if size is below minimum. Includes space for function*.
         push rax
-        push rcx
-        sub rsp, 20h
-        call _ZN2Js28GetStackSizeForAsmJsUnboxingEPNS_14ScriptFunctionE
+        push rdi
+        call C_FUNC(_ZN2Js28GetStackSizeForAsmJsUnboxingEPNS_14ScriptFunctionE)
         mov r13, rax
-        add rsp, 20h
-        pop rcx
+        pop rdi
         pop rax
 
-setup_stack_and_reg_args:
+LOCAL_LABEL(setup_stack_and_reg_args):
 
         // OP_CallAsmInternal checks stack space
 
-stack_alloc:
+LOCAL_LABEL(stack_alloc):
         sub  rsp, r13
 
         // copy all args to the new stack frame.
-        lea r11, [rsi]
-        lea r10, [rsp + 8] // copy after ScriptFunction*
-copy_stack_args:
-        mov rdi, qword ptr [r11]
-        mov qword ptr [r10], rdi
+        lea r11, [r15]
+        lea r10, [rsp + 8]      // copy after ScriptFunction*
+        push r13                // save r13
+LOCAL_LABEL(copy_stack_args):
+        mov rsi, qword ptr [r11]
+        mov qword ptr [r10], rsi
         add r11, 8
         add r10, 8
         sub r13, 8
-        cmp r13, 0
-        jg copy_stack_args
+        cmp r13, 8  // skipped 1
+        jg LOCAL_LABEL(copy_stack_args)
+        pop r13                 // restore r13
 
         // r12 points to arg size map
-setup_reg_args_1:
-        lea r11, [rsi]
+LOCAL_LABEL(setup_reg_args_1):
+        lea r11, [r15]
         // argc < 1 ?
         cmp rbx, 1h
-        jl setup_args_done
+        jl LOCAL_LABEL(setup_args_done)
         cmp dword ptr[r12], 10h
-        je SIMDArg1
-        mov rdx, qword ptr [r11]
+        je LOCAL_LABEL(SIMDArg1)
+        mov rsi, qword ptr [r11]
         movq xmm1, qword ptr [r11]
         add r11, 8h
-        jmp setup_reg_args_2
-SIMDArg1:
+        jmp LOCAL_LABEL(setup_reg_args_2)
+LOCAL_LABEL(SIMDArg1):
         movups xmm1, xmmword ptr [r11]
         add r11, 10h
 
-setup_reg_args_2:
+LOCAL_LABEL(setup_reg_args_2):
         // argc < 2 ?
         cmp rbx, 2h
-        jl setup_args_done
+        jl LOCAL_LABEL(setup_args_done)
 
         add r12, 4
         cmp dword ptr[r12], 10h
-        je SIMDArg2
-        mov r8, qword ptr [r11]
+        je LOCAL_LABEL(SIMDArg2)
+        mov rdx, qword ptr [r11]
         movq xmm2, qword ptr [r11]
         add r11, 8h
-        jmp setup_reg_args_3
-SIMDArg2:
+        jmp LOCAL_LABEL(setup_reg_args_3)
+LOCAL_LABEL(SIMDArg2):
         movups xmm2, xmmword ptr [r11]
         add r11, 10h
 
-setup_reg_args_3:
+LOCAL_LABEL(setup_reg_args_3):
         // argc < 3 ?
         cmp rbx, 3h
-        jl setup_args_done
+        jl LOCAL_LABEL(setup_args_done)
         add r12, 4
         cmp dword ptr[r12], 10h
-        je SIMDArg3
-        mov r9, qword ptr [r11]
+        je LOCAL_LABEL(SIMDArg3)
+        mov rcx, qword ptr [r11]
         movq xmm3, qword ptr [r11]
-SIMDArg3:
+LOCAL_LABEL(SIMDArg3):
         movups xmm3, xmmword ptr [r11]
 
-setup_args_done:
+LOCAL_LABEL(setup_args_done):
+        // "home" arg0. other args already copied.
+        mov [rsp], rdi
         call rax
-done:
-        lea rsp, [rbp]
-        pop rbp
+        add rsp, r13            // restore stack
+
+// done:
+        pop r15
         pop r13
         pop r12
-        pop rdi
-        pop rsi
         pop rbx
+        pop_nonvol_reg rbp
         ret
-
 NESTED_END _ZN2Js18JavascriptFunction17CallAsmJsFunctionIiEET_PNS_16RecyclableObjectEPFPvS4_NS_8CallInfoEzEjPS5_, _TEXT
 
 #endif // _ENABLE_ASM_JS

+ 2 - 1
lib/Runtime/PlatformAgnostic/Platform/Linux/UnicodeText.ICU.cpp

@@ -252,7 +252,8 @@ namespace PlatformAgnostic
                 Assert(false);
             }
 
-            if (U_FAILURE(errorCode))
+            if (U_FAILURE(errorCode) &&
+                !(destLength == 0 && errorCode == U_BUFFER_OVERFLOW_ERROR))
             {
                 *pErrorOut = TranslateUErrorCode(errorCode);
                 return -1;

+ 0 - 5
pal/inc/rt/palrt.h

@@ -890,11 +890,6 @@ Remember to fix the errcode defintion in safecrt.h.
 #define _vscprintf _vscprintf_unsafe
 #define _vscwprintf _vscwprintf_unsafe
 
-// #define sprintf_s _snprintf
-// #define swprintf_s _snwprintf
-// #define vsprintf_s _vsnprintf
-// #define vswprintf_s _vsnwprintf
-
 extern "C++" {
 
 #include <safemath.h>