KJS: transform labeled blocks to labeled do-while

It's a workaround for JDK-8177691.
Such code can appear during inline.
This commit is contained in:
Zalim Bashorov
2017-03-20 21:10:27 +03:00
committed by Zalim Bashorov
parent 76fa6ad5c2
commit 678d2e7c21
6 changed files with 209 additions and 8 deletions
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.*
object LabeledBlockToDoWhileTransformation {
fun apply(fragments: List<JsProgramFragment>) {
for (fragment in fragments) {
apply(fragment.declarationBlock)
apply(fragment.initializerBlock)
}
}
fun apply(root: JsNode) {
object : JsVisitorWithContextImpl() {
override fun endVisit(x: JsLabel, ctx: JsContext<JsNode>) {
if (x.statement is JsBlock) {
x.statement = JsDoWhile(JsLiteral.FALSE, x.statement)
}
super.endVisit(x, ctx)
}
}.accept(root)
}
}
@@ -17,18 +17,18 @@
package org.jetbrains.kotlin.js.test.optimizer
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.util.TextOutputImpl
import com.google.gwt.dev.js.rhino.CodePosition
import com.google.gwt.dev.js.rhino.ErrorReporter
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
import org.jetbrains.kotlin.js.test.BasicBoxTest
import org.jetbrains.kotlin.js.test.createScriptEngine
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.junit.Assert
import org.junit.Rule
import org.junit.rules.TestName
@@ -60,18 +60,22 @@ abstract class BasicOptimizerTest(private var basePath: String) {
updateMetadata(unoptimizedCode, unoptimizedAst)
for (statement in unoptimizedAst) {
object : RecursiveJsVisitor() {
override fun visitFunction(x: JsFunction) {
FunctionPostProcessor(x).apply()
super.visitFunction(x)
}
}.accept(statement)
process(statement)
}
val optimizedAst = parse(optimizedCode, errorReporter, parserScope)
Assert.assertEquals(astToString(optimizedAst), astToString(unoptimizedAst))
}
protected open fun process(statement: JsStatement) {
object : RecursiveJsVisitor() {
override fun visitFunction(x: JsFunction) {
FunctionPostProcessor(x).apply()
super.visitFunction(x)
}
}.accept(statement)
}
private fun updateMetadata(code: String, ast: List<JsStatement>) {
val comments = findSyntheticComments(code)
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.test.optimizer
import org.jetbrains.kotlin.js.backend.ast.JsStatement
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation
import org.junit.Test
class LabeledBlockToDoWhileTransformationTest : BasicOptimizerTest("labeled-block-to-do-while") {
@Test fun simple() = box()
override fun process(statement: JsStatement) {
LabeledBlockToDoWhileTransformation.apply(statement)
}
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer;
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
import org.jetbrains.kotlin.js.inline.JsInliner;
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation;
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
import org.jetbrains.kotlin.js.translate.general.AstGenerationResult;
@@ -124,6 +125,8 @@ public final class K2JSTranslator {
JsInliner.process(config, analysisResult.getBindingTrace(), translationResult.getInnerModuleName(), allFragments, newFragments);
LabeledBlockToDoWhileTransformation.INSTANCE.apply(newFragments);
CoroutineTransformer coroutineTransformer = new CoroutineTransformer(translationResult.getProgram());
for (JsProgramFragment fragment : newFragments) {
coroutineTransformer.accept(fragment.getDeclarationBlock());
@@ -174,6 +177,7 @@ public final class K2JSTranslator {
for (JsImportedModule module : translationResult.getImportedModuleList()) {
importedModules.add(module.getExternalName());
}
return new TranslationResult.Success(config, files, translationResult.getProgram(), diagnostics, importedModules,
moduleDescriptor, bindingTrace.getBindingContext(), metadataHeader, fileMap);
}
@@ -0,0 +1,62 @@
var a = eval("true");
function box() {
var functions = [box1, box2, box3];
for (i in functions) {
var f = functions[i];
var result = f();
if (f.toString().indexOf("label: do {") < 0) {
// http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8177691
if (result === "OK") return "Looks like JDK-8177691 fixed for " + f;
if (result !== void 0) return "Result of function changed: " + f;
}
else if (result !== "OK") {
return "fail on " + f
}
}
return "OK"
}
function box1() {
label: do {
try {
if (a) throw 1;
}
catch (e) {
break label;
}
throw 2;
} while (false);
return "OK";
}
function box2() {
label: do {
try {
if (a) throw 1;
}
finally {
break label;
}
throw 2;
} while (false);
return 'OK';
}
function box3() {
label: do {
try {
throw 1;
}
finally {
break label;
}
} while (false);
return 'OK';
}
@@ -0,0 +1,62 @@
var a = eval("true");
function box() {
var functions = [box1, box2, box3];
for (i in functions) {
var f = functions[i];
var result = f();
if (f.toString().indexOf("label: do {") < 0) {
// See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8177691
if (result === "OK") return "Looks like JDK-8177691 fixed for " + f;
if (result !== void 0) return "Result of function changed: " + f;
}
else if (result !== "OK") {
return "fail on " + f
}
}
return "OK"
}
function box1() {
label: {
try {
if (a) throw 1;
}
catch (e) {
break label;
}
throw 2;
}
return 'OK';
};
function box2() {
label: {
try {
if (a) throw 1;
}
finally {
break label;
}
throw 2;
}
return 'OK';
}
function box3() {
label: {
try {
throw 1;
}
finally {
break label;
}
}
return 'OK';
}