JS backend: added the ability to turn off the inline optimization.

This commit is contained in:
Zalim Bashorov
2014-08-14 22:50:11 +04:00
parent 338789664c
commit 0e075c7d5f
12 changed files with 72 additions and 28 deletions
@@ -38,6 +38,9 @@ public abstract class CommonCompilerArguments {
@Argument(value = "X", description = "Print a synopsis of advanced options") @Argument(value = "X", description = "Print a synopsis of advanced options")
public boolean extraHelp; public boolean extraHelp;
@Argument(value = "Xno-inline", description = "Disable method inlining")
public boolean noInline;
public List<String> freeArgs = new SmartList<String>(); public List<String> freeArgs = new SmartList<String>();
@NotNull @NotNull
@@ -63,9 +63,6 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
@Argument(value = "Xno-param-assertions", description = "Don't generate not-null assertions on parameters of methods accessible from Java") @Argument(value = "Xno-param-assertions", description = "Don't generate not-null assertions on parameters of methods accessible from Java")
public boolean noParamAssertions; public boolean noParamAssertions;
@Argument(value = "Xno-inline", description = "Disable method inlining")
public boolean noInline;
@Argument(value = "Xno-optimize", description = "Disable optimizations") @Argument(value = "Xno-optimize", description = "Disable optimizations")
public boolean noOptimize; public boolean noOptimize;
@@ -198,12 +198,14 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
} }
EcmaVersion ecmaVersion = EcmaVersion.defaultVersion(); EcmaVersion ecmaVersion = EcmaVersion.defaultVersion();
String moduleId = FileUtil.getNameWithoutExtension(new File(arguments.outputFile)); String moduleId = FileUtil.getNameWithoutExtension(new File(arguments.outputFile));
boolean inlineEnabled = !arguments.noInline;
if (arguments.libraryFiles != null) { if (arguments.libraryFiles != null) {
return new LibrarySourcesConfig(project, moduleId, Arrays.asList(arguments.libraryFiles), ecmaVersion, arguments.sourceMap); return new LibrarySourcesConfig(project, moduleId, Arrays.asList(arguments.libraryFiles), ecmaVersion, arguments.sourceMap, inlineEnabled);
} }
else { else {
// lets discover the JS library definitions on the classpath // lets discover the JS library definitions on the classpath
return new ClassPathLibraryDefintionsConfig(project, moduleId, ecmaVersion, arguments.sourceMap); return new ClassPathLibraryDefintionsConfig(project, moduleId, ecmaVersion, arguments.sourceMap, inlineEnabled);
} }
} }
@@ -36,10 +36,11 @@ public abstract class Config {
//NOTE: a hacky solution to be able to rerun code samples with lib loaded only once: used by tests and web demo //NOTE: a hacky solution to be able to rerun code samples with lib loaded only once: used by tests and web demo
@NotNull @NotNull
public static final String REWRITABLE_MODULE_NAME = "JS_TESTS"; public static final String REWRITABLE_MODULE_NAME = "JS_TESTS";
private boolean inlineEnabled;
@NotNull @NotNull
public static Config getEmptyConfig(@NotNull Project project, @NotNull EcmaVersion ecmaVersion) { public static Config getEmptyConfig(@NotNull Project project, @NotNull EcmaVersion ecmaVersion) {
return new Config(project, "main", ecmaVersion) { return new Config(project, "main", ecmaVersion, false, true) {
@NotNull @NotNull
@Override @Override
protected List<JetFile> generateLibFiles() { protected List<JetFile> generateLibFiles() {
@@ -161,21 +162,28 @@ public abstract class Config {
private final boolean sourcemap; private final boolean sourcemap;
public Config(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion) { public Config(
this(project, moduleId, ecmaVersion, false); @NotNull Project project,
} @NotNull String moduleId,
@NotNull EcmaVersion ecmaVersion,
public Config(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion, boolean sourcemap) { boolean sourcemap,
boolean inlineEnabled
) {
this.project = project; this.project = project;
this.target = ecmaVersion; this.target = ecmaVersion;
this.moduleId = moduleId; this.moduleId = moduleId;
this.sourcemap = sourcemap; this.sourcemap = sourcemap;
this.inlineEnabled = inlineEnabled;
} }
public boolean isSourcemap() { public boolean isSourcemap() {
return sourcemap; return sourcemap;
} }
public boolean isInlineEnabled() {
return inlineEnabled;
}
@NotNull @NotNull
public Project getProject() { public Project getProject() {
return project; return project;
@@ -56,9 +56,10 @@ public class LibrarySourcesConfig extends Config {
@NotNull String moduleId, @NotNull String moduleId,
@NotNull List<String> files, @NotNull List<String> files,
@NotNull EcmaVersion ecmaVersion, @NotNull EcmaVersion ecmaVersion,
boolean sourcemap boolean sourcemap,
boolean inlineEnabled
) { ) {
super(project, moduleId, ecmaVersion, sourcemap); super(project, moduleId, ecmaVersion, sourcemap, inlineEnabled);
this.files = files; this.files = files;
} }
@@ -36,7 +36,7 @@ public class TestConfig extends Config {
@NotNull List<JetFile> files, @NotNull List<JetFile> files,
@NotNull BindingContext libraryContext, @NotNull BindingContext libraryContext,
@NotNull ModuleDescriptor module) { @NotNull ModuleDescriptor module) {
return new TestConfig(project, version, files, libraryContext, module, false); return new TestConfig(project, version, files, libraryContext, module, false, true);
} }
}; };
@@ -47,7 +47,7 @@ public class TestConfig extends Config {
@NotNull List<JetFile> files, @NotNull List<JetFile> files,
@NotNull BindingContext libraryContext, @NotNull BindingContext libraryContext,
@NotNull ModuleDescriptor module) { @NotNull ModuleDescriptor module) {
return new TestConfig(project, version, files, libraryContext, module, true); return new TestConfig(project, version, files, libraryContext, module, true, true);
} }
}; };
@@ -58,9 +58,16 @@ public class TestConfig extends Config {
@NotNull @NotNull
private final ModuleDescriptor libraryModule; private final ModuleDescriptor libraryModule;
public TestConfig(@NotNull Project project, @NotNull EcmaVersion version, public TestConfig(
@NotNull List<JetFile> files, @NotNull BindingContext libraryContext, @NotNull ModuleDescriptor module, boolean sourcemap) { @NotNull Project project,
super(project, REWRITABLE_MODULE_NAME, version, sourcemap); @NotNull EcmaVersion version,
@NotNull List<JetFile> files,
@NotNull BindingContext libraryContext,
@NotNull ModuleDescriptor module,
boolean sourcemap,
boolean inlineEnabled
) {
super(project, REWRITABLE_MODULE_NAME, version, sourcemap, inlineEnabled);
jsLibFiles = files; jsLibFiles = files;
this.libraryContext = libraryContext; this.libraryContext = libraryContext;
libraryModule = module; libraryModule = module;
@@ -45,7 +45,7 @@ public class TestConfigWithUnitTests extends TestConfig {
@NotNull List<JetFile> files, @NotNull List<JetFile> files,
@NotNull BindingContext libraryContext, @NotNull BindingContext libraryContext,
@NotNull ModuleDescriptor module) { @NotNull ModuleDescriptor module) {
super(project, version, files, libraryContext, module, false); super(project, version, files, libraryContext, module, false, true);
} }
@Override @Override
@@ -30,8 +30,14 @@ public class ClassPathLibraryDefintionsConfig extends Config {
@NotNull @NotNull
public static final String META_INF_SERVICES_FILE = "META-INF/services/org.jetbrains.kotlin.js.libraryDefinitions"; public static final String META_INF_SERVICES_FILE = "META-INF/services/org.jetbrains.kotlin.js.libraryDefinitions";
public ClassPathLibraryDefintionsConfig(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion version, boolean sourcemap) { public ClassPathLibraryDefintionsConfig(
super(project, moduleId, version, sourcemap); @NotNull Project project,
@NotNull String moduleId,
@NotNull EcmaVersion version,
boolean sourcemap,
boolean inlineEnabled
) {
super(project, moduleId, version, sourcemap, inlineEnabled);
} }
@NotNull @NotNull
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.reflect.ReflectionTypes;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.config.LibrarySourcesConfig; import org.jetbrains.k2js.config.LibrarySourcesConfig;
import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Generator;
@@ -48,12 +49,12 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.getSuggestedNa
*/ */
public final class StaticContext { public final class StaticContext {
public static StaticContext generateStaticContext(@NotNull BindingContext bindingContext, @NotNull EcmaVersion ecmaVersion, @NotNull ModuleDescriptor moduleDescriptor) { public static StaticContext generateStaticContext(@NotNull BindingContext bindingContext, @NotNull Config config, @NotNull ModuleDescriptor moduleDescriptor) {
JsProgram program = new JsProgram("main"); JsProgram program = new JsProgram("main");
Namer namer = Namer.newInstance(program.getRootScope()); Namer namer = Namer.newInstance(program.getRootScope());
Intrinsics intrinsics = new Intrinsics(); Intrinsics intrinsics = new Intrinsics();
StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope());
return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, program.getRootScope(), ecmaVersion, moduleDescriptor); return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, program.getRootScope(), config, moduleDescriptor);
} }
@NotNull @NotNull
@@ -90,20 +91,24 @@ public final class StaticContext {
@NotNull @NotNull
private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap(); private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap();
@NotNull
private final Config config;
@NotNull @NotNull
private final EcmaVersion ecmaVersion; private final EcmaVersion ecmaVersion;
//TODO: too many parameters in constructor //TODO: too many parameters in constructor
private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext, private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext,
@NotNull Namer namer, @NotNull Intrinsics intrinsics, @NotNull Namer namer, @NotNull Intrinsics intrinsics,
@NotNull StandardClasses standardClasses, @NotNull JsScope rootScope, @NotNull EcmaVersion ecmaVersion, @NotNull ModuleDescriptor moduleDescriptor) { @NotNull StandardClasses standardClasses, @NotNull JsScope rootScope, @NotNull Config config, @NotNull ModuleDescriptor moduleDescriptor) {
this.program = program; this.program = program;
this.bindingContext = bindingContext; this.bindingContext = bindingContext;
this.namer = namer; this.namer = namer;
this.intrinsics = intrinsics; this.intrinsics = intrinsics;
this.rootScope = rootScope; this.rootScope = rootScope;
this.standardClasses = standardClasses; this.standardClasses = standardClasses;
this.ecmaVersion = ecmaVersion; this.config = config;
this.ecmaVersion = config.getTarget();
this.reflectionTypes = new ReflectionTypes(moduleDescriptor); this.reflectionTypes = new ReflectionTypes(moduleDescriptor);
} }
@@ -214,6 +219,10 @@ public final class StaticContext {
return result; return result;
} }
public Config getConfig() {
return config;
}
private final class NameGenerator extends Generator<JsName> { private final class NameGenerator extends Generator<JsName> {
public NameGenerator() { public NameGenerator() {
@@ -20,11 +20,15 @@ import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.MemberDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.reflect.ReflectionTypes; import org.jetbrains.jet.lang.reflect.ReflectionTypes;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics; import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils;
@@ -246,6 +250,11 @@ public class TranslationContext {
return staticContext.getProgram(); return staticContext.getProgram();
} }
@NotNull
public Config getConfig() {
return staticContext.getConfig();
}
@NotNull @NotNull
public JsScope scope() { public JsScope scope() {
return dynamicContext.getScope(); return dynamicContext.getScope();
@@ -169,7 +169,7 @@ public final class Translation {
throws TranslationException { throws TranslationException {
try { try {
JsProgram program = doGenerateAst(bindingContext, files, mainCallParameters, moduleDescriptor, config); JsProgram program = doGenerateAst(bindingContext, files, mainCallParameters, moduleDescriptor, config);
return JsInliner.process(program); return config.isInlineEnabled() ? JsInliner.process(program) : program;
} }
catch (UnsupportedOperationException e) { catch (UnsupportedOperationException e) {
throw new UnsupportedFeatureException("Unsupported feature used.", e); throw new UnsupportedFeatureException("Unsupported feature used.", e);
@@ -184,7 +184,7 @@ public final class Translation {
@NotNull MainCallParameters mainCallParameters, @NotNull MainCallParameters mainCallParameters,
@NotNull ModuleDescriptor moduleDescriptor, @NotNull ModuleDescriptor moduleDescriptor,
@NotNull Config config) throws MainFunctionNotFoundException { @NotNull Config config) throws MainFunctionNotFoundException {
StaticContext staticContext = StaticContext.generateStaticContext(bindingContext, config.getTarget(), moduleDescriptor); StaticContext staticContext = StaticContext.generateStaticContext(bindingContext, config, moduleDescriptor);
JsProgram program = staticContext.getProgram(); JsProgram program = staticContext.getProgram();
JsBlock block = program.getGlobalBlock(); JsBlock block = program.getGlobalBlock();
@@ -53,6 +53,8 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
} }
public static boolean shouldBeInlined(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { public static boolean shouldBeInlined(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
if (!context.getConfig().isInlineEnabled()) return false;
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext()); ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext());
assert resolvedCall != null; assert resolvedCall != null;