Esempio n. 1
0
void CodeGenWorkItem::OnAddToJitQueue()
{
    Assert(!this->isInJitQueue);
    this->isInJitQueue = true;
    VerifyJitMode();

    this->entryPointInfo->SetCodeGenQueued();
    if(IS_JS_ETW(EventEnabledJSCRIPT_FUNCTION_JIT_QUEUED()))
    {
        WCHAR displayNameBuffer[256];
        WCHAR* displayName = displayNameBuffer;
        size_t sizeInChars = this->GetDisplayName(displayName, 256);
        if(sizeInChars > 256)
        {
            displayName = HeapNewArray(WCHAR, sizeInChars);
            this->GetDisplayName(displayName, 256);
        }
        JS_ETW(EventWriteJSCRIPT_FUNCTION_JIT_QUEUED(
            this->GetFunctionNumber(),
            displayName,
            this->GetScriptContext(),
            this->GetInterpretedCount()));

        if(displayName != displayNameBuffer)
        {
            HeapDeleteArray(sizeInChars, displayName);
        }
    }
}
Esempio n. 2
0
void CodeGenWorkItem::OnRemoveFromJitQueue(NativeCodeGenerator* generator)
{
    // This is called from within the lock

    this->isInJitQueue = false;
    this->entryPointInfo->SetCodeGenPending();
    functionBody->GetScriptContext()->GetThreadContext()->UnregisterCodeGenRecyclableData(this->recyclableData);
    this->recyclableData = nullptr;

    if(IS_JS_ETW(EventEnabledJSCRIPT_FUNCTION_JIT_DEQUEUED()))
    {
        WCHAR displayNameBuffer[256];
        WCHAR* displayName = displayNameBuffer;
        size_t sizeInChars = this->GetDisplayName(displayName, 256);
        if(sizeInChars > 256)
        {
            displayName = HeapNewArray(WCHAR, sizeInChars);
            this->GetDisplayName(displayName, 256);
        }
        JS_ETW(EventWriteJSCRIPT_FUNCTION_JIT_DEQUEUED(
            this->GetFunctionNumber(),
            displayName,
            this->GetScriptContext(),
            this->GetInterpretedCount()));

        if(displayName != displayNameBuffer)
        {
            HeapDeleteArray(sizeInChars, displayName);
        }
    }

    if(this->Type() == JsLoopBodyWorkItemType)
    {
        // Go ahead and delete it and let it re-queue if more interpreting of the loop happens
        auto loopBodyWorkItem = static_cast<JsLoopBodyCodeGen*>(this);
        loopBodyWorkItem->loopHeader->ResetInterpreterCount();
        loopBodyWorkItem->GetEntryPoint()->Reset();
        HeapDelete(loopBodyWorkItem);
    }
    else
    {
        Assert(GetJitMode() == ExecutionMode::FullJit); // simple JIT work items are not removed from the queue

        GetFunctionBody()->OnFullJitDequeued(static_cast<Js::FunctionEntryPointInfo *>(GetEntryPoint()));

        // Add it back to the list of available functions to be jitted
        generator->AddWorkItem(this);
    }
}
    void JavascriptExternalFunction::PrepareExternalCall(Js::Arguments * args)
    {
        ScriptContext * scriptContext = this->type->GetScriptContext();
        Assert(!scriptContext->GetThreadContext()->IsDisableImplicitException());
        scriptContext->VerifyAlive();

        Assert(scriptContext->GetThreadContext()->IsScriptActive());

        if (args->Info.Count == 0)
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined);
        }

        Var &thisVar = args->Values[0];

        Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(thisVar);

        this->callCount++;
        if (IS_JS_ETW(EventEnabledJSCRIPT_HOSTING_EXTERNAL_FUNCTION_CALL_START()))
        {
            JavascriptFunction* caller = nullptr;

            // Lot the caller function if the call count of the external function pass certain threshold (randomly pick 256)
            // we don't want to call stackwalk too often. The threshold can be adjusted as needed.
            if (callCount >= ETW_MIN_COUNT_FOR_CALLER && ((callCount % ETW_MIN_COUNT_FOR_CALLER) == 0))
            {
                Js::JavascriptStackWalker stackWalker(scriptContext);
                bool foundScriptCaller = false;
                while(stackWalker.GetCaller(&caller))
                {
                    if(caller != nullptr && Js::ScriptFunction::Is(caller))
                    {
                        foundScriptCaller = true;
                        break;
                    }
                }
                if(foundScriptCaller)
                {
                    Var sourceString = caller->EnsureSourceString();
                    Assert(JavascriptString::Is(sourceString));
                    const char16* callerString = Js::JavascriptString::FromVar(sourceString)->GetSz();
                    char16* outString = (char16*)callerString;
                    int length = 0;
                    if (wcschr(callerString, _u('\n')) != NULL || wcschr(callerString, _u('\n')) != NULL)
                    {
                        length = Js::JavascriptString::FromVar(sourceString)->GetLength();
                        outString = HeapNewArray(char16, length+1);
                        int j = 0;
                        for (int i = 0; i < length; i++)
                        {
                            if (callerString[i] != _u('\n') && callerString[i] != L'\r')
                            {
                                outString[j++] = callerString[i];
                            }
                        }
                        outString[j] = L'\0';
                    }
                    JS_ETW(EventWriteJSCRIPT_HOSTING_CALLER_TO_EXTERNAL(scriptContext, this, typeId, outString, callCount));
                    if (outString != callerString)
                    {
                        HeapDeleteArray(length+1, outString);
                    }
#if DBG_DUMP
                    if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostPhase))
                    {
                        Output::Print(_u("Large number of Call to trampoline: methodAddr= %p, Object typeid= %d, caller method= %s, callcount= %d\n"),
                            this, typeId, callerString, callCount);
                    }
#endif
                }
            }
            JS_ETW(EventWriteJSCRIPT_HOSTING_EXTERNAL_FUNCTION_CALL_START(scriptContext, this, typeId));
#if DBG_DUMP
            if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostPhase))
            {
                Output::Print(_u("Call to trampoline: methodAddr= %p, Object typeid= %d\n"), this, typeId);
            }
#endif
        }

        Js::RecyclableObject* directHostObject = nullptr;
        switch(typeId)
        {
        case TypeIds_Integer:
#if FLOATVAR
        case TypeIds_Number:
#endif // FLOATVAR
            Assert(!Js::RecyclableObject::Is(thisVar));
            break;
        default:
            {
                Assert(Js::RecyclableObject::Is(thisVar));

                ScriptContext* scriptContextThisVar = Js::RecyclableObject::FromVar(thisVar)->GetScriptContext();
                // We need to verify "this" pointer is active as well. The problem is that DOM prototype functions are
                // the same across multiple frames, and caller can do function.call(closedthis)
                Assert(!scriptContext->GetThreadContext()->IsDisableImplicitException());
                scriptContextThisVar->VerifyAlive();

                // translate direct host for fastDOM.
                switch(typeId)
                {
                case Js::TypeIds_GlobalObject:
                    {
                        Js::GlobalObject* srcGlobalObject = static_cast<Js::GlobalObject*>(thisVar);
                        directHostObject = srcGlobalObject->GetDirectHostObject();
                        // For jsrt, direct host object can be null. If thats the case don't change it.
                        if (directHostObject != nullptr)
                        {
                            thisVar = directHostObject;
                        }

                    }
                    break;
                case Js::TypeIds_Undefined:
                case Js::TypeIds_Null:
                    {
                        // Call to DOM function with this as "undefined" or "null"
                        // This should be converted to Global object
                        Js::GlobalObject* srcGlobalObject = scriptContextThisVar->GetGlobalObject() ;
                        directHostObject = srcGlobalObject->GetDirectHostObject();
                        // For jsrt, direct host object can be null. If thats the case don't change it.
                        if (directHostObject != nullptr)
                        {
                            thisVar = directHostObject;
                        }
                    }
                    break;
                }
            }
            break;
        }
    }
    Var JavascriptSIMDObject::ToLocaleString(const Var* args, uint numArgs, const char16 *typeString, const T (&laneValues)[N], 
        CallInfo* callInfo, ScriptContext* scriptContext) const
    {
        Assert(args);
        Assert(N == 4 || N == 8 || N == 16);
        if (typeDescriptor == TypeIds_SIMDBool8x16 ||
            typeDescriptor == TypeIds_SIMDBool16x8 ||
            typeDescriptor == TypeIds_SIMDBool32x4)
        {
            return ToString(scriptContext);   //Boolean types does not have toLocaleString.
        }

        // Creating a new arguments list for the JavascriptNumber generated from each lane.The optional SIMDToLocaleString Args are
        //added to this argument list. 
        Var* newArgs = HeapNewArray(Var, numArgs);
        switch (numArgs)
        {
        case 1:
            break;
        case 2:
            newArgs[1] = args[1];
            break;
        case 3:
            newArgs[1] = args[1];
            newArgs[2] = args[2];
            break;
        default:
            Assert(UNREACHED);
        }
        //Locale specifc seperator?? 
        JavascriptString *seperator = JavascriptString::NewWithSz(_u(", "), scriptContext);
        uint idx = 0;
        Var laneVar = nullptr;
        BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("fromCodePoint"));
        char16* stringBuffer = AnewArray(tempAllocator, char16, SIMD_STRING_BUFFER_MAX);
        JavascriptString *result = nullptr;

        swprintf_s(stringBuffer, 1024, typeString);
        result = JavascriptString::NewCopySzFromArena(stringBuffer, scriptContext, scriptContext->GeneralAllocator());

        if (typeDescriptor == TypeIds_SIMDFloat32x4)
        {
            for (; idx < numLanes - 1; ++idx)
            {
                laneVar = JavascriptNumber::ToVarWithCheck(laneValues[idx], scriptContext);
                newArgs[0] = laneVar;
                JavascriptString *laneValue = JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext);
                result = JavascriptString::Concat(result, laneValue);
                result = JavascriptString::Concat(result, seperator);
            }
            laneVar = JavascriptNumber::ToVarWithCheck(laneValues[idx], scriptContext);
            newArgs[0] = laneVar;
            result = JavascriptString::Concat(result, JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext));
        }
        else if (typeDescriptor == TypeIds_SIMDInt8x16 || typeDescriptor == TypeIds_SIMDInt16x8 || typeDescriptor == TypeIds_SIMDInt32x4)
        {
            for (; idx < numLanes - 1; ++idx)
            {
                laneVar = JavascriptNumber::ToVar(static_cast<int>(laneValues[idx]), scriptContext); 
                newArgs[0] = laneVar;
                JavascriptString *laneValue = JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext);
                result = JavascriptString::Concat(result, laneValue);
                result = JavascriptString::Concat(result, seperator);
            }
            laneVar = JavascriptNumber::ToVar(static_cast<int>(laneValues[idx]), scriptContext);
            newArgs[0] = laneVar;
            result = JavascriptString::Concat(result, JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext));
        }
        else
        {
            Assert((typeDescriptor == TypeIds_SIMDUint8x16 || typeDescriptor == TypeIds_SIMDUint16x8 || typeDescriptor == TypeIds_SIMDUint32x4));
            for (; idx < numLanes - 1; ++idx)
            {
                laneVar = JavascriptNumber::ToVar(static_cast<uint>(laneValues[idx]), scriptContext); 
                newArgs[0] = laneVar;
                JavascriptString *laneValue = JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext);
                result = JavascriptString::Concat(result, laneValue);
                result = JavascriptString::Concat(result, seperator);
            }
            laneVar = JavascriptNumber::ToVar(static_cast<uint>(laneValues[idx]), scriptContext);
            newArgs[0] = laneVar;
            result = JavascriptString::Concat(result, JavascriptNumber::ToLocaleStringIntl(newArgs, *callInfo, scriptContext));
        }
        HeapDeleteArray(numArgs, newArgs);
        END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
        return JavascriptString::Concat(result, JavascriptString::NewWithSz(_u(")"), scriptContext));
    }