From e4b081e1bf62be074f82cfa02dba648c8f591612 Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Thu, 20 Dec 2018 15:22:02 +0300 Subject: [PATCH] JS: fix inline cycle reporting --- .../kotlin/js/inline/InlinerCycleReporter.kt | 55 +++++++++---------- .../jetbrains/kotlin/js/inline/JsInliner.kt | 19 +++---- .../js/inline/context/FunctionContext.kt | 4 +- 3 files changed, 35 insertions(+), 43 deletions(-) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlinerCycleReporter.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlinerCycleReporter.kt index 31c5c20b30d..61fa7b8b9f6 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlinerCycleReporter.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlinerCycleReporter.kt @@ -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 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) { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.kt index b403f14ab49..6ba517979f2 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.kt @@ -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) } } \ No newline at end of file diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt index 615e2ac1d01..3c76f683f29 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt @@ -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) }