JS: fix inline cycle reporting

This commit is contained in:
Anton Bannykh
2018-12-20 15:22:02 +03:00
parent b5b770c804
commit e4b081e1bf
3 changed files with 35 additions and 43 deletions
@@ -57,7 +57,15 @@ class InlinerCycleReporter(
} }
fun processInlineFunction(definition: FunctionWithWrapper, call: JsInvocation?, doProcess: () -> Unit) { fun processInlineFunction(definition: FunctionWithWrapper, call: JsInvocation?, doProcess: () -> Unit) {
val function = definition.function
if (call != null) {
currentNamedFunction?.let {
inlineCallInfos.add(JsCallInfo(call, it))
}
}
try {
when (functionVisitingState[definition.function]) { when (functionVisitingState[definition.function]) {
VisitedState.IN_PROCESS -> { VisitedState.IN_PROCESS -> {
reportInlineCycle(call, definition.function) reportInlineCycle(call, definition.function)
@@ -66,32 +74,19 @@ class InlinerCycleReporter(
VisitedState.PROCESSED -> return VisitedState.PROCESSED -> return
} }
val function = definition.function
functionVisitingState[function] = VisitedState.IN_PROCESS functionVisitingState[function] = VisitedState.IN_PROCESS
val result = withFunction(function, doProcess) withFunction(function, doProcess)
functionVisitingState[function] = VisitedState.PROCESSED functionVisitingState[function] = VisitedState.PROCESSED
return result } finally {
}
fun <T> inlineCall(call: JsInvocation, doInline: () -> T): T {
currentNamedFunction?.let {
inlineCallInfos.add(JsCallInfo(call, it))
}
val result = doInline()
if (!inlineCallInfos.isEmpty()) { if (!inlineCallInfos.isEmpty()) {
if (inlineCallInfos.last.call == call) { if (inlineCallInfos.last.call == call) {
inlineCallInfos.removeLast() inlineCallInfos.removeLast()
} }
} }
}
return result
} }
private fun reportInlineCycle(call: JsInvocation?, calledFunction: JsFunction) { private fun reportInlineCycle(call: JsInvocation?, calledFunction: JsFunction) {
@@ -60,8 +60,6 @@ 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)
@@ -74,7 +72,6 @@ class JsInliner(
// TODO shouldn't we process the resultExpression qualifier along with the lambda inlining? // TODO shouldn't we process the resultExpression qualifier along with the lambda inlining?
resultExpression?.synthetic = true resultExpression?.synthetic = true
InlineableResult(JsBlock(inliningContext.previousStatements + inlineableBody), resultExpression) return 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)
} }