Example #1
0
// internal
void asCScriptFunction::JITCompile()
{
	if( funcType != asFUNC_SCRIPT )
		return;

	asASSERT( scriptData );

	asIJITCompiler *jit = engine->GetJITCompiler();
	if( !jit )
		return;

	// Make sure the function has been compiled with JitEntry instructions
	// For functions that has JitEntry this will be a quick test
	asUINT length;
	asDWORD *byteCode = GetByteCode(&length);
	asDWORD *end = byteCode + length;
	bool foundJitEntry = false;
	while( byteCode < end )
	{
		// Determine the instruction
		asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode);
		if( op == asBC_JitEntry )
		{
			foundJitEntry = true;
			break;
		}

		// Move to next instruction
		byteCode += asBCTypeSize[asBCInfo[op].type];
	}

	if( !foundJitEntry )
	{
		asCString msg;
		msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration());
		engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
	}

	// Release the previous function, if any
	if( scriptData->jitFunction )
	{
		engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction);
		scriptData->jitFunction = 0;
	}

	// Compile for native system
	int r = jit->CompileFunction(this, &scriptData->jitFunction);
	if( r < 0 )
		asASSERT( scriptData->jitFunction == 0 );
}
Example #2
0
Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::FunctionInfo* functionInfo,
    bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, Js::ProfileId callSiteId, uint recursiveInlineDepth, bool allowRecursiveInlining)
{
#if defined(DBG_DUMP) || defined(ENABLE_DEBUG_CONFIG_OPTIONS)
    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
    char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
#endif
    Js::FunctionProxy * proxy = functionInfo->GetFunctionProxy();
    if (proxy && proxy->IsFunctionBody())
    {
        if (isLoopBody && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->topFunc))
        {
            INLINE_TESTTRACE_VERBOSE(_u("INLINING: Skip Inline: Jit loop body: %s (%s)\n"), this->topFunc->GetDisplayName(),
                this->topFunc->GetDebugNumberSet(debugStringBuffer));
            return nullptr;
        }

        // Note: disable inline for debugger, as we can't bailout at return from function.
        // Alternative can be generate this bailout as part of inline, which can be done later as perf improvement.
        const auto inlinee = proxy->GetFunctionBody();
        Assert(this->jitMode == ExecutionMode::FullJit);
        if (PHASE_OFF(Js::InlinePhase, inlinee) ||
            PHASE_OFF(Js::GlobOptPhase, inlinee) ||
            !ContinueInliningUserDefinedFunctions(this->bytecodeInlinedCount) ||
            this->isInDebugMode)
        {
            return nullptr;
        }

        if (functionInfo->IsDeferred() || inlinee->GetByteCode() == nullptr)
        {
            // DeferredParse...
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: No bytecode\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (inlinee->GetHasTry())
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Has try\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        // This is a hard limit as the argOuts array is statically sized.
        if (inlinee->GetInParamsCount() > Js::InlineeCallInfo::MaxInlineeArgoutCount)
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count greater then MaxInlineeArgoutCount\tInlinee: %s (%s)\tParamcount: %d\tMaxInlineeArgoutCount: %d\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(), Js::InlineeCallInfo::MaxInlineeArgoutCount,
                inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (inlinee->GetInParamsCount() == 0)
        {
            // Inline candidate has no params, not even a this pointer.  This can only be the global function,
            // which we shouldn't inline.
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count is zero!\tInlinee: %s (%s)\tParamcount: %d\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(),
                inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (inlinee->GetDontInline())
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Do not inline\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        // Do not inline a call to a class constructor if it isn't part of a new expression since the call will throw a TypeError anyway.
        if (inlinee->IsClassConstructor() && !isConstructorCall)
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Class constructor without new keyword\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (!DeciderInlineIntoInliner(inlinee, inliner, isConstructorCall, isPolymorphicCall, constantArgInfo, recursiveInlineDepth, allowRecursiveInlining))
        {
            return nullptr;
        }

#if defined(ENABLE_DEBUG_CONFIG_OPTIONS)
        TraceInlining(inliner, inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetByteCodeCount(), this->topFunc, this->bytecodeInlinedCount, inlinee, callSiteId, this->isLoopBody);
#endif

        this->bytecodeInlinedCount += inlinee->GetByteCodeCount();
        return inlinee;
    }

    Js::OpCode builtInInlineCandidateOpCode;
    ValueType builtInReturnType;
    GetBuiltInInfo(functionInfo, &builtInInlineCandidateOpCode, &builtInReturnType);

    if(builtInInlineCandidateOpCode == 0 && builtInReturnType.IsUninitialized())
    {
        return nullptr;
    }

    Assert(this->jitMode == ExecutionMode::FullJit);
    if (builtInInlineCandidateOpCode != 0 &&
        (
            PHASE_OFF(Js::InlinePhase, inliner) ||
            PHASE_OFF(Js::GlobOptPhase, inliner) ||
            isConstructorCall
        ))
    {
        return nullptr;
    }

    // Note: for built-ins at this time we don't have enough data (the instr) to decide whether it's going to be inlined.
    return functionInfo;
}
Example #3
0
int Compile(KIMLBYTE *&code, KIMLUINT &codeSize)
{
	auto compiler = new Compiler();
	if (!compiler)
	{
		showError("Cannot initialize compiler service.\n");
		return RET_FAIL_COMPILER;
	}

	std::vector<std::string> files;
	for (auto it = includeFiles.begin(); it != includeFiles.end(); ++it)
	{
		files.push_back(*it);
	}
	files.push_back(inputfile);

	bool failed = false;

	FILE *fp;
	for (auto it = files.begin(); it != files.end(); ++it)
	{
		fp = fopen(it->c_str(), "r");
		if (!fp)
		{
			showError("Cannot open: %s.\n", it->c_str());
			delete compiler;
			return RET_FAIL_IO;
		}

		if (!compiler->Parse(it->c_str(), fp))
		{
			failed = true;
		}

		fclose(fp);
	}

	if (failed)
	{
		showError("*** Parsing failed.\n");
		delete compiler;
		return RET_FAIL_COMPILER;
	}

	if (!compiler->Compile(hasDebugInfo))
	{
		auto &errors = compiler->GetErrors();
		for (unsigned int i = 0, c = errors.size(); i < c; ++i)
		{
			auto &error = errors[i];
			KIMLCSTRING msg = compileErrorMessages[error.code];
			showError("%s[%u]: %s\n", files[error.compileUnitIndex].c_str(), error.line, msg);
		}
		delete compiler;
		return RET_FAIL_COMPILER;
	}

	if (!compiler->Finish())
	{
		showError("*** Failed to finish compilation.\n");
		delete compiler;
		return RET_FAIL_COMPILER;
	}

	if (!compiler->GetByteCode(&code, &codeSize))
	{
		showError("*** Failed to export bytecode.\n");
		delete compiler;
		return RET_FAIL_COMPILER;
	}

	delete compiler;
	return RET_OK;
}