[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 // vararg with a single segment => no need to concatenate
if (segments.size == 1) { if (segments.size == 1) {
val segment = segments.first() val segment = segments.first()
if (expression in externalVarargs) { val argument = getArgumentFromSingleSegment(
externalVarargs.remove(expression) expression,
return segment segment,
} arrayInfo
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
return arrayInfo.boxArrayIfNeeded(argument) return arrayInfo.boxArrayIfNeeded(argument)
} }
@@ -206,6 +187,38 @@ private class VarargTransformer(
return arrayInfo.boxArrayIfNeeded(res) 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 { private fun transformFunctionAccessExpression(expression: IrFunctionAccessExpression): IrExpression {
if (expression.symbol.owner.isExternal) { if (expression.symbol.owner.isExternal) {
for (i in 0 until expression.valueArgumentsCount) { for (i in 0 until expression.valueArgumentsCount) {
@@ -170,6 +170,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
JsNew(refForExternalClass, arguments) JsNew(refForExternalClass, arguments)
} else { } else {
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray( val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
expression,
context,
JsNullLiteral(), JsNullLiteral(),
arguments, arguments,
varargParameterIndex 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) // 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( val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
expression,
context,
jsExtensionReceiver, jsExtensionReceiver,
arguments, arguments,
varargParameterIndex varargParameterIndex
@@ -223,6 +225,8 @@ fun translateCall(
} }
fun argumentsWithVarargAsSingleArray( fun argumentsWithVarargAsSingleArray(
expression: IrFunctionAccessExpression,
context: JsGenerationContext,
additionalReceiver: JsExpression?, additionalReceiver: JsExpression?,
arguments: List<JsExpression>, arguments: List<JsExpression>,
varargParameterIndex: Int, 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 // Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays
varargParameterIndex -> { varargParameterIndex -> {
val valueArgument = expression.getValueArgument(varargParameterIndex)
if (arraysForConcat.isNotEmpty()) { if (arraysForConcat.isNotEmpty()) {
concatElements.add(JsArrayLiteral(arraysForConcat)) concatElements.add(JsArrayLiteral(arraysForConcat))
} }
@@ -250,7 +256,10 @@ fun argumentsWithVarargAsSingleArray(
is JsArrayLiteral -> argument is JsArrayLiteral -> argument
is JsNew -> argument.arguments.firstOrNull() as? JsArrayLiteral is JsNew -> argument.arguments.firstOrNull() as? JsArrayLiteral
else -> null 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) concatElements.add(varargArgument)
} }