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,41 +57,36 @@ class InlinerCycleReporter(
}
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
functionVisitingState[function] = VisitedState.IN_PROCESS
val result = withFunction(function, doProcess)
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()
if (call != null) {
currentNamedFunction?.let {
inlineCallInfos.add(JsCallInfo(call, it))
}
}
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) {
@@ -60,21 +60,18 @@ class JsInliner(
fun inline(scope: InliningScope, call: JsInvocation, currentStatement: JsStatement?): InlineableResult {
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
scope.process(inlineableBody)
// TODO shouldn't we process the resultExpression qualifier along with the lambda inlining?
resultExpression?.synthetic = true
// TODO shouldn't we process the resultExpression qualifier along with the lambda inlining?
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) {
inliningScopeCache.computeIfAbsent(fragment) {
loadFragment(fragment)
ProgramFragmentInliningScope(fragment)
}
} else null
@@ -75,8 +76,7 @@ class FunctionContext(
*/
private fun getFunctionDefinitionImpl(call: JsInvocation, scope: InliningScope): InlineFunctionDefinition? {
// Ensure we have the local function information
// TODO is this necessary?
loadFragment(scope.fragment)
assert(scope.fragment in inliningScopeCache)
return lookUpFunctionDirect(call) ?: lookUpFunctionIndirect(call, scope) ?: lookUpFunctionExternal(call, scope.fragment)
}