JsTests speed up: cash the scope with Kotlin library. Refactor CodeGenerator class.

About 10% speed up (not much but still...)
This commit is contained in:
Pavel V. Talanov
2012-06-29 13:24:24 +04:00
parent 72271cbdd4
commit 49c6555e5e
7 changed files with 117 additions and 69 deletions
@@ -42,9 +42,6 @@ public abstract class BasicTest extends TestWithEnvironment {
private static final String TEST_FILES = "js/js.translator/testFiles/";
private static final String CASES = "cases/";
private static final String OUT = "out/";
private static final String KOTLIN_JS_LIB = pathToTestFilesRoot() + "kotlin_lib.js";
private static final String KOTLIN_JS_LIB_ECMA_3 = pathToTestFilesRoot() + "kotlin_lib_ecma3.js";
private static final String KOTLIN_JS_LIB_ECMA_5 = pathToTestFilesRoot() + "kotlin_lib_ecma5.js";
private static final String EXPECTED = "expected/";
@NotNull
@@ -90,10 +87,7 @@ public abstract class BasicTest extends TestWithEnvironment {
@NotNull
protected List<String> additionalJSFiles(@NotNull EcmaVersion ecmaVersion) {
List<String> list = Lists.newArrayList();
list.add(ecmaVersion == EcmaVersion.v5 ? KOTLIN_JS_LIB_ECMA_5 : KOTLIN_JS_LIB_ECMA_3);
list.add(KOTLIN_JS_LIB);
return list;
return Lists.newArrayList();
}
protected void generateJavaScriptFiles(@NotNull String kotlinFilename,
@@ -141,7 +135,7 @@ public abstract class BasicTest extends TestWithEnvironment {
}
@NotNull
protected static String pathToTestFilesRoot() {
public static String pathToTestFilesRoot() {
return TEST_FILES;
}
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import static org.jetbrains.k2js.test.rhino.RhinoUtils.flushSystemOut;
import static org.junit.Assert.assertEquals;
/**
@@ -44,6 +45,7 @@ public class RhinoFunctionResultChecker implements RhinoResultChecker {
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
Object result = evaluateFunction(context, scope);
flushSystemOut(context, scope);
assertResultValid(result);
}
@@ -17,6 +17,7 @@
package org.jetbrains.k2js.test.rhino;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.facade.K2JSTranslator;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
@@ -44,12 +45,15 @@ public final class RhinoSystemOutputChecker implements RhinoResultChecker {
+ "END_OF_EXPECTED\n", trimmedExpected.equals(trimmedActual));
}
@NotNull
private static String getSystemOutput(@NotNull Context context, @NotNull Scriptable scope) {
Object output = context.evaluateString(scope, "Kotlin.System.output()", "test", 0, null);
Object output = context.evaluateString(scope, K2JSTranslator.GET_SYSTEM_OUT, "test", 0, null);
RhinoUtils.flushSystemOut(context, scope);
assertTrue("Output should be a string.", output instanceof String);
return (String) output;
}
@NotNull
public static String trimSpace(@NotNull String s) {
String[] choppedUpString = s.trim().split("\\s");
StringBuilder sb = new StringBuilder();
@@ -16,66 +16,135 @@
package org.jetbrains.k2js.test.rhino;
import closurecompiler.internal.com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.facade.K2JSTranslator;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import java.io.FileReader;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.utils.ExceptionUtils.rethrow;
import static org.jetbrains.k2js.test.BasicTest.pathToTestFilesRoot;
/**
* @author Pavel Talanov
*/
public final class RhinoUtils {
public static final String KOTLIN_JS_LIB_COMMON = pathToTestFilesRoot() + "kotlin_lib.js";
private static final String KOTLIN_JS_LIB_ECMA_3 = pathToTestFilesRoot() + "kotlin_lib_ecma3.js";
private static final String KOTLIN_JS_LIB_ECMA_5 = pathToTestFilesRoot() + "kotlin_lib_ecma5.js";
private RhinoUtils() {
}
private static void runFileWithRhino(@NotNull String inputFile,
@NotNull Context context,
@NotNull Scriptable scope) throws Exception {
@NotNull Context context,
@NotNull Scriptable scope) throws Exception {
FileReader reader = new FileReader(inputFile);
try {
context.evaluateReader(scope, reader, inputFile, 1, null);
} finally {
}
finally {
reader.close();
}
}
public static void runRhinoTest(@NotNull List<String> fileNames,
@NotNull RhinoResultChecker checker) throws Exception {
@NotNull RhinoResultChecker checker) throws Exception {
runRhinoTest(fileNames, checker, null, EcmaVersion.defaultVersion());
}
public static void runRhinoTest(@NotNull List<String> fileNames,
@NotNull RhinoResultChecker checker,
@Nullable Map<String, Object> variables,
@NotNull EcmaVersion ecmaVersion) throws Exception {
@NotNull RhinoResultChecker checker,
@Nullable Map<String, Object> variables,
@NotNull EcmaVersion ecmaVersion) throws Exception {
Context context = createContext(ecmaVersion);
try {
Scriptable scope = getScope(ecmaVersion, context);
putGlobalVariablesIntoScope(scope, variables);
for (String filename : fileNames) {
runFileWithRhino(filename, context, scope);
}
checker.runChecks(context, scope);
}
finally {
Context.exit();
}
}
@NotNull
private static Scriptable getScope(@NotNull EcmaVersion version, @NotNull Context context) {
ScriptableObject scope = context.initStandardObjects(null, false);
scope.setParentScope(getParentScope(version, context));
return scope;
}
@NotNull
private static Scriptable getParentScope(@NotNull EcmaVersion version, @NotNull Context context) {
Scriptable parentScope = versionToScope.get(version);
if (parentScope == null) {
parentScope = initScope(version, context);
versionToScope.put(version, parentScope);
}
return parentScope;
}
@NotNull
private static Scriptable initScope(@NotNull EcmaVersion version, @NotNull Context context) {
ScriptableObject scope = context.initStandardObjects();
try {
runFileWithRhino(getKotlinLibFile(version), context, scope);
runFileWithRhino(KOTLIN_JS_LIB_COMMON, context, scope);
}
catch (Exception e) {
throw rethrow(e);
}
scope.sealObject();
return scope;
}
//TODO:
@NotNull
private static Context createContext(@NotNull EcmaVersion ecmaVersion) {
Context context = Context.enter();
if (ecmaVersion == EcmaVersion.v5) {
// actually, currently, doesn't matter because dart doesn't produce js 1.8 code (expression closures)
context.setLanguageVersion(Context.VERSION_1_8);
}
return context;
}
Scriptable scope = context.initStandardObjects();
if (variables != null) {
Set<Map.Entry<String,Object>> entries = variables.entrySet();
for (Map.Entry<String, Object> entry : entries) {
String name = entry.getKey();
Object value = entry.getValue();
scope.put(name, scope, value);
}
private static void putGlobalVariablesIntoScope(@NotNull Scriptable scope, @Nullable Map<String, Object> variables) {
if (variables == null) {
return;
}
for (String filename : fileNames) {
runFileWithRhino(filename, context, scope);
Set<Map.Entry<String, Object>> entries = variables.entrySet();
for (Map.Entry<String, Object> entry : entries) {
String name = entry.getKey();
Object value = entry.getValue();
scope.put(name, scope, value);
}
checker.runChecks(context, scope);
Context.exit();
}
@NotNull
private static final Map<EcmaVersion, Scriptable> versionToScope = Maps.newHashMap();
@NotNull
public static String getKotlinLibFile(@NotNull EcmaVersion ecmaVersion) {
return ecmaVersion == EcmaVersion.v5 ? KOTLIN_JS_LIB_ECMA_5 : KOTLIN_JS_LIB_ECMA_3;
}
static void flushSystemOut(@NotNull Context context, @NotNull Scriptable scope) {
context.evaluateString(scope, K2JSTranslator.FLUSH_SYSTEM_OUT, "test", 0, null);
}
}
@@ -20,6 +20,7 @@ import closurecompiler.internal.com.google.common.collect.Maps;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.facade.K2JSTranslator;
@@ -29,7 +30,6 @@ import org.jetbrains.k2js.test.config.TestConfig;
import java.io.File;
import java.io.FileWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -46,21 +46,16 @@ public final class TranslationUtils {
@NotNull
private static final Map<EcmaVersion, K2JSTranslator> translators = Maps.newHashMap();
public static void translateFile(@NotNull Project project, @NotNull String inputFile,
@NotNull String outputFile, @NotNull MainCallParameters mainCallParameters, @NotNull EcmaVersion version) throws Exception {
translateFiles(project, Collections.singletonList(inputFile), outputFile, mainCallParameters, version, null);
}
public static void translateFiles(@NotNull Project project, @NotNull List<String> inputFiles,
@NotNull String outputFile,
@NotNull MainCallParameters mainCallParameters,
@NotNull EcmaVersion version,
List<String> rawStatements) throws Exception {
@Nullable List<String> rawStatements) throws Exception {
List<JetFile> psiFiles = createPsiFileList(inputFiles, project);
JsProgram program = getTranslator(project, version).generateProgram(psiFiles, mainCallParameters, rawStatements);
FileWriter writer = new FileWriter(new File(outputFile));
try {
writer.write(CodeGenerator.toString(program, null));
writer.write(CodeGenerator.generateProgramToString(program, null));
}
finally {
writer.close();
@@ -20,13 +20,13 @@ import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.facade.exceptions.TranslationException;
import org.jetbrains.k2js.generate.CodeGenerator;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.utils.JetFileUtils;
@@ -37,6 +37,7 @@ import java.util.List;
import static org.jetbrains.k2js.facade.FacadeUtils.parseString;
import static org.jetbrains.k2js.facade.FacadeUtils.writeCodeToFile;
import static org.jetbrains.k2js.generate.CodeGenerator.generateProgramToString;
/**
* @author Pavel Talanov
@@ -45,6 +46,9 @@ import static org.jetbrains.k2js.facade.FacadeUtils.writeCodeToFile;
*/
public final class K2JSTranslator {
public static final String FLUSH_SYSTEM_OUT = "Kotlin.System.flush();\n";
public static final String GET_SYSTEM_OUT = "Kotlin.System.output();\n";
public static void translateWithMainCallParametersAndSaveToFile(@NotNull MainCallParameters mainCall,
@NotNull List<JetFile> files,
@NotNull String outputPath,
@@ -62,22 +66,20 @@ public final class K2JSTranslator {
this.config = config;
}
//TODO: web demo related method
//NOTE: web demo related method
@SuppressWarnings("UnusedDeclaration")
@NotNull
public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException {
JetFile file = JetFileUtils.createPsiFile("test", programText, getProject());
String programCode = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString)), null) + "\n";
String flushOutput = "Kotlin.System.flush();\n";
String programOutput = "Kotlin.System.output();\n";
return flushOutput + programCode + programOutput;
return FLUSH_SYSTEM_OUT + programCode + GET_SYSTEM_OUT;
}
@NotNull
public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters, List<String> rawStatements) throws TranslationException {
public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters,
@Nullable List<String> rawStatements) throws TranslationException {
JsProgram program = generateProgram(Arrays.asList(file), mainCallParameters, rawStatements);
CodeGenerator generator = new CodeGenerator();
return generator.generateToString(program, rawStatements);
return generateProgramToString(program, rawStatements);
}
@NotNull
@@ -85,14 +87,13 @@ public final class K2JSTranslator {
throws TranslationException {
List<String> rawStatements = Lists.newArrayList();
JsProgram program = generateProgram(files, mainCallParameters, rawStatements);
CodeGenerator generator = new CodeGenerator();
return generator.generateToString(program, rawStatements);
return generateProgramToString(program, rawStatements);
}
@NotNull
public JsProgram generateProgram(@NotNull List<JetFile> filesToTranslate,
@NotNull MainCallParameters mainCallParameters,
List<String> rawStatements)
@Nullable List<String> rawStatements)
throws TranslationException {
JetStandardLibrary.initialize(config.getProject());
BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config);
@@ -21,10 +21,8 @@ import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.util.DefaultTextOutput;
import com.google.dart.compiler.util.TextOutput;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
/**
@@ -35,31 +33,16 @@ public final class CodeGenerator {
@NotNull
private final TextOutput output = new DefaultTextOutput(false);
public CodeGenerator() {
}
public static void toFile(@NotNull String outputFile, @NotNull JsProgram program) throws IOException {
CodeGenerator generator = new CodeGenerator();
generator.generateToFile(program, new File(outputFile));
private CodeGenerator() {
}
@NotNull
public static String toString(@NotNull JsProgram program, List<String> rawStatements) {
public static String generateProgramToString(@NotNull JsProgram program, @Nullable List<String> rawStatements) {
return (new CodeGenerator()).generateToString(program, rawStatements);
}
public void generateToFile(@NotNull JsProgram program, @NotNull File file) throws IOException {
generateCode(program);
FileWriter writer = new FileWriter(file);
try {
writer.write(output.toString());
} finally {
writer.close();
}
}
@NotNull
public String generateToString(@NotNull JsProgram program, List<String> rawStatements) {
private String generateToString(@NotNull JsProgram program, List<String> rawStatements) {
generateCode(program);
if (rawStatements != null) {
for (String statement : rawStatements) {