[JS IR] arrayConcat not use additional slice

This commit is contained in:
Ilya Goncharov
2021-03-09 14:20:06 +03:00
parent 76005813ff
commit f890156dde
3 changed files with 49 additions and 25 deletions
@@ -152,30 +152,11 @@ private class VarargTransformer(
// vararg with a single segment => no need to concatenate
if (segments.size == 1) {
val segment = segments.first()
if (expression in externalVarargs) {
externalVarargs.remove(expression)
return segment
}
val argument = if (expression.elements.any { it is IrSpreadElement }) {
val elementType = arrayInfo.primitiveElementType
val copyFunction =
if (elementType.isChar() || elementType.isBoolean() || elementType.isLong())
context.intrinsics.taggedArrayCopy
else
context.intrinsics.jsArraySlice
IrCallImpl(
expression.startOffset,
expression.endOffset,
arrayInfo.primitiveArrayType,
copyFunction,
typeArgumentsCount = 1,
valueArgumentsCount = 1
).apply {
putTypeArgument(0, arrayInfo.primitiveArrayType)
putValueArgument(0, segment)
}
} else segment
val argument = getArgumentFromSingleSegment(
expression,
segment,
arrayInfo
)
return arrayInfo.boxArrayIfNeeded(argument)
}
@@ -206,6 +187,38 @@ private class VarargTransformer(
return arrayInfo.boxArrayIfNeeded(res)
}
private fun getArgumentFromSingleSegment(
expression: IrVararg,
segment: IrExpression,
arrayInfo: InlineClassArrayInfo
): IrExpression {
if (expression in externalVarargs) {
externalVarargs.remove(expression)
return segment
}
return if (expression.elements.any { it is IrSpreadElement }) {
val elementType = arrayInfo.primitiveElementType
val copyFunction =
if (elementType.isChar() || elementType.isBoolean() || elementType.isLong())
context.intrinsics.taggedArrayCopy
else
context.intrinsics.jsArraySlice
IrCallImpl(
expression.startOffset,
expression.endOffset,
arrayInfo.primitiveArrayType,
copyFunction,
typeArgumentsCount = 1,
valueArgumentsCount = 1
).apply {
putTypeArgument(0, arrayInfo.primitiveArrayType)
putValueArgument(0, segment)
}
} else segment
}
private fun transformFunctionAccessExpression(expression: IrFunctionAccessExpression): IrExpression {
if (expression.symbol.owner.isExternal) {
for (i in 0 until expression.valueArgumentsCount) {
@@ -170,6 +170,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
JsNew(refForExternalClass, arguments)
} else {
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
expression,
context,
JsNullLiteral(),
arguments,
varargParameterIndex
@@ -156,6 +156,8 @@ fun translateCall(
// TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators)
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
expression,
context,
jsExtensionReceiver,
arguments,
varargParameterIndex
@@ -223,6 +225,8 @@ fun translateCall(
}
fun argumentsWithVarargAsSingleArray(
expression: IrFunctionAccessExpression,
context: JsGenerationContext,
additionalReceiver: JsExpression?,
arguments: List<JsExpression>,
varargParameterIndex: Int,
@@ -241,6 +245,8 @@ fun argumentsWithVarargAsSingleArray(
// Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays
varargParameterIndex -> {
val valueArgument = expression.getValueArgument(varargParameterIndex)
if (arraysForConcat.isNotEmpty()) {
concatElements.add(JsArrayLiteral(arraysForConcat))
}
@@ -250,7 +256,10 @@ fun argumentsWithVarargAsSingleArray(
is JsArrayLiteral -> argument
is JsNew -> argument.arguments.firstOrNull() as? JsArrayLiteral
else -> null
} ?: JsInvocation(JsNameRef("call", JsNameRef("slice", JsArrayLiteral())), argument)
} ?: if (valueArgument is IrCall && valueArgument.symbol == context.staticContext.backendContext.intrinsics.arrayConcat)
argument
else
JsInvocation(JsNameRef("call", JsNameRef("slice", JsArrayLiteral())), argument)
concatElements.add(varargArgument)
}