JS: fix inline cycle reporting
This commit is contained in:
@@ -57,41 +57,36 @@ class InlinerCycleReporter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun processInlineFunction(definition: FunctionWithWrapper, call: JsInvocation?, doProcess: () -> Unit) {
|
fun processInlineFunction(definition: FunctionWithWrapper, call: JsInvocation?, doProcess: () -> Unit) {
|
||||||
|
|
||||||
when (functionVisitingState[definition.function]) {
|
|
||||||
VisitedState.IN_PROCESS -> {
|
|
||||||
reportInlineCycle(call, definition.function)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
VisitedState.PROCESSED -> return
|
|
||||||
}
|
|
||||||
|
|
||||||
val function = definition.function
|
val function = definition.function
|
||||||
|
|
||||||
functionVisitingState[function] = VisitedState.IN_PROCESS
|
if (call != null) {
|
||||||
|
currentNamedFunction?.let {
|
||||||
val result = withFunction(function, doProcess)
|
inlineCallInfos.add(JsCallInfo(call, it))
|
||||||
|
|
||||||
functionVisitingState[function] = VisitedState.PROCESSED
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun <T> inlineCall(call: JsInvocation, doInline: () -> T): T {
|
|
||||||
currentNamedFunction?.let {
|
|
||||||
inlineCallInfos.add(JsCallInfo(call, it))
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = doInline()
|
|
||||||
|
|
||||||
if (!inlineCallInfos.isEmpty()) {
|
|
||||||
if (inlineCallInfos.last.call == call) {
|
|
||||||
inlineCallInfos.removeLast()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
try {
|
||||||
|
when (functionVisitingState[definition.function]) {
|
||||||
|
VisitedState.IN_PROCESS -> {
|
||||||
|
reportInlineCycle(call, definition.function)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
VisitedState.PROCESSED -> return
|
||||||
|
}
|
||||||
|
|
||||||
|
functionVisitingState[function] = VisitedState.IN_PROCESS
|
||||||
|
|
||||||
|
withFunction(function, doProcess)
|
||||||
|
|
||||||
|
functionVisitingState[function] = VisitedState.PROCESSED
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!inlineCallInfos.isEmpty()) {
|
||||||
|
if (inlineCallInfos.last.call == call) {
|
||||||
|
inlineCallInfos.removeLast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportInlineCycle(call: JsInvocation?, calledFunction: JsFunction) {
|
private fun reportInlineCycle(call: JsInvocation?, calledFunction: JsFunction) {
|
||||||
|
|||||||
@@ -60,21 +60,18 @@ class JsInliner(
|
|||||||
fun inline(scope: InliningScope, call: JsInvocation, currentStatement: JsStatement?): InlineableResult {
|
fun inline(scope: InliningScope, call: JsInvocation, currentStatement: JsStatement?): InlineableResult {
|
||||||
val definition = functionContext.getFunctionDefinition(call, scope)
|
val definition = functionContext.getFunctionDefinition(call, scope)
|
||||||
|
|
||||||
return cycleReporter.inlineCall(call) {
|
val function = scope.importFunctionDefinition(definition)
|
||||||
|
|
||||||
val function = scope.importFunctionDefinition(definition)
|
val inliningContext = InliningContext(currentStatement)
|
||||||
|
|
||||||
val inliningContext = InliningContext(currentStatement)
|
val (inlineableBody, resultExpression) = FunctionInlineMutator.getInlineableCallReplacement(call, function, inliningContext)
|
||||||
|
|
||||||
val (inlineableBody, resultExpression) = FunctionInlineMutator.getInlineableCallReplacement(call, function, inliningContext)
|
// body of inline function can contain call to lambdas that need to be inlined
|
||||||
|
scope.process(inlineableBody)
|
||||||
|
|
||||||
// body of inline function can contain call to lambdas that need to be inlined
|
// TODO shouldn't we process the resultExpression qualifier along with the lambda inlining?
|
||||||
scope.process(inlineableBody)
|
resultExpression?.synthetic = true
|
||||||
|
|
||||||
// TODO shouldn't we process the resultExpression qualifier along with the lambda inlining?
|
return InlineableResult(JsBlock(inliningContext.previousStatements + inlineableBody), resultExpression)
|
||||||
resultExpression?.synthetic = true
|
|
||||||
|
|
||||||
InlineableResult(JsBlock(inliningContext.previousStatements + inlineableBody), resultExpression)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,7 @@ class FunctionContext(
|
|||||||
|
|
||||||
fun scopeForFragment(fragment: JsProgramFragment) = if (fragment in newFragments) {
|
fun scopeForFragment(fragment: JsProgramFragment) = if (fragment in newFragments) {
|
||||||
inliningScopeCache.computeIfAbsent(fragment) {
|
inliningScopeCache.computeIfAbsent(fragment) {
|
||||||
|
loadFragment(fragment)
|
||||||
ProgramFragmentInliningScope(fragment)
|
ProgramFragmentInliningScope(fragment)
|
||||||
}
|
}
|
||||||
} else null
|
} else null
|
||||||
@@ -75,8 +76,7 @@ class FunctionContext(
|
|||||||
*/
|
*/
|
||||||
private fun getFunctionDefinitionImpl(call: JsInvocation, scope: InliningScope): InlineFunctionDefinition? {
|
private fun getFunctionDefinitionImpl(call: JsInvocation, scope: InliningScope): InlineFunctionDefinition? {
|
||||||
// Ensure we have the local function information
|
// Ensure we have the local function information
|
||||||
// TODO is this necessary?
|
assert(scope.fragment in inliningScopeCache)
|
||||||
loadFragment(scope.fragment)
|
|
||||||
|
|
||||||
return lookUpFunctionDirect(call) ?: lookUpFunctionIndirect(call, scope) ?: lookUpFunctionExternal(call, scope.fragment)
|
return lookUpFunctionDirect(call) ?: lookUpFunctionIndirect(call, scope) ?: lookUpFunctionExternal(call, scope.fragment)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user