Procházet zdrojové kódy

Added support for array type annotations
Improved performance by removing binary searchs
Improved support for type annotations in function parameters

Franco Castellacci před 9 roky
rodič
revize
5ba431ac3c

+ 3 - 1
lib/Backend/GlobOpt.cpp

@@ -5802,7 +5802,7 @@ GlobOpt::OptSrc(IR::Opnd *opnd, IR::Instr * *pInstr, Value **indirIndexValRef, I
                 if (paramSlotNum >= 0)
                 {
                     ValueType parameterType;
-                    if (instr->m_func->GetJITFunctionBody()->GetParameterTypeInfo() != nullptr)
+                    if (CONFIG_FLAG(ParamTypeAnnotations) && instr->m_func->GetJITFunctionBody()->GetParameterTypeInfo() != nullptr)
                     {
                         Js::TypeHint typeHint = (Js::TypeHint) instr->m_func->GetJITFunctionBody()->GetParameterTypeInfo()->content[paramSlotNum];
                         switch (typeHint)
@@ -5819,6 +5819,8 @@ GlobOpt::OptSrc(IR::Opnd *opnd, IR::Instr * *pInstr, Value **indirIndexValRef, I
                             case Js::TypeHint::Object:
                                 parameterType = ValueType::UninitializedObject;
                                 break;
+                            case Js::TypeHint::FloatArray:
+                                parameterType = ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(Js::TypeId::TypeIds_NativeFloatArray);
                             default:
                                 parameterType = instr->m_func->GetReadOnlyProfileInfo()->GetParameterInfo(static_cast<Js::ArgSlot>(paramSlotNum));
                         }

+ 59 - 6
lib/Backend/IRBuilder.cpp

@@ -4507,13 +4507,9 @@ IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot insta
 
     if (CONFIG_FLAG(TypeAnnotations))
     {
-        void* typeAnnotation;
-        if (m_func->GetJITFunctionBody()->GetTypeAnnotationsArray() && (typeAnnotation = bsearch(&offset,
-            m_func->GetJITFunctionBody()->GetTypeAnnotationsArray()->content,
-            m_func->GetJITFunctionBody()->GetTypeAnnotationsArray()->count,
-            sizeof(Js::FunctionBody::TypeInformation), compareTypeInfos)) != nullptr)
+        if (m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx) != nullptr && m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx)->bytecodeOffset == offset)
         {
-            switch (((Js::FunctionBody::TypeInformation*)typeAnnotation)->type)
+            switch ((Js::TypeHint)m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx++)->type)
             {
             case Js::TypeHint::Int:
                 instr->AsProfiledInstr()->u.FldInfo().valueType = ValueType::Int.SetCanBeTaggedValue(true);
@@ -4527,6 +4523,9 @@ IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot insta
             case Js::TypeHint::Object:
                 instr->AsProfiledInstr()->u.FldInfo().valueType = ValueType::UninitializedObject;
                 break;
+            case Js::TypeHint::FloatArray:
+                instr->AsProfiledInstr()->u.FldInfo().valueType = ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(Js::TypeId::TypeIds_NativeFloatArray);
+                break;
             }
         }
     }
@@ -5410,6 +5409,27 @@ IRBuilder::BuildElementI(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRe
 
             regOpnd = this->BuildDstOpnd(regSlot);
 
+            if (CONFIG_FLAG(TypeAnnotations))
+            {
+                if (m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx) != nullptr && m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx)->bytecodeOffset == offset)
+                {
+                    switch ((Js::TypeHint)m_func->GetJITFunctionBody()->GetTypeHint(this->m_currentTypeHintIdx++)->type)
+                    {
+                    case Js::TypeHint::FloatArray:
+                        arrayType = ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(Js::TypeId::TypeIds_NativeFloatArray);
+                        regOpnd->SetValueType(arrayType);
+                        break;
+                    }
+                    if (newOpcode == Js::OpCode::LdElemI_A)
+                    {
+                        Js::LdElemInfo *const newLdElemInfo = JitAnew(m_func->m_alloc, Js::LdElemInfo, *ldElemInfo);
+                        newLdElemInfo->arrayType = arrayType;
+                        newLdElemInfo->elemType = arrayType;
+                        ldElemInfo = newLdElemInfo;
+                    }
+                }
+            }
+
             if (m_func->DoSimpleJitDynamicProfile() && isProfiledInstr)
             {
                 instr = IR::JitProfilingInstr::New(newOpcode, regOpnd, indirOpnd, m_func);
@@ -5667,6 +5687,39 @@ IRBuilder::BuildArgIn(uint32 offset, Js::RegSlot dstRegSlot, uint16 argument)
             dstOpnd->SetValueType(profiledValueType);
         }
     }
+    if (CONFIG_FLAG(ParamTypeAnnotations) && 
+        this->m_func->GetJITFunctionBody()->GetParameterTypeInfo() != nullptr && 
+        this->m_func->GetJITFunctionBody()->GetParameterTypeInfo()->count > 0)
+    {
+        int paramSlotIndex = symSrc->GetParamSlotNum() - 2;
+        if (paramSlotIndex >= 0)
+        {
+            Js::TypeHint typeHint = (Js::TypeHint) this->m_func->GetJITFunctionBody()->GetParameterTypeInfo()->content[paramSlotIndex];
+            switch (typeHint)
+            {
+            case Js::TypeHint::Int:
+                dstOpnd->SetValueType(ValueType::Int.SetCanBeTaggedValue(true));
+                srcOpnd->SetValueType(ValueType::Int.SetCanBeTaggedValue(true));
+                break;
+            case Js::TypeHint::Float:
+                dstOpnd->SetValueType(ValueType::Float.SetCanBeTaggedValue(true));
+                srcOpnd->SetValueType(ValueType::Float.SetCanBeTaggedValue(true));
+                break;
+            case Js::TypeHint::Bool:
+                dstOpnd->SetValueType(ValueType::Boolean);
+                srcOpnd->SetValueType(ValueType::Boolean);
+                break;
+            case Js::TypeHint::Object:
+                dstOpnd->SetValueType(ValueType::UninitializedObject);
+                srcOpnd->SetValueType(ValueType::UninitializedObject);
+                break;
+            case Js::TypeHint::FloatArray:
+                dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(Js::TypeId::TypeIds_NativeFloatArray));
+                srcOpnd->SetValueType(ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(Js::TypeId::TypeIds_NativeFloatArray));
+                break;
+            }
+        }
+    }
 
     instr = IR::Instr::New(Js::OpCode::ArgIn_A, dstOpnd, srcOpnd, m_func);
     this->AddInstr(instr, offset);

+ 3 - 0
lib/Backend/IRBuilder.h

@@ -82,6 +82,7 @@ public:
 #ifdef BYTECODE_BRANCH_ISLAND
         , longBranchMap(nullptr)
 #endif
+        ,m_currentTypeHintIdx(0)
     {
         auto loopCount = func->GetJITFunctionBody()->GetLoopCount();
         if (loopCount > 0) {
@@ -330,6 +331,8 @@ private:
     IRBuilderSwitchAdapter m_switchAdapter;
     SwitchIRBuilder     m_switchBuilder;
 
+    uint32              m_currentTypeHintIdx;
+
     BVFixed *           m_ldSlots;
     BVFixed *           m_stSlots;
 #if DBG

+ 11 - 0
lib/Backend/JITTimeFunctionBody.cpp

@@ -1099,6 +1099,17 @@ TypeAnnotationsArrayIDL * JITTimeFunctionBody::GetTypeAnnotationsArray() const
     return m_bodyData.typeAnnotations;
 }
 
+TypeInformationIDL * JITTimeFunctionBody::GetTypeHint(uint32 idx) const
+{
+    if (m_bodyData.typeAnnotations != nullptr && idx < m_bodyData.typeAnnotations->count)
+    {
+        return &m_bodyData.typeAnnotations->content[idx];
+    } else 
+    {
+        return nullptr;
+    }
+}
+
 ParameterTypeInfoIDL * JITTimeFunctionBody::GetParameterTypeInfo() const
 {
     return m_bodyData.parameterTypeInfo;

+ 1 - 0
lib/Backend/JITTimeFunctionBody.h

@@ -183,6 +183,7 @@ public:
     Js::PropertyIdArray * GetFormalsPropIdArray() const;
     
     TypeAnnotationsArrayIDL* GetTypeAnnotationsArray() const;
+    TypeInformationIDL* GetTypeHint(uint32 idx) const;
     ParameterTypeInfoIDL* GetParameterTypeInfo() const;
 
     Js::ForInCache * GetForInCache(uint profileId) const;

+ 2 - 1
lib/Common/Common.h

@@ -44,7 +44,8 @@ namespace Js
         Float = 4,
         Bool = 5,
         Array = 6,
-        Function = 7
+        Function = 7,
+        FloatArray = 8
     };
 }
 

+ 6 - 0
lib/Common/ConfigFlagsList.h

@@ -706,6 +706,8 @@ PHASE(All)
 #define DEFAULT_CONFIG_SkipSplitWhenResultIgnored (false)
 
 #define DEFAULT_CONFIG_TypeAnnotations (false)
+#define DEFAULT_CONFIG_ParamTypeAnnotations (false)
+#define DEFAULT_CONFIG_RemoveIntOverflow (false)
 
 #define DEFAULT_CONFIG_MinMemOpCount (16U)
 
@@ -1364,7 +1366,11 @@ FLAGNR(Boolean, TraceAsyncDebugCalls  , "Trace calls to async debugging API (def
 #ifdef TRACK_DISPATCH
 FLAGNR(Boolean, TrackDispatch         , "Save stack traces of where JavascriptDispatch/HostVariant are created", false)
 #endif
+//TypeAnnotation Flags:
 FLAGNR(Boolean, TypeAnnotations       , "Enables the usage of type annotations in comments (default: false)", DEFAULT_CONFIG_TypeAnnotations)
+FLAGNR(Boolean, ParamTypeAnnotations  , "Enables the usage of type annotations in function parameters(default: false)", DEFAULT_CONFIG_ParamTypeAnnotations)
+FLAGNR(Boolean, RemoveIntOverflow     , "Removes int overflow checks for operations with annotated operands (default: false)", DEFAULT_CONFIG_RemoveIntOverflow)
+
 FLAGNR(Boolean, Verbose               , "Dump details", DEFAULT_CONFIG_Verbose)
 FLAGNR(Boolean, UseFullName           , "Enable fully qualified name", DEFAULT_CONFIG_UseFullName)
 FLAGNR(Boolean, UseFunctionIdForTrace , "Use function id instead of function number for trace output", false)

+ 9 - 0
lib/Parser/Parse.cpp

@@ -3603,6 +3603,12 @@ ParseNodePtr Parser::ParsePostfixOperators(
                 }
                 break;
             }
+        case tkTypeAnnBegin: 
+            if (CONFIG_FLAG(TypeAnnotations))
+            {
+                AddTypeAnnotationToParseNode<buildAST>(pnode);
+            }
+            break;
         default:
             return pnode;
         }
@@ -6442,6 +6448,9 @@ void Parser::AddTypeAnnotationToParseNode(ParseNodePtr pnode)
         case tkTypeObject:
             pnode->typeHint = Js::TypeHint::Object;
             break;
+        case tkTypeFloatArray:
+            pnode->typeHint = Js::TypeHint::FloatArray;
+            break;
         }
     }
     m_pscan->Scan(); //Leave the scanner pointing to the next token

+ 6 - 0
lib/Parser/Scan.cpp

@@ -1166,6 +1166,12 @@ tokens Scanner<EncodingPolicy>::ScanTypeAnnotationType(EncodedCharPtr *pp)
             token = tkTypeFloat;
             break;
         }
+        else if (p[0] == 'l' && p[1] == 'o' && p[2] == 'a' && p[3] == 't' && p[4] == 'a' && p[5] == 'r' && p[6] == 'r' && p[7] == '}')
+        {
+            p += 8;
+            token = tkTypeFloatArray;
+            break;
+        }
         Error(ERRsyntax);
     case 'b':
         if (p[0] == 'o' && p[1] == 'o' && p[2] == 'l' && p[3] == '}')

+ 1 - 0
lib/Parser/kwd-lsc.h

@@ -186,6 +186,7 @@ TOK_DCL(tkTypeAnnBegin  , No, knopNone   , No, knopNone   ) // /** @type { Marks
 TOK_DCL(tkTypeInt       , No, knopNone   , No, knopNone   )
 TOK_DCL(tkTypeFloat     , No, knopNone   , No, knopNone   )
 TOK_DCL(tkTypeBool      , No, knopNone   , No, knopNone   )
+TOK_DCL(tkTypeFloatArray, No, knopNone   , No, knopNone   )
 TOK_DCL(tkTypeObject    , No, knopNone   , No, knopNone   )
 
 

+ 4 - 0
lib/Runtime/ByteCode/ByteCodeEmitter.cpp

@@ -10757,6 +10757,10 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
             callObjLocation;
 
         EmitSuperMethodBegin(pnode, byteCodeGenerator, funcInfo);
+        if (pnode->typeHint != Js::TypeHint::Unknown)
+        {
+            funcInfo->GetParsedFunctionBody()->AddBytecodeOffsetTypeAnnotation(byteCodeGenerator->Writer()->GetCurrentOffset(), pnode->location, pnode->typeHint);
+        }
         byteCodeGenerator->Writer()->Element(
             Js::OpCode::LdElemI_A, pnode->location, protoLocation, pnode->sxBin.pnode2->location);