فهرست منبع

Bugfix in the stack allocation for asm.js, correctly calculated how many vars are needed to allocate all the memory needed taking alignment into account.
Some improvement to the asm.js function entry jit tracing + compile only in test builds

Michael Ferris 9 سال پیش
والد
کامیت
f3b970d142

+ 15 - 3
lib/Backend/IRBuilderAsmJs.cpp

@@ -129,10 +129,12 @@ IRBuilderAsmJs::Build()
         BuildImplicitArgIns();
     }
 
-    if (PHASE_TRACE(Js::AsmjsFunctionEntryPhase, m_func))
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
+    if (!this->IsLoopBody() && PHASE_TRACE(Js::AsmjsFunctionEntryPhase, m_func))
     {
         BuildArgInTracing();
     }
+#endif
 
     if (m_statementReader.AtStatementBoundary(&m_jnReader))
     {
@@ -364,7 +366,7 @@ IR::RegOpnd *
 IRBuilderAsmJs::BuildIntConstOpnd(Js::RegSlot regSlot)
 {
     Js::Var * constTable = (Js::Var*)m_func->GetJITFunctionBody()->GetConstTable();
-    WAsmJs::TypedSlotInfo info = m_func->GetJITFunctionBody()->GetAsmJsInfo()->GetTypedSlotInfo(WAsmJs::INT32);
+    const WAsmJs::TypedSlotInfo& info = m_func->GetJITFunctionBody()->GetAsmJsInfo()->GetTypedSlotInfo(WAsmJs::INT32);
     int* intConstTable = reinterpret_cast<int*>(((byte*)constTable) + info.constSrcByteOffset);
     Js::RegSlot srcReg = GetTypedRegFromRegSlot(regSlot, WAsmJs::INT32);
     Assert(srcReg >= Js::FunctionBody::FirstRegSlot && srcReg < info.constCount && info.isValidType);
@@ -913,6 +915,7 @@ IRBuilderAsmJs::BuildImplicitArgIns()
     }
 }
 
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
 void
 IRBuilderAsmJs::BuildArgInTracing()
 {
@@ -942,7 +945,6 @@ IRBuilderAsmJs::BuildArgInTracing()
 
     m_argStack->Push(instr);
 
-
     auto PushArg = [&](IRType type, ValueType valueType, IR::Opnd* srcOpnd) {
         StackSym* symDst = StackSym::NewArgSlotSym(argOutSlot++, m_func, type);
         symDst->m_allocated = true;
@@ -954,6 +956,15 @@ IRBuilderAsmJs::BuildArgInTracing()
         m_argStack->Push(instr);
         argSize += max(TySize[type], MachPtr);
     };
+
+    // Move the function object as an argument
+    {
+        StackSym* stackSym = StackSym::New(m_func);
+        IR::RegOpnd* stackOpnd = IR::RegOpnd::New(stackSym, TyVar, m_func);
+        AddInstr(IR::Instr::New(Js::OpCode::LdFuncObj, stackOpnd, m_func), Js::Constants::NoByteCodeOffset);
+
+        PushArg(TyVar, ValueType::GetObject(ObjectType::Object), stackOpnd);
+    }
     PushArg(TyInt32, ValueType::GetInt(false), IR::IntConstOpnd::New(nArgs, TyInt32, m_func));
 
     for (Js::ArgSlot i = 0; i < nArgs; ++i)
@@ -1006,6 +1017,7 @@ IRBuilderAsmJs::BuildArgInTracing()
     BuildAsmCall(Js::OpCodeAsmJs::AsmJsEntryTracing, Js::Constants::NoByteCodeOffset, nArgs * 2 + 1, 0, 0, 0);
 #endif
 }
+#endif
 
 void
 IRBuilderAsmJs::InsertLabels()

+ 2 - 0
lib/Backend/IRBuilderAsmJs.h

@@ -77,7 +77,9 @@ private:
     void                    CreateLoadConstInstrForType(byte* table, Js::RegSlot& regAllocated, uint32 constCount, uint32 offset, IRType irType, ValueType valueType, Js::OpCode opcode, F extraProcess);
     void                    BuildConstantLoads();
     void                    BuildImplicitArgIns();
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
     void                    BuildArgInTracing();
+#endif
     void                    InsertLabels();
     IR::LabelInstr *        CreateLabel(IR::BranchInstr * branchInstr, uint& offset);
 #if DBG

+ 1 - 1
lib/Backend/JnHelperMethodList.h

@@ -531,7 +531,7 @@ HELPERCALL(DirectMath_NearestFlt, (float(*)(float)) Wasm::WasmMath::Nearest<floa
 HELPERCALL(PopCnt32, Math::PopCnt32, 0)
 HELPERCALL(PopCnt64, (int64(*)(int64)) Wasm::WasmMath::PopCnt<int64>, 0)
 
-#if defined(ASMJS_PLAT) || defined(ENABLE_WASM)
+#if (defined(ASMJS_PLAT) || defined(ENABLE_WASM)) && defined(ENABLE_DEBUG_CONFIG_OPTIONS)
 HELPERCALL(TraceAsmJsArgIn, WAsmJs::TraceAsmJsArgsIn, 0)
 #endif
 

+ 2 - 0
lib/Backend/amd64/LowererMDArch.cpp

@@ -573,11 +573,13 @@ LowererMDArch::LowerCallArgs(IR::Instr *callInstr, ushort callFlags, Js::ArgSlot
 
     if (m_func->GetJITFunctionBody()->IsAsmJsMode())
     {
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
         if (callInstr->m_opcode == Js::OpCode::AsmJsEntryTracing)
         {
             callInstr = this->lowererMD->ChangeToHelperCall(callInstr, IR::HelperTraceAsmJsArgIn);
         }
         else
+#endif
         {
             IR::Opnd * functionObjOpnd = callInstr->UnlinkSrc1();
             GeneratePreCall(callInstr, functionObjOpnd, cfgInsertLoc->GetNextRealInstr());

+ 2 - 0
lib/Backend/i386/LowererMDArch.cpp

@@ -884,6 +884,7 @@ LowererMDArch::LowerAsmJsCallI(IR::Instr * callInstr)
     const uint32 argSlots = argCount + (stackAlignment / 4) + 1;
     m_func->m_argSlotsForFunctionsCalled = max(m_func->m_argSlotsForFunctionsCalled, argSlots);
 
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
     if (callInstr->m_opcode == Js::OpCode::AsmJsEntryTracing)
     {
         callInstr = this->lowererMD->ChangeToHelperCall(callInstr, IR::HelperTraceAsmJsArgIn);
@@ -896,6 +897,7 @@ LowererMDArch::LowerAsmJsCallI(IR::Instr * callInstr)
         callInstr->InsertAfter(fixStack);
         return fixStack;
     }
+#endif
 
     IR::Opnd * functionObjOpnd = callInstr->UnlinkSrc1();
 

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

@@ -84,10 +84,8 @@ namespace Js
             }
             asmInfo->SetIsHeapBufferConst(!mUsesChangeHeap);
             asmInfo->SetUsesHeapBuffer(mUsesHeapBuffer);
-            uint32 varCount = func->GetTotalJsVarCount();
 
             functionBody->CheckAndSetOutParamMaxDepth(func->GetMaxArgOutDepth());
-            functionBody->CheckAndSetVarCount(varCount);
             // should be set in EmitOneFunction
             Assert(functionBody->GetIsAsmjsMode());
             Assert(functionBody->GetIsAsmJsFunction());

+ 1 - 1
lib/Runtime/Language/AsmJsTypes.cpp

@@ -925,7 +925,7 @@ namespace Js
 
     bool AsmJsFunctionInfo::Init(AsmJsFunc* func)
     {
-        func->CommitToFunctionInfo(this);
+        func->CommitToFunctionInfo(this, func->GetFuncBody());
 
         Recycler* recycler = func->GetFuncBody()->GetScriptContext()->GetRecycler();
         mArgCount = func->GetArgCount();

+ 1 - 2
lib/Runtime/Language/AsmJsTypes.h

@@ -796,9 +796,8 @@ namespace Js
         void UpdateMaxArgOutDepth(int outParamsCount);
         inline int GetArgOutDepth() const{ return mArgOutDepth; }
         inline int GetMaxArgOutDepth() const{ return mMaxArgOutDepth; }
-        void CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo) {mTypedRegisterAllocator.CommitToFunctionInfo(funcInfo);}
+        void CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo, FunctionBody* body) {mTypedRegisterAllocator.CommitToFunctionInfo(funcInfo, body);}
         void CommitToFunctionBody(FunctionBody* body) { mTypedRegisterAllocator.CommitToFunctionBody(body); }
-        uint32 GetTotalJsVarCount() { return mTypedRegisterAllocator.GetTotalJsVarCount(); }
     };
 
     struct MathBuiltin

+ 57 - 31
lib/Runtime/Language/WAsmjsUtils.cpp

@@ -10,11 +10,15 @@
 namespace WAsmJs
 {
 
-    void TraceAsmJsArgsIn(int n, ...)
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
+    void TraceAsmJsArgsIn(Js::Var function, int n, ...)
     {
+        Assert(Js::AsmJsScriptFunction::Is(function));
+        Js::AsmJsScriptFunction* asmFunction = (Js::AsmJsScriptFunction*)function;
         va_list argptr;
         va_start(argptr, n);
-        Output::Print(_u("Executing function ("));
+
+        Output::Print(_u("Executing function %s("), asmFunction->GetFunctionBody()->GetDisplayName());
         for (int i = 0; i < n ; i++)
         {
             IRType type = (IRType)va_arg(argptr, int32);
@@ -40,6 +44,7 @@ namespace WAsmJs
         }
         Output::Print(_u("){\n"));
     }
+#endif
 
     uint32 GetTypeByteSize(Types type)
     {
@@ -162,15 +167,20 @@ namespace WAsmJs
         return total;
     }
 
-    void TypedRegisterAllocator::CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo) const
+    uint32 TypedRegisterAllocator::GetTotalJsVarConstCount() const
+    {
+        return UInt32Math::Add(Js::AsmJsFunctionMemory::RequiredVarConstants, GetTotalJsVarCount(true));
+    }
+
+    void TypedRegisterAllocator::CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo, Js::FunctionBody* body) const
     {
         uint32 offset = Js::AsmJsFunctionMemory::RequiredVarConstants * sizeof(Js::Var);
         WAsmJs::TypedConstSourcesInfo constSourcesInfo = GetConstSourceInfos();
 
 #if DBG_DUMP
-        if (PHASE_TRACE1(Js::AsmjsInterpreterStackPhase))
+        if (PHASE_TRACE(Js::AsmjsInterpreterStackPhase, body))
         {
-            Output::Print(_u("ASMFunctionInfo Stack Data\n"));
+            Output::Print(_u("ASMFunctionInfo Stack Data for %s\n"), body->GetDisplayName());
             Output::Print(_u("==========================\n"));
             Output::Print(_u("RequiredVarConstants:%d\n"), Js::AsmJsFunctionMemory::RequiredVarConstants);
         }
@@ -180,52 +190,68 @@ namespace WAsmJs
         {
             Types type = (Types)i;
 
-            TypedSlotInfo* slotInfo = funcInfo->GetTypedSlotInfo(type);
+            TypedSlotInfo& slotInfo = *funcInfo->GetTypedSlotInfo(type);
             // Check if we don't want to commit this type
             if (!IsTypeExcluded(type))
             {
                 RegisterSpace* registerSpace = GetRegisterSpace(type);
-                slotInfo->isValidType = true;
-                slotInfo->constCount = registerSpace->GetConstCount();
-                slotInfo->varCount = registerSpace->GetVarCount();
-                slotInfo->tmpCount = registerSpace->GetTmpCount();
-                slotInfo->constSrcByteOffset = constSourcesInfo.srcByteOffsets[i];
+                slotInfo.isValidType = true;
+                slotInfo.constCount = registerSpace->GetConstCount();
+                slotInfo.varCount = registerSpace->GetVarCount();
+                slotInfo.tmpCount = registerSpace->GetTmpCount();
+                slotInfo.constSrcByteOffset = constSourcesInfo.srcByteOffsets[i];
 
                 offset = Math::AlignOverflowCheck(offset, GetTypeByteSize(type));
-                slotInfo->byteOffset = offset;
+                slotInfo.byteOffset = offset;
+
+                // Update offset for next type
+                uint32 totalTypeCount = 0;
+                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo.constCount);
+                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo.varCount);
+                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo.tmpCount);
 
+                offset = UInt32Math::Add(offset, UInt32Math::Mul(totalTypeCount, GetTypeByteSize(type)));
 #if DBG_DUMP
-                if (PHASE_TRACE1(Js::AsmjsInterpreterStackPhase))
+                if (PHASE_TRACE(Js::AsmjsInterpreterStackPhase, body))
                 {
                     char16 buf[16];
                     RegisterSpace::GetTypeDebugName(type, buf, 16);
-                    Output::Print(_u("%s Offset:%d  ConstCount:%d  VarCount:%d  TmpCount:%d\n"),
+                    Output::Print(_u("%s Offset:%d  ConstCount:%d  VarCount:%d  TmpCount:%d = %d * %d = 0x%x bytes\n"),
                                   buf,
-                                  slotInfo->byteOffset,
-                                  slotInfo->constCount,
-                                  slotInfo->varCount,
-                                  slotInfo->tmpCount);
+                                  slotInfo.byteOffset,
+                                  slotInfo.constCount,
+                                  slotInfo.varCount,
+                                  slotInfo.tmpCount,
+                                  totalTypeCount,
+                                  GetTypeByteSize(type),
+                                  totalTypeCount * GetTypeByteSize(type));
                 }
 #endif
-
-                // Update offset for next type
-                uint32 totalTypeCount = 0;
-                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo->constCount);
-                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo->varCount);
-                totalTypeCount = UInt32Math::Add(totalTypeCount, slotInfo->tmpCount);
-
-                offset = UInt32Math::Add(offset, UInt32Math::Mul(totalTypeCount, GetTypeByteSize(type)));
             }
             else
             {
-                memset(slotInfo, 0, sizeof(TypedSlotInfo));
-                slotInfo->isValidType = false;
+                memset(&slotInfo, 0, sizeof(TypedSlotInfo));
+                slotInfo.isValidType = false;
             }
         }
+
+        // These bytes offset already calculated the alignment, used them to determine how many Js::Var we need to do the allocation
+        uint32 stackByteSize = offset;
+        uint32 jsVarNeededForConsts = GetTotalJsVarConstCount();
+        Assert(stackByteSize >= jsVarNeededForConsts * sizeof(Js::Var));
+        // The vars need to compensate the possible alignment done, so instead of counting how many vars we have
+        // We substract the number of const from the total size needed
+        uint32 jsVarNeededForVars = ConvertOffset<byte, Js::Var>(stackByteSize) - jsVarNeededForConsts;
+        Assert((jsVarNeededForConsts + jsVarNeededForVars) * sizeof(Js::Var) >= stackByteSize);
+        body->CheckAndSetVarCount(jsVarNeededForVars);
+
 #if DBG_DUMP
-        if (PHASE_TRACE1(Js::AsmjsInterpreterStackPhase))
+        if (PHASE_TRACE(Js::AsmjsInterpreterStackPhase, body))
         {
-            Output::Print(_u("\n"));
+            Output::Print(_u("Total memory required: (%d consts + %d vars) * sizeof(Js::Var) >= 0x%x bytes\n"),
+                          jsVarNeededForConsts,
+                          jsVarNeededForVars,
+                          stackByteSize);
         }
 #endif
     }
@@ -233,7 +259,7 @@ namespace WAsmJs
     void TypedRegisterAllocator::CommitToFunctionBody(Js::FunctionBody* body)
     {
         // this value is the number of Var slots needed to allocate all the const
-        const uint32 nbConst = UInt32Math::Add(Js::AsmJsFunctionMemory::RequiredVarConstants, GetTotalJsVarCount(true));
+        const uint32 nbConst = GetTotalJsVarConstCount();
         body->CheckAndSetConstantCount(nbConst);
     }
 

+ 7 - 4
lib/Runtime/Language/WAsmjsUtils.h

@@ -14,7 +14,9 @@ namespace WAsmJs
     static const double INT_SLOTS_SPACE = (sizeof(int) / (double)sizeof(Js::Var)); // 1 in x86 and 0.5 in x64
     static const double SIMD_SLOTS_SPACE = (sizeof(SIMDValue) / sizeof(Js::Var)); // 4 in x86 and 2 in x64
 
-    void TraceAsmJsArgsIn(int n, ...);
+#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
+    void TraceAsmJsArgsIn(Js::Var function, int n, ...);
+#endif
 
     typedef Js::RegSlot RegSlot;
 
@@ -271,9 +273,7 @@ namespace WAsmJs
     public:
         TypedRegisterAllocator(ArenaAllocator* allocator, AllocateRegisterSpaceFunc allocateFunc, uint32 excludedMask = 0);
 
-        uint32 GetJsVarCount(Types type, bool constOnly /*= false*/) const;
-        uint32 GetTotalJsVarCount(bool constOnly = false) const;
-        void CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo) const;
+        void CommitToFunctionInfo(Js::AsmJsFunctionInfo* funcInfo, Js::FunctionBody* body) const;
         void CommitToFunctionBody(Js::FunctionBody* body);
         TypedConstSourcesInfo GetConstSourceInfos() const;
 
@@ -286,6 +286,9 @@ namespace WAsmJs
 
         RegisterSpace* GetRegisterSpace(Types type) const;
     private:
+        uint32 GetJsVarCount(Types type, bool constOnly /*= false*/) const;
+        uint32 GetTotalJsVarCount(bool constOnly = false) const;
+        uint32 GetTotalJsVarConstCount() const;
         bool IsValidType(Types type) const;
     };
 };

+ 1 - 2
lib/WasmReader/WasmByteCodeGenerator.cpp

@@ -351,11 +351,10 @@ WasmBytecodeGenerator::GenerateFunction()
 #endif
 
     Js::AsmJsFunctionInfo * info = GetFunctionBody()->GetAsmJsFunctionInfo();
-    mTypedRegisterAllocator.CommitToFunctionInfo(info);
     mTypedRegisterAllocator.CommitToFunctionBody(GetFunctionBody());
+    mTypedRegisterAllocator.CommitToFunctionInfo(info, GetFunctionBody());
 
     GetFunctionBody()->CheckAndSetOutParamMaxDepth(m_maxArgOutDepth);
-    GetFunctionBody()->CheckAndSetVarCount(mTypedRegisterAllocator.GetTotalJsVarCount());
 }
 
 void