JS: save function descriptor for inline calls

This commit is contained in:
Alexey Tsvetkov
2015-01-29 13:28:05 +03:00
parent 083b506fe1
commit bfd82e2dd2
3 changed files with 108 additions and 17 deletions
@@ -19,11 +19,14 @@ package com.google.dart.compiler.backend.js.ast.metadata
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.builtins.InlineStrategy
import kotlin.properties.Delegates
import org.jetbrains.kotlin.descriptors.CallableDescriptor
public var JsName.staticRef: JsNode? by MetadataProperty(default = null)
public var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
public var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null)
public var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
public var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
@@ -17,13 +17,11 @@
package org.jetbrains.kotlin.js.translate.reference;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
import com.google.dart.compiler.common.SourceInfoImpl;
import com.google.gwt.dev.js.JsParser;
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.InlineStrategy;
import org.jetbrains.kotlin.builtins.InlineUtil;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
@@ -47,6 +45,7 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.UtilsPackage.setInlineCallMetadata;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall;
@@ -65,11 +64,10 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
}
JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate();
CallableDescriptor descriptor = getFunctionDescriptor(expression, context);
if (shouldBeInlined(expression, context)
&& callExpression instanceof JsInvocation) {
MetadataPackage.setInlineStrategy((JsInvocation) callExpression, InlineStrategy.IN_PLACE);
if (shouldBeInlined(expression, context)) {
setInlineCallMetadata(callExpression, descriptor, context);
}
return callExpression;
@@ -78,17 +76,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
public static boolean shouldBeInlined(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
if (!context.getConfig().isInlineEnabled()) return false;
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext());
assert resolvedCall != null;
CallableDescriptor descriptor;
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
descriptor = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor();
} else {
descriptor = resolvedCall.getCandidateDescriptor();
}
CallableDescriptor descriptor = getFunctionDescriptor(expression, context);
return shouldBeInlined(descriptor);
}
@@ -106,6 +94,21 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
return false;
}
@NotNull
private static CallableDescriptor getFunctionDescriptor(
@NotNull JetCallExpression expression,
@NotNull TranslationContext context
) {
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext());
assert resolvedCall != null;
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor();
}
return resolvedCall.getCandidateDescriptor();
}
private CallExpressionTranslator(
@NotNull JetCallExpression expression,
@Nullable JsExpression receiver,
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2015 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.translate.utils
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.*
import org.jetbrains.kotlin.builtins.InlineStrategy
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
/**
* Recursively walks expression and sets metadata for all invocations of descriptor.
*
* When JetExpression is compiled, the resulting JsExpression
* might not be JsInvocation.
*
* For example, extension call with nullable receiver:
* x?.fn(y)
* will compile to:
* (x != null) ? fn.call(x, y) : null
*/
fun setInlineCallMetadata(
expression: JsExpression,
descriptor: CallableDescriptor,
context: TranslationContext
) {
assert(CallExpressionTranslator.shouldBeInlined(descriptor)) {
"Expected descriptor of callable, that should be inlined, but got: $descriptor"
}
val name = context.aliasedName(descriptor)
val visitor = object : RecursiveJsVisitor() {
override fun visitInvocation(invocation: JsInvocation?) {
if (invocation == null) return
super.visitInvocation(invocation)
if (name == invocation.name) {
invocation.descriptor = descriptor
invocation.inlineStrategy = InlineStrategy.IN_PLACE
}
}
}
visitor.accept(expression)
}
fun TranslationContext.aliasedName(descriptor: CallableDescriptor): JsName {
val alias = getAliasForDescriptor(descriptor)
val aliasName = (alias as? JsNameRef)?.getName()
return aliasName ?: getNameForDescriptor(descriptor)
}
val JsExpression?.name: JsName?
get() = when (this) {
is JsInvocation -> {
val qualifier = this.getQualifier()
when {
isCallInvocation(this) -> (qualifier as JsNameRef).getQualifier().name
else -> qualifier.name
}
}
is JsNameRef -> this.getName()
else -> null
}