Use local aliases for Kotlin runtime functions in JS BE
This commit is contained in:
+195
-22
@@ -190,6 +190,88 @@ public final class DebugJsAstProtoBuf {
|
||||
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.InlineStrategy)
|
||||
}
|
||||
|
||||
/**
|
||||
* Protobuf enum {@code org.jetbrains.kotlin.serialization.js.ast.SpecialFunction}
|
||||
*/
|
||||
public enum SpecialFunction
|
||||
implements org.jetbrains.kotlin.protobuf.ProtocolMessageEnum {
|
||||
/**
|
||||
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
|
||||
*/
|
||||
DEFINE_INLINE_FUNCTION(0, 1),
|
||||
/**
|
||||
* <code>WRAP_FUNCTION = 2;</code>
|
||||
*/
|
||||
WRAP_FUNCTION(1, 2),
|
||||
;
|
||||
|
||||
/**
|
||||
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
|
||||
*/
|
||||
public static final int DEFINE_INLINE_FUNCTION_VALUE = 1;
|
||||
/**
|
||||
* <code>WRAP_FUNCTION = 2;</code>
|
||||
*/
|
||||
public static final int WRAP_FUNCTION_VALUE = 2;
|
||||
|
||||
|
||||
public final int getNumber() { return value; }
|
||||
|
||||
public static SpecialFunction valueOf(int value) {
|
||||
switch (value) {
|
||||
case 1: return DEFINE_INLINE_FUNCTION;
|
||||
case 2: return WRAP_FUNCTION;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
|
||||
internalGetValueMap() {
|
||||
return internalValueMap;
|
||||
}
|
||||
private static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
|
||||
internalValueMap =
|
||||
new org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>() {
|
||||
public SpecialFunction findValueByNumber(int number) {
|
||||
return SpecialFunction.valueOf(number);
|
||||
}
|
||||
};
|
||||
|
||||
public final org.jetbrains.kotlin.protobuf.Descriptors.EnumValueDescriptor
|
||||
getValueDescriptor() {
|
||||
return getDescriptor().getValues().get(index);
|
||||
}
|
||||
public final org.jetbrains.kotlin.protobuf.Descriptors.EnumDescriptor
|
||||
getDescriptorForType() {
|
||||
return getDescriptor();
|
||||
}
|
||||
public static final org.jetbrains.kotlin.protobuf.Descriptors.EnumDescriptor
|
||||
getDescriptor() {
|
||||
return org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.getDescriptor().getEnumTypes().get(2);
|
||||
}
|
||||
|
||||
private static final SpecialFunction[] VALUES = values();
|
||||
|
||||
public static SpecialFunction valueOf(
|
||||
org.jetbrains.kotlin.protobuf.Descriptors.EnumValueDescriptor desc) {
|
||||
if (desc.getType() != getDescriptor()) {
|
||||
throw new java.lang.IllegalArgumentException(
|
||||
"EnumValueDescriptor is not for this type.");
|
||||
}
|
||||
return VALUES[desc.getIndex()];
|
||||
}
|
||||
|
||||
private final int index;
|
||||
private final int value;
|
||||
|
||||
private SpecialFunction(int index, int value) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.SpecialFunction)
|
||||
}
|
||||
|
||||
public interface LocationOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.Location)
|
||||
org.jetbrains.kotlin.protobuf.MessageOrBuilder {
|
||||
@@ -47073,13 +47155,22 @@ public final class DebugJsAstProtoBuf {
|
||||
int getLocalNameId();
|
||||
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
boolean hasImported();
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
boolean getImported();
|
||||
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
boolean hasSpecialFunction();
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
||||
@@ -47153,6 +47244,17 @@ public final class DebugJsAstProtoBuf {
|
||||
imported_ = input.readBool();
|
||||
break;
|
||||
}
|
||||
case 40: {
|
||||
int rawValue = input.readEnum();
|
||||
org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction value = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.valueOf(rawValue);
|
||||
if (value == null) {
|
||||
unknownFields.mergeVarintField(5, rawValue);
|
||||
} else {
|
||||
bitField0_ |= 0x00000010;
|
||||
specialFunction_ = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
||||
@@ -47241,23 +47343,39 @@ public final class DebugJsAstProtoBuf {
|
||||
public static final int IMPORTED_FIELD_NUMBER = 4;
|
||||
private boolean imported_;
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean hasImported() {
|
||||
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean getImported() {
|
||||
return imported_;
|
||||
}
|
||||
|
||||
public static final int SPECIAL_FUNCTION_FIELD_NUMBER = 5;
|
||||
private org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction specialFunction_;
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public boolean hasSpecialFunction() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction() {
|
||||
return specialFunction_;
|
||||
}
|
||||
|
||||
private void initFields() {
|
||||
temporary_ = false;
|
||||
identifier_ = 0;
|
||||
localNameId_ = 0;
|
||||
imported_ = false;
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@@ -47288,6 +47406,9 @@ public final class DebugJsAstProtoBuf {
|
||||
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||
output.writeBool(4, imported_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
output.writeEnum(5, specialFunction_.getNumber());
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@@ -47313,6 +47434,10 @@ public final class DebugJsAstProtoBuf {
|
||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||
.computeBoolSize(4, imported_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||
.computeEnumSize(5, specialFunction_.getNumber());
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@@ -47438,6 +47563,8 @@ public final class DebugJsAstProtoBuf {
|
||||
bitField0_ = (bitField0_ & ~0x00000004);
|
||||
imported_ = false;
|
||||
bitField0_ = (bitField0_ & ~0x00000008);
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47482,6 +47609,10 @@ public final class DebugJsAstProtoBuf {
|
||||
to_bitField0_ |= 0x00000008;
|
||||
}
|
||||
result.imported_ = imported_;
|
||||
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
to_bitField0_ |= 0x00000010;
|
||||
}
|
||||
result.specialFunction_ = specialFunction_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
return result;
|
||||
@@ -47510,6 +47641,9 @@ public final class DebugJsAstProtoBuf {
|
||||
if (other.hasImported()) {
|
||||
setImported(other.getImported());
|
||||
}
|
||||
if (other.hasSpecialFunction()) {
|
||||
setSpecialFunction(other.getSpecialFunction());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
@@ -47639,19 +47773,19 @@ public final class DebugJsAstProtoBuf {
|
||||
|
||||
private boolean imported_ ;
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean hasImported() {
|
||||
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean getImported() {
|
||||
return imported_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public Builder setImported(boolean value) {
|
||||
bitField0_ |= 0x00000008;
|
||||
@@ -47660,7 +47794,7 @@ public final class DebugJsAstProtoBuf {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public Builder clearImported() {
|
||||
bitField0_ = (bitField0_ & ~0x00000008);
|
||||
@@ -47669,6 +47803,41 @@ public final class DebugJsAstProtoBuf {
|
||||
return this;
|
||||
}
|
||||
|
||||
private org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public boolean hasSpecialFunction() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction() {
|
||||
return specialFunction_;
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public Builder setSpecialFunction(org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
bitField0_ |= 0x00000010;
|
||||
specialFunction_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public Builder clearSpecialFunction() {
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
||||
}
|
||||
|
||||
@@ -49160,19 +49329,23 @@ public final class DebugJsAstProtoBuf {
|
||||
"ule\022\024\n\014signature_id\030\001 \002(\005\022\025\n\rexpression_" +
|
||||
"id\030\002 \002(\005\"\034\n\013StringTable\022\r\n\005entry\030\001 \003(\t\"K" +
|
||||
"\n\tNameTable\022>\n\005entry\030\001 \003(\0132/.org.jetbrai",
|
||||
"ns.kotlin.serialization.js.ast.Name\"V\n\004N" +
|
||||
"ame\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 \001" +
|
||||
"(\005\022\025\n\rlocal_name_id\030\003 \001(\005\022\020\n\010imported\030\004 " +
|
||||
"\001(\010\"\346\001\n\005Chunk\022L\n\014string_table\030\001 \002(\01326.or" +
|
||||
"g.jetbrains.kotlin.serialization.js.ast." +
|
||||
"StringTable\022H\n\nname_table\030\002 \002(\01324.org.je" +
|
||||
"tbrains.kotlin.serialization.js.ast.Name" +
|
||||
"Table\022E\n\010fragment\030\003 \002(\01323.org.jetbrains." +
|
||||
"kotlin.serialization.js.ast.Fragment*@\n\013" +
|
||||
"SideEffects\022\021\n\rAFFECTS_STATE\020\001\022\024\n\020DEPEND",
|
||||
"S_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016InlineStrategy" +
|
||||
"\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PLACE\020\001\022\016\n\nNOT_I" +
|
||||
"NLINE\020\002B\024B\022DebugJsAstProtoBuf"
|
||||
"ns.kotlin.serialization.js.ast.Name\"\263\001\n\004" +
|
||||
"Name\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 " +
|
||||
"\001(\005\022\025\n\rlocal_name_id\030\003 \001(\005\022\027\n\010imported\030\004" +
|
||||
" \001(\010:\005false\022T\n\020special_function\030\005 \001(\0162:." +
|
||||
"org.jetbrains.kotlin.serialization.js.as" +
|
||||
"t.SpecialFunction\"\346\001\n\005Chunk\022L\n\014string_ta" +
|
||||
"ble\030\001 \002(\01326.org.jetbrains.kotlin.seriali" +
|
||||
"zation.js.ast.StringTable\022H\n\nname_table\030" +
|
||||
"\002 \002(\01324.org.jetbrains.kotlin.serializati" +
|
||||
"on.js.ast.NameTable\022E\n\010fragment\030\003 \002(\01323.",
|
||||
"org.jetbrains.kotlin.serialization.js.as" +
|
||||
"t.Fragment*@\n\013SideEffects\022\021\n\rAFFECTS_STA" +
|
||||
"TE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016" +
|
||||
"InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PL" +
|
||||
"ACE\020\001\022\016\n\nNOT_INLINE\020\002*@\n\017SpecialFunction" +
|
||||
"\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FUN" +
|
||||
"CTION\020\002B\024B\022DebugJsAstProtoBuf"
|
||||
};
|
||||
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||
@@ -49509,7 +49682,7 @@ public final class DebugJsAstProtoBuf {
|
||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_fieldAccessorTable = new
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_descriptor,
|
||||
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", "Imported", });
|
||||
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", "Imported", "SpecialFunction", });
|
||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_descriptor =
|
||||
getDescriptor().getMessageTypes().get(54);
|
||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_fieldAccessorTable = new
|
||||
|
||||
@@ -31,6 +31,8 @@ var JsName.descriptor: DeclarationDescriptor? by MetadataProperty(default = null
|
||||
|
||||
var JsName.localAlias: JsName? by MetadataProperty(default = null)
|
||||
|
||||
var JsName.specialFunction: SpecialFunction? by MetadataProperty(default = null)
|
||||
|
||||
var JsExpression.localAlias: JsName? by MetadataProperty(default = null)
|
||||
|
||||
// TODO: move this to module 'js.inliner' and change dependency on 'frontend' to dependency on 'descriptors'
|
||||
@@ -133,4 +135,9 @@ enum class SideEffectKind {
|
||||
AFFECTS_STATE,
|
||||
DEPENDS_ON_STATE,
|
||||
PURE
|
||||
}
|
||||
|
||||
enum class SpecialFunction(val suggestedName: String) {
|
||||
DEFINE_INLINE_FUNCTION("defineInlineFunction"),
|
||||
WRAP_FUNCTION("wrapFunction")
|
||||
}
|
||||
@@ -359,6 +359,7 @@ class Analyzer(private val context: Context) : JsVisitor() {
|
||||
private fun enterFunction(function: JsFunction, arguments: List<JsExpression>) {
|
||||
functionsToEnter += function
|
||||
context.addNodesForLocalVars(function.collectLocalVariables())
|
||||
context.markSpecialFunctions(function.body)
|
||||
|
||||
for ((param, arg) in function.parameters.zip(arguments)) {
|
||||
if (arg is JsFunction && arg.name == null && isProperFunctionalParameter(arg.body, param)) {
|
||||
@@ -377,6 +378,7 @@ class Analyzer(private val context: Context) : JsVisitor() {
|
||||
private fun enterFunctionWithGivenNodes(function: JsFunction, arguments: List<Node>) {
|
||||
functionsToEnter += function
|
||||
context.addNodesForLocalVars(function.collectLocalVariables())
|
||||
context.markSpecialFunctions(function.body)
|
||||
|
||||
for ((param, arg) in function.parameters.zip(arguments)) {
|
||||
val paramNode = context.nodes[param.name]!!
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
package org.jetbrains.kotlin.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.array
|
||||
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.index
|
||||
|
||||
@@ -32,6 +35,45 @@ class Context {
|
||||
nodes += names.filter { it !in nodes }.associate { it to Node(it) }
|
||||
}
|
||||
|
||||
fun markSpecialFunctions(root: JsNode) {
|
||||
val candidates = mutableMapOf<JsName, SpecialFunction>()
|
||||
val unsuitableNames = mutableSetOf<JsName>()
|
||||
val assignedNames = mutableSetOf<JsName>()
|
||||
root.accept(object : RecursiveJsVisitor() {
|
||||
override fun visit(x: JsVars.JsVar) {
|
||||
val name = x.name
|
||||
if (!assignedNames.add(name)) {
|
||||
unsuitableNames += name
|
||||
}
|
||||
|
||||
val initializer = x.initExpression
|
||||
if (initializer != null) {
|
||||
val specialName = when {
|
||||
isDefineInlineFunction(initializer) -> SpecialFunction.DEFINE_INLINE_FUNCTION
|
||||
isWrapFunction(initializer) -> SpecialFunction.WRAP_FUNCTION
|
||||
else -> null
|
||||
}
|
||||
specialName?.let { candidates[name] = specialName }
|
||||
}
|
||||
super.visit(x)
|
||||
}
|
||||
|
||||
override fun visitBinaryExpression(x: JsBinaryOperation) {
|
||||
JsAstUtils.decomposeAssignmentToVariable(x)?.let { (left, _) -> unsuitableNames += left }
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
x.name?.let { unsuitableNames += it }
|
||||
}
|
||||
})
|
||||
|
||||
for ((name, function) in candidates) {
|
||||
if (name !in unsuitableNames) {
|
||||
name.specialFunction = function
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun extractNode(expression: JsExpression): Node? {
|
||||
val node = extractNodeImpl(expression)?.original
|
||||
return if (node != null && moduleExportsNode in generateSequence(node) { it.qualifier?.parent }) {
|
||||
|
||||
@@ -18,10 +18,7 @@ package org.jetbrains.kotlin.js.dce
|
||||
|
||||
import com.google.gwt.dev.js.rhino.CodePosition
|
||||
import com.google.gwt.dev.js.rhino.ErrorReporter
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.dce.Context.Node
|
||||
import org.jetbrains.kotlin.js.inline.util.collectDefinedNames
|
||||
import org.jetbrains.kotlin.js.inline.util.fixForwardNameReferences
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
|
||||
import org.jetbrains.kotlin.js.dce.Context.Node
|
||||
|
||||
fun Context.isObjectDefineProperty(function: JsExpression) = isObjectFunction(function, "defineProperty")
|
||||
@@ -25,9 +27,11 @@ fun Context.isObjectGetOwnPropertyDescriptor(function: JsExpression) = isObjectF
|
||||
|
||||
fun Context.isDefineModule(function: JsExpression): Boolean = isKotlinFunction(function, "defineModule")
|
||||
|
||||
fun Context.isDefineInlineFunction(function: JsExpression): Boolean = isKotlinFunction(function, "defineInlineFunction")
|
||||
fun Context.isDefineInlineFunction(function: JsExpression): Boolean =
|
||||
isKotlinFunction(function, "defineInlineFunction") || isSpecialFunction(function, SpecialFunction.DEFINE_INLINE_FUNCTION)
|
||||
|
||||
fun Context.isWrapFunction(function: JsExpression): Boolean = isKotlinFunction(function, "wrapFunction")
|
||||
fun Context.isWrapFunction(function: JsExpression): Boolean =
|
||||
isKotlinFunction(function, "wrapFunction") || isSpecialFunction(function, SpecialFunction.WRAP_FUNCTION)
|
||||
|
||||
fun Context.isObjectFunction(function: JsExpression, functionName: String): Boolean {
|
||||
if (function !is JsNameRef) return false
|
||||
@@ -45,6 +49,9 @@ fun Context.isKotlinFunction(function: JsExpression, name: String): Boolean {
|
||||
return receiver in nodes && receiver.ident.toLowerCase() == "kotlin"
|
||||
}
|
||||
|
||||
fun isSpecialFunction(expr: JsExpression, specialFunction: SpecialFunction): Boolean =
|
||||
expr is JsNameRef && expr.qualifier == null && expr.name?.specialFunction == specialFunction
|
||||
|
||||
fun Context.isAmdDefine(function: JsExpression): Boolean = isTopLevelFunction(function, "define")
|
||||
|
||||
fun Context.isTopLevelFunction(function: JsExpression, name: String): Boolean {
|
||||
|
||||
@@ -22,10 +22,7 @@ import com.intellij.util.containers.SLRUCache
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.inline.util.*
|
||||
import org.jetbrains.kotlin.js.parser.OffsetToSourceMapping
|
||||
@@ -51,6 +48,7 @@ private val JS_IDENTIFIER_PART = "$JS_IDENTIFIER_START\\p{Pc}\\p{Mc}\\p{Mn}\\d"
|
||||
private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*"
|
||||
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
|
||||
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
|
||||
private val WRAP_FUNCTION_PATTERN = Regex("var\\s+($JS_IDENTIFIER)\\s*=\\s*($JS_IDENTIFIER)\\.wrapFunction\\s*;").toPattern()
|
||||
|
||||
class FunctionReader(
|
||||
private val reporter: JsConfig.Reporter,
|
||||
@@ -73,10 +71,13 @@ class FunctionReader(
|
||||
val fileContent: String,
|
||||
val moduleVariable: String,
|
||||
val kotlinVariable: String,
|
||||
val wrapFunctionVariable: String?,
|
||||
offsetToSourceMappingProvider: () -> OffsetToSourceMapping,
|
||||
val sourceMap: SourceMap?
|
||||
) {
|
||||
val offsetToSourceMapping by lazy(offsetToSourceMappingProvider)
|
||||
|
||||
val wrapFunctionRegex = wrapFunctionVariable?.let { Regex("\\s*$it\\s*\\(\\s*").toPattern() }
|
||||
}
|
||||
|
||||
private val moduleNameToInfo by lazy {
|
||||
@@ -98,6 +99,10 @@ class FunctionReader(
|
||||
val moduleVariable = preciseMatcher.group(4)
|
||||
val kotlinVariable = preciseMatcher.group(1)
|
||||
|
||||
val wrapFunctionVariable = WRAP_FUNCTION_PATTERN.matcher(content).let { matcher ->
|
||||
if (matcher.find() && matcher.group(2) == kotlinVariable) matcher.group(1) else null
|
||||
}
|
||||
|
||||
val sourceMap = sourceMapContent?.let {
|
||||
val sourceMapResult = SourceMapParser.parse(StringReader(it))
|
||||
when (sourceMapResult) {
|
||||
@@ -114,6 +119,7 @@ class FunctionReader(
|
||||
fileContent = content,
|
||||
moduleVariable = moduleVariable,
|
||||
kotlinVariable = kotlinVariable,
|
||||
wrapFunctionVariable = wrapFunctionVariable,
|
||||
offsetToSourceMappingProvider = { OffsetToSourceMapping(content) },
|
||||
sourceMap = sourceMap
|
||||
)
|
||||
@@ -195,10 +201,11 @@ class FunctionReader(
|
||||
offset++
|
||||
}
|
||||
|
||||
val wrapFunctionMatcher = wrapFunctionRegex.matcher(ShallowSubSequence(source, offset, source.length))
|
||||
val isWrapped = wrapFunctionMatcher.lookingAt()
|
||||
val sourcePart = ShallowSubSequence(source, offset, source.length)
|
||||
val wrapFunctionMatcher = info.wrapFunctionRegex?.matcher(sourcePart)
|
||||
val isWrapped = wrapFunctionMatcher?.lookingAt() == true
|
||||
if (isWrapped) {
|
||||
offset += wrapFunctionMatcher.end()
|
||||
offset += wrapFunctionMatcher!!.end()
|
||||
}
|
||||
|
||||
val position = info.offsetToSourceMapping[offset]
|
||||
@@ -220,12 +227,19 @@ class FunctionReader(
|
||||
wrapperStatements?.forEach { remapper.remap(it) }
|
||||
}
|
||||
|
||||
val allDefinedNames = collectDefinedNamesInAllScopes(function)
|
||||
val replacements = hashMapOf(info.moduleVariable to moduleReference,
|
||||
info.kotlinVariable to Namer.kotlinObject())
|
||||
replaceExternalNames(function, replacements)
|
||||
wrapperStatements?.forEach { replaceExternalNames(it, replacements) }
|
||||
replaceExternalNames(function, replacements, allDefinedNames)
|
||||
wrapperStatements?.forEach { replaceExternalNames(it, replacements, allDefinedNames) }
|
||||
function.markInlineArguments(descriptor)
|
||||
|
||||
info.wrapFunctionVariable.let { wrapFunction ->
|
||||
for (externalName in (collectReferencedNames(function) - allDefinedNames).filter { it.ident == wrapFunction }) {
|
||||
externalName.specialFunction = SpecialFunction.WRAP_FUNCTION
|
||||
}
|
||||
}
|
||||
|
||||
val namesWithoutSizeEffects = wrapperStatements.orEmpty().asSequence()
|
||||
.flatMap { collectDefinedNames(it).asSequence() }
|
||||
.toSet()
|
||||
@@ -283,12 +297,10 @@ private fun JsFunction.markInlineArguments(descriptor: CallableDescriptor) {
|
||||
visitor.accept(this)
|
||||
}
|
||||
|
||||
private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpression>) {
|
||||
val skipNames = collectDefinedNamesInAllScopes(node)
|
||||
|
||||
private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpression>, definedNames: Set<JsName>) {
|
||||
val visitor = object: JsVisitorWithContextImpl() {
|
||||
override fun endVisit(x: JsNameRef, ctx: JsContext<JsNode>) {
|
||||
if (x.qualifier != null || x.name in skipNames) return
|
||||
if (x.qualifier != null || x.name in definedNames) return
|
||||
|
||||
replacements[x.ident]?.let {
|
||||
ctx.replaceMe(it)
|
||||
@@ -299,8 +311,6 @@ private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpre
|
||||
visitor.accept(node)
|
||||
}
|
||||
|
||||
private val wrapFunctionRegex = Regex("\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\s*\\.\\s*wrapFunction\\s*\\(\\s*").toPattern()
|
||||
|
||||
private class ShallowSubSequence(private val underlying: CharSequence, private val start: Int, end: Int) : CharSequence {
|
||||
override val length: Int = end - start
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
fun collectFunctionReferencesInside(scope: JsNode): List<JsName> =
|
||||
collectReferencedNames(scope).filter { it.staticRef is JsFunction }
|
||||
|
||||
private fun collectReferencedNames(scope: JsNode): Set<JsName> {
|
||||
fun collectReferencedNames(scope: JsNode): Set<JsName> {
|
||||
val references = mutableSetOf<JsName>()
|
||||
|
||||
object : RecursiveJsVisitor() {
|
||||
|
||||
@@ -427,6 +427,12 @@ message Name {
|
||||
optional int32 identifier = 2;
|
||||
optional int32 local_name_id = 3;
|
||||
optional bool imported = 4 [default = false];
|
||||
optional SpecialFunction special_function = 5;
|
||||
}
|
||||
|
||||
enum SpecialFunction {
|
||||
DEFINE_INLINE_FUNCTION = 1;
|
||||
WRAP_FUNCTION = 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.serialization.js.ast
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Expression.ExpressionCase
|
||||
@@ -443,6 +444,9 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
||||
if (nameProto.hasImported()) {
|
||||
name.imported = nameProto.imported
|
||||
}
|
||||
if (nameProto.hasSpecialFunction()) {
|
||||
name.specialFunction = map(nameProto.specialFunction)
|
||||
}
|
||||
nameCache[id] = name
|
||||
name
|
||||
}
|
||||
@@ -513,6 +517,11 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
||||
InlineStrategy.NOT_INLINE -> KotlinInlineStrategy.NOT_INLINE
|
||||
}
|
||||
|
||||
private fun map(specialFunction: JsAstProtoBuf.SpecialFunction) = when(specialFunction) {
|
||||
JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION -> SpecialFunction.DEFINE_INLINE_FUNCTION
|
||||
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
|
||||
}
|
||||
|
||||
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
|
||||
val deserializedFile = fileId?.let { deserializeString(it) }
|
||||
val file = deserializedFile ?: fileStack.peek()
|
||||
|
||||
@@ -138,6 +138,62 @@ public final class JsAstProtoBuf {
|
||||
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.InlineStrategy)
|
||||
}
|
||||
|
||||
/**
|
||||
* Protobuf enum {@code org.jetbrains.kotlin.serialization.js.ast.SpecialFunction}
|
||||
*/
|
||||
public enum SpecialFunction
|
||||
implements org.jetbrains.kotlin.protobuf.Internal.EnumLite {
|
||||
/**
|
||||
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
|
||||
*/
|
||||
DEFINE_INLINE_FUNCTION(0, 1),
|
||||
/**
|
||||
* <code>WRAP_FUNCTION = 2;</code>
|
||||
*/
|
||||
WRAP_FUNCTION(1, 2),
|
||||
;
|
||||
|
||||
/**
|
||||
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
|
||||
*/
|
||||
public static final int DEFINE_INLINE_FUNCTION_VALUE = 1;
|
||||
/**
|
||||
* <code>WRAP_FUNCTION = 2;</code>
|
||||
*/
|
||||
public static final int WRAP_FUNCTION_VALUE = 2;
|
||||
|
||||
|
||||
public final int getNumber() { return value; }
|
||||
|
||||
public static SpecialFunction valueOf(int value) {
|
||||
switch (value) {
|
||||
case 1: return DEFINE_INLINE_FUNCTION;
|
||||
case 2: return WRAP_FUNCTION;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
|
||||
internalGetValueMap() {
|
||||
return internalValueMap;
|
||||
}
|
||||
private static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
|
||||
internalValueMap =
|
||||
new org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>() {
|
||||
public SpecialFunction findValueByNumber(int number) {
|
||||
return SpecialFunction.valueOf(number);
|
||||
}
|
||||
};
|
||||
|
||||
private final int value;
|
||||
|
||||
private SpecialFunction(int index, int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.SpecialFunction)
|
||||
}
|
||||
|
||||
public interface LocationOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.Location)
|
||||
org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder {
|
||||
@@ -34765,13 +34821,22 @@ public final class JsAstProtoBuf {
|
||||
int getLocalNameId();
|
||||
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
boolean hasImported();
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
boolean getImported();
|
||||
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
boolean hasSpecialFunction();
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
||||
@@ -34843,6 +34908,18 @@ public final class JsAstProtoBuf {
|
||||
imported_ = input.readBool();
|
||||
break;
|
||||
}
|
||||
case 40: {
|
||||
int rawValue = input.readEnum();
|
||||
org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction value = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.valueOf(rawValue);
|
||||
if (value == null) {
|
||||
unknownFieldsCodedOutput.writeRawVarint32(tag);
|
||||
unknownFieldsCodedOutput.writeRawVarint32(rawValue);
|
||||
} else {
|
||||
bitField0_ |= 0x00000010;
|
||||
specialFunction_ = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
||||
@@ -34925,23 +35002,39 @@ public final class JsAstProtoBuf {
|
||||
public static final int IMPORTED_FIELD_NUMBER = 4;
|
||||
private boolean imported_;
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean hasImported() {
|
||||
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean getImported() {
|
||||
return imported_;
|
||||
}
|
||||
|
||||
public static final int SPECIAL_FUNCTION_FIELD_NUMBER = 5;
|
||||
private org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction specialFunction_;
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public boolean hasSpecialFunction() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction() {
|
||||
return specialFunction_;
|
||||
}
|
||||
|
||||
private void initFields() {
|
||||
temporary_ = false;
|
||||
identifier_ = 0;
|
||||
localNameId_ = 0;
|
||||
imported_ = false;
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@@ -34972,6 +35065,9 @@ public final class JsAstProtoBuf {
|
||||
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||
output.writeBool(4, imported_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
output.writeEnum(5, specialFunction_.getNumber());
|
||||
}
|
||||
output.writeRawBytes(unknownFields);
|
||||
}
|
||||
|
||||
@@ -34997,6 +35093,10 @@ public final class JsAstProtoBuf {
|
||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||
.computeBoolSize(4, imported_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||
.computeEnumSize(5, specialFunction_.getNumber());
|
||||
}
|
||||
size += unknownFields.size();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@@ -35099,6 +35199,8 @@ public final class JsAstProtoBuf {
|
||||
bitField0_ = (bitField0_ & ~0x00000004);
|
||||
imported_ = false;
|
||||
bitField0_ = (bitField0_ & ~0x00000008);
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -35138,6 +35240,10 @@ public final class JsAstProtoBuf {
|
||||
to_bitField0_ |= 0x00000008;
|
||||
}
|
||||
result.imported_ = imported_;
|
||||
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
to_bitField0_ |= 0x00000010;
|
||||
}
|
||||
result.specialFunction_ = specialFunction_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
return result;
|
||||
}
|
||||
@@ -35156,6 +35262,9 @@ public final class JsAstProtoBuf {
|
||||
if (other.hasImported()) {
|
||||
setImported(other.getImported());
|
||||
}
|
||||
if (other.hasSpecialFunction()) {
|
||||
setSpecialFunction(other.getSpecialFunction());
|
||||
}
|
||||
setUnknownFields(
|
||||
getUnknownFields().concat(other.unknownFields));
|
||||
return this;
|
||||
@@ -35286,19 +35395,19 @@ public final class JsAstProtoBuf {
|
||||
|
||||
private boolean imported_ ;
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean hasImported() {
|
||||
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public boolean getImported() {
|
||||
return imported_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public Builder setImported(boolean value) {
|
||||
bitField0_ |= 0x00000008;
|
||||
@@ -35307,7 +35416,7 @@ public final class JsAstProtoBuf {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool imported = 4;</code>
|
||||
* <code>optional bool imported = 4 [default = false];</code>
|
||||
*/
|
||||
public Builder clearImported() {
|
||||
bitField0_ = (bitField0_ & ~0x00000008);
|
||||
@@ -35316,6 +35425,41 @@ public final class JsAstProtoBuf {
|
||||
return this;
|
||||
}
|
||||
|
||||
private org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public boolean hasSpecialFunction() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction() {
|
||||
return specialFunction_;
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public Builder setSpecialFunction(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
bitField0_ |= 0x00000010;
|
||||
specialFunction_ = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
|
||||
*/
|
||||
public Builder clearSpecialFunction() {
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.serialization.js.ast
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.BinaryOperation.Type.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.UnaryOperation.Type.*
|
||||
@@ -552,6 +553,11 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
|
||||
KotlinInlineStrategy.NOT_INLINE -> InlineStrategy.NOT_INLINE
|
||||
}
|
||||
|
||||
private fun map(specialFunction: SpecialFunction) = when (specialFunction) {
|
||||
SpecialFunction.DEFINE_INLINE_FUNCTION -> JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION
|
||||
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
|
||||
}
|
||||
|
||||
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
|
||||
val builder = Name.newBuilder()
|
||||
builder.identifier = serialize(name.ident)
|
||||
@@ -564,6 +570,10 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
|
||||
builder.imported = true
|
||||
}
|
||||
|
||||
name.specialFunction?.let {
|
||||
builder.specialFunction = map(it)
|
||||
}
|
||||
|
||||
val result = nameTableBuilder.entryCount
|
||||
nameTableBuilder.addEntry(builder)
|
||||
result
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.TypeCheck;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
@@ -361,6 +362,18 @@ public final class Namer {
|
||||
return pureFqn(WRAP_FUNCTION, kotlinObject());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression createSpecialFunction(@NotNull SpecialFunction specialFunction) {
|
||||
switch (specialFunction) {
|
||||
case DEFINE_INLINE_FUNCTION:
|
||||
return createInlineFunction();
|
||||
case WRAP_FUNCTION:
|
||||
return wrapFunction();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown function: " + specialFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String suggestedModuleName(@NotNull String id) {
|
||||
if (id.isEmpty()) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestionKt;
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.SignatureUtilsKt;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
@@ -141,6 +143,8 @@ public final class StaticContext {
|
||||
|
||||
private final Map<String, JsExpression> modulesImportedForInline = new HashMap<>();
|
||||
|
||||
private final Map<SpecialFunction, JsName> specialFunctions = new EnumMap<>(SpecialFunction.class);
|
||||
|
||||
public StaticContext(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull JsConfig config,
|
||||
@@ -859,4 +863,14 @@ public final class StaticContext {
|
||||
return moduleRef;
|
||||
}).deepCopy();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForSpecialFunction(@NotNull SpecialFunction specialFunction) {
|
||||
return specialFunctions.computeIfAbsent(specialFunction, f -> {
|
||||
JsExpression expression = Namer.createSpecialFunction(specialFunction);
|
||||
JsName name = importDeclaration(f.getSuggestedName(), TranslationUtils.getTagForSpecialFunction(f), expression);
|
||||
MetadataProperties.setSpecialFunction(name, f);
|
||||
return name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.ClassModelGenerator;
|
||||
@@ -819,4 +820,22 @@ public class TranslationContext {
|
||||
public TranslationContext getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForSpecialFunction(@NotNull SpecialFunction function) {
|
||||
if (inlineFunctionContext == null || !isPublicInlineFunction()) {
|
||||
return staticContext.getNameForSpecialFunction(function);
|
||||
}
|
||||
else {
|
||||
String tag = TranslationUtils.getTagForSpecialFunction(function);
|
||||
return inlineFunctionContext.getImports().computeIfAbsent(tag, t -> {
|
||||
JsExpression imported = Namer.createSpecialFunction(function);
|
||||
JsName result = JsScope.declareTemporaryName(function.getSuggestedName());
|
||||
MetadataProperties.setImported(result, true);
|
||||
MetadataProperties.setSpecialFunction(result, function);
|
||||
inlineFunctionContext.getImportBlock().getStatements().add(JsAstUtils.newVar(result, imported));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
||||
}
|
||||
innerContext.translateFunction(expression, function)
|
||||
return innerContext.wrapWithInlineMetadata(function, descriptor)
|
||||
return innerContext.wrapWithInlineMetadata(context, function, descriptor)
|
||||
}
|
||||
|
||||
// used from kotlinx.serialization
|
||||
|
||||
+6
-3
@@ -101,11 +101,14 @@ fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, fun
|
||||
function.functionDescriptor = descriptor
|
||||
}
|
||||
|
||||
fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor): JsExpression {
|
||||
fun TranslationContext.wrapWithInlineMetadata(
|
||||
outerContext: TranslationContext,
|
||||
function: JsFunction, descriptor: FunctionDescriptor
|
||||
): JsExpression {
|
||||
val sourceInfo = descriptor.source.getPsi()
|
||||
return if (descriptor.isInline && descriptor.isEffectivelyPublicApi) {
|
||||
val metadata = InlineMetadata.compose(function, descriptor, this)
|
||||
val functionWithMetadata = metadata.functionWithMetadata(sourceInfo)
|
||||
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
|
||||
|
||||
config.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.apply {
|
||||
val psiFile = (descriptor.source.containingFile as? PsiSourceFile)?.psiFile ?: return@apply
|
||||
@@ -136,6 +139,6 @@ fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor:
|
||||
else {
|
||||
null
|
||||
}
|
||||
if (block != null) InlineMetadata.wrapFunction(FunctionWithWrapper(function, block), sourceInfo) else function
|
||||
if (block != null) InlineMetadata.wrapFunction(outerContext, FunctionWithWrapper(function, block), sourceInfo) else function
|
||||
}
|
||||
}
|
||||
|
||||
+13
-8
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.js.translate.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
|
||||
import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
@@ -43,8 +45,11 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
|
||||
}
|
||||
|
||||
private fun decomposeCreateFunctionCall(call: JsInvocation): InlineMetadata? {
|
||||
val qualifier = call.qualifier
|
||||
if (qualifier !is JsNameRef || qualifier.ident != Namer.DEFINE_INLINE_FUNCTION) return null
|
||||
val qualifier = call.qualifier as? JsNameRef ?: return null
|
||||
if (qualifier.ident != Namer.DEFINE_INLINE_FUNCTION &&
|
||||
qualifier.name?.specialFunction != SpecialFunction.DEFINE_INLINE_FUNCTION) {
|
||||
return null
|
||||
}
|
||||
|
||||
val arguments = call.arguments
|
||||
if (arguments.size != METADATA_PROPERTIES_COUNT) return null
|
||||
@@ -61,8 +66,7 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
|
||||
if (callExpression !is JsInvocation) return null
|
||||
|
||||
val qualifier = callExpression.qualifier as? JsNameRef ?: return null
|
||||
val qualifierQualifier = qualifier.qualifier as? JsNameRef ?: return null
|
||||
if (qualifierQualifier.qualifier != null || qualifier.ident != Namer.WRAP_FUNCTION) return null
|
||||
if (qualifier.name?.specialFunction != SpecialFunction.WRAP_FUNCTION) return null
|
||||
if (callExpression.arguments.size != 1) return null
|
||||
|
||||
val argument = callExpression.arguments[0] as? JsFunction ?: return null
|
||||
@@ -78,7 +82,7 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun wrapFunction(function: FunctionWithWrapper, sourceInfo: Any?): JsExpression {
|
||||
fun wrapFunction(context: TranslationContext, function: FunctionWithWrapper, sourceInfo: Any?): JsExpression {
|
||||
val wrapperBody = function.wrapperBody ?: JsBlock(JsReturn(function.function))
|
||||
val wrapper = JsFunction(function.function.scope, wrapperBody, "")
|
||||
function.wrapperBody?.statements?.forEach {
|
||||
@@ -90,10 +94,11 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
|
||||
}
|
||||
}
|
||||
|
||||
return JsInvocation(Namer.wrapFunction(), wrapper).source(sourceInfo)
|
||||
return JsInvocation(context.getNameForSpecialFunction(SpecialFunction.WRAP_FUNCTION).makeRef(), wrapper).source(sourceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
fun functionWithMetadata(sourceInfo: Any?): JsExpression =
|
||||
JsInvocation(Namer.createInlineFunction(), tag, wrapFunction(function, sourceInfo))
|
||||
fun functionWithMetadata(context: TranslationContext, sourceInfo: Any?): JsExpression =
|
||||
JsInvocation(context.getNameForSpecialFunction(SpecialFunction.DEFINE_INLINE_FUNCTION).makeRef(),
|
||||
tag, wrapFunction(context, function, sourceInfo))
|
||||
}
|
||||
+2
-2
@@ -114,7 +114,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
||||
|
||||
private fun TranslationContext.addFunctionDeclaration(name: JsName, function: JsFunction, source: Any?) {
|
||||
addFunctionButNotExport(name, if (isPublicInlineFunction) {
|
||||
InlineMetadata.wrapFunction(FunctionWithWrapper(function, null), source)
|
||||
InlineMetadata.wrapFunction(this, FunctionWithWrapper(function, null), source)
|
||||
}
|
||||
else {
|
||||
function
|
||||
@@ -127,7 +127,7 @@ fun JsFunction.withCapturedParameters(
|
||||
invokingContext: TranslationContext,
|
||||
source: KtDeclaration
|
||||
): JsExpression {
|
||||
context.addFunctionDeclaration(functionName, this, source)
|
||||
invokingContext.addFunctionDeclaration(functionName, this, source)
|
||||
val ref = JsAstUtils.pureFqn(functionName, null)
|
||||
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
@@ -58,14 +59,15 @@ public final class TranslationUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(
|
||||
@NotNull JsFunction function, @NotNull FunctionDescriptor descriptor,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
JsExpression functionExpression = function;
|
||||
if (InlineUtil.isInline(descriptor)) {
|
||||
InlineMetadata metadata = InlineMetadata.compose(function, descriptor, context);
|
||||
PsiElement sourceInfo = KotlinSourceElementKt.getPsi(descriptor.getSource());
|
||||
functionExpression = metadata.functionWithMetadata(sourceInfo);
|
||||
functionExpression = metadata.functionWithMetadata(context, sourceInfo);
|
||||
}
|
||||
|
||||
if (DescriptorUtils.isExtension(descriptor) ||
|
||||
@@ -414,4 +416,9 @@ public final class TranslationUtils {
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getTagForSpecialFunction(@NotNull SpecialFunction specialFunction) {
|
||||
return "special:" + specialFunction.name();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// EXPECTED_REACHABLE_NODES: 994
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
fun foo(x: String) = "foo($x)"
|
||||
|
||||
Reference in New Issue
Block a user