From 70e847b794e8586fda04b417607be5e61a5d75c8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 27 Jan 2016 03:28:35 +0300 Subject: [PATCH] Reimplement generation of intrinsic array constructors Instead of relying on a class from the runtime (which thus cannot be deleted from the runtime ever), rely on a class from the compiler instead. This has a minor downside: that class is compiled by the bootstrap compiler, so if codegen of 'for'-loops or something else used in that class changes, it won't immediately have an effect on a local working copy (on the build server everything will be fine because of a 2-step building process). In the future it may make sense to just manually create all the bytecode instructions and dump them into a MethodNode. Currently the amount of work needed for that seems rather significant --- .../kotlin/codegen/ExpressionCodegen.java | 69 ++--------- .../inline/FictitiousArrayConstructor.kt | 38 +++++++ .../kotlin/codegen/inline/InlineCodegen.java | 78 ++++++------- .../codegen/inline/InlineCodegenUtil.java | 12 +- .../codegen/intrinsics/ArrayConstructor.kt | 27 +++++ .../intrinsics/IntrinsicArrayConstructors.kt | 107 ++++++++++++++++++ .../codegen/intrinsics/IntrinsicMethods.java | 5 +- compiler/compiler.pro | 2 + .../kotlin/resolve/inline/InlineUtil.java | 11 ++ .../kotlin/builtins/KotlinBuiltIns.java | 4 + .../internal/IntrinsicArrayConstructors.kt | 92 --------------- 11 files changed, 253 insertions(+), 192 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/FictitiousArrayConstructor.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/ArrayConstructor.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt delete mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/IntrinsicArrayConstructors.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index a78bdd78c7d..3fac79aa049 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -56,8 +56,6 @@ import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesKt; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor; -import org.jetbrains.kotlin.name.ClassId; -import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; @@ -80,13 +78,11 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.receivers.*; -import org.jetbrains.kotlin.serialization.deserialization.FindClassInModuleKt; import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeProjection; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; -import org.jetbrains.kotlin.utils.StringsKt; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Opcodes; @@ -101,7 +97,8 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.resolve.BindingContextUtils.*; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral; @@ -2435,11 +2432,11 @@ public class ExpressionCodegen extends KtVisitor impleme // We should inline callable containing reified type parameters even if inline is disabled // because they may contain something to reify and straight call will probably fail at runtime boolean isInline = (state.isInlineEnabled() || InlineUtil.containsReifiedTypeParameters(descriptor)) && - InlineUtil.isInline(descriptor); + (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor)); if (!isInline) return defaultCallGenerator; - SimpleFunctionDescriptor original = DescriptorUtils.unwrapFakeOverride((SimpleFunctionDescriptor) descriptor.getOriginal()); + FunctionDescriptor original = DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal()); return new InlineCodegen(this, state, original, callElement, typeParameterMappings); } @@ -2457,6 +2454,8 @@ public class ExpressionCodegen extends KtVisitor impleme KotlinType type = TypeUtils.uncaptureTypeForInlineMapping(entry.getValue()); + boolean isReified = key.isReified() || InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor()); + Pair typeParameterAndReificationArgument = extractReificationArgument(type); if (typeParameterAndReificationArgument == null) { // type is not generic @@ -2464,16 +2463,13 @@ public class ExpressionCodegen extends KtVisitor impleme Type asmType = typeMapper.mapTypeParameter(type, signatureWriter); mappings.addParameterMappingToType( - key.getName().getIdentifier(), - type, - asmType, - signatureWriter.toString(), - key.isReified()); + key.getName().getIdentifier(), type, asmType, signatureWriter.toString(), isReified + ); } else { mappings.addParameterMappingForFurtherReification( - key.getName().getIdentifier(), type, - typeParameterAndReificationArgument.getSecond(), key.isReified()); + key.getName().getIdentifier(), type, typeParameterAndReificationArgument.getSecond(), isReified + ); } } return getOrCreateCallGenerator( @@ -3412,50 +3408,7 @@ public class ExpressionCodegen extends KtVisitor impleme }); } - final ConstructorDescriptor constructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); - - final ClassDescriptor intrinsicConstructors = - FindClassInModuleKt.findClassAcrossModuleDependencies( - getContainingModule(context.getContextDescriptor()), - ClassId.topLevel(new FqName("kotlin.jvm.internal.IntrinsicArrayConstructors")) - ); - // TODO: do not depend on a class from the runtime - assert intrinsicConstructors != null : "Class IntrinsicArrayConstructors is not found"; - - ResolvedCall fakeResolvedCall = new DelegatingResolvedCall(resolvedCall) { - private final CallableDescriptor descriptor; - - { - Collection functions = intrinsicConstructors.getUnsubstitutedMemberScope().getContributedFunctions( - constructor.getContainingDeclaration().getName(), NoLookupLocation.FROM_BACKEND); - assert functions.size() == 1 - : "IntrinsicArrayConstructors does not have a single constructor for " + - constructor.getContainingDeclaration().getName() + ":\n" + StringsKt.join(functions, "\n"); - descriptor = CollectionsKt.single(functions); - } - - @NotNull - @Override - public CallableDescriptor getResultingDescriptor() { - return descriptor; - } - - @NotNull - @Override - public Map getTypeArguments() { - Map originalArgs = super.getTypeArguments(); - if (originalArgs.isEmpty()) return originalArgs; - - assert originalArgs.size() == 1 : "Unknown constructor called: " + originalArgs.size() + " type arguments"; - - return Collections.singletonMap( - CollectionsKt.single(descriptor.getTypeParameters()), - CollectionsKt.single(originalArgs.values()) - ); - } - }; - - return invokeFunction(fakeResolvedCall, StackValue.singleton(intrinsicConstructors, typeMapper)); + return invokeFunction(resolvedCall, StackValue.none()); } public void newArrayInstruction(@NotNull KotlinType arrayType) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/FictitiousArrayConstructor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/FictitiousArrayConstructor.kt new file mode 100644 index 00000000000..b844efff559 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/FictitiousArrayConstructor.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2016 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.codegen.inline + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl + +internal class FictitiousArrayConstructor(arrayClass: ClassDescriptor) : SimpleFunctionDescriptorImpl( + arrayClass.containingDeclaration, null, Annotations.EMPTY, arrayClass.name, CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE +) { + companion object Factory { + @JvmStatic + fun create(arrayConstructor: ConstructorDescriptor): FictitiousArrayConstructor { + val arrayClass = arrayConstructor.containingDeclaration + return FictitiousArrayConstructor(arrayClass).apply { + this.initialize(null, null, arrayConstructor.typeParameters, arrayConstructor.valueParameters, arrayClass.defaultType, + Modality.FINAL, Visibilities.PUBLIC) + this.isInline = true + } + } + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index d44a26a2e48..7626f1ef08f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.context.*; +import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; @@ -69,7 +70,7 @@ public class InlineCodegen extends CallGenerator { private final GenerationState state; private final JetTypeMapper typeMapper; - private final SimpleFunctionDescriptor functionDescriptor; + private final FunctionDescriptor functionDescriptor; private final JvmMethodSignature jvmSignature; private final KtElement callElement; private final MethodContext context; @@ -92,17 +93,21 @@ public class InlineCodegen extends CallGenerator { public InlineCodegen( @NotNull ExpressionCodegen codegen, @NotNull GenerationState state, - @NotNull SimpleFunctionDescriptor functionDescriptor, + @NotNull FunctionDescriptor function, @NotNull KtElement callElement, @Nullable TypeParameterMappings typeParameterMappings ) { - assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor; + assert InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function) : + "InlineCodegen can inline only inline functions and array constructors: " + function; this.state = state; this.typeMapper = state.getTypeMapper(); this.codegen = codegen; this.callElement = callElement; - this.functionDescriptor = functionDescriptor.getOriginal(); + this.functionDescriptor = + InlineUtil.isArrayConstructorWithLambda(function) + ? FictitiousArrayConstructor.create((ConstructorDescriptor) function) + : function.getOriginal(); this.typeParameterMappings = typeParameterMappings; reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings); @@ -119,13 +124,14 @@ public class InlineCodegen extends CallGenerator { isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory()); sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); - reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal()); + + if (!(functionDescriptor instanceof FictitiousArrayConstructor)) { + reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal()); + } } @Override - public void genCallWithoutAssertions( - @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen - ) { + public void genCallWithoutAssertions(@NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen) { genCall(callableMethod, null, false, codegen); } @@ -176,19 +182,25 @@ public class InlineCodegen extends CallGenerator { } @NotNull - private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException { - JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); - - Method asmMethod; - if (callDefault) { - asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind()); - } - else { - asmMethod = jvmSignature.getAsmMethod(); - } + private SMAPAndMethodNode createMethodNode(boolean callDefault) throws IOException { + Method asmMethod = callDefault + ? typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind()) + : jvmSignature.getAsmMethod(); SMAPAndMethodNode nodeAndSMAP; - if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { + if (functionDescriptor instanceof FictitiousArrayConstructor) { + nodeAndSMAP = InlineCodegenUtil.getMethodNode( + IntrinsicArrayConstructorsKt.getBytecode(), + asmMethod.getName(), + asmMethod.getDescriptor(), + IntrinsicArrayConstructorsKt.getClassId() + ); + + if (nodeAndSMAP == null) { + throw new IllegalStateException("Couldn't obtain array constructor body for " + descriptorName(functionDescriptor)); + } + } + else if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable( (DeserializedSimpleFunctionDescriptor) functionDescriptor); @@ -203,14 +215,14 @@ public class InlineCodegen extends CallGenerator { ); if (nodeAndSMAP == null) { - throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); + throw new IllegalStateException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); } } else { PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); - if (element == null || !(element instanceof KtNamedFunction)) { - throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); + if (!(element instanceof KtNamedFunction)) { + throw new IllegalStateException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); } KtNamedFunction inliningFunction = (KtNamedFunction) element; @@ -260,14 +272,10 @@ public class InlineCodegen extends CallGenerator { Parameters parameters = invocationParamBuilder.buildParameters(); - InliningContext info = new RootInliningContext(expressionMap, - state, - codegen.getInlineNameGenerator() - .subGenerator(functionDescriptor.getName().asString()), - codegen.getContext(), - callElement, - getInlineCallSiteInfo(), reifiedTypeInliner, - typeParameterMappings); + InliningContext info = new RootInliningContext( + expressionMap, state, codegen.getInlineNameGenerator().subGenerator(jvmSignature.getAsmMethod().getName()), + codegen.getContext(), callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings + ); MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText(), @@ -529,13 +537,11 @@ public class InlineCodegen extends CallGenerator { @Override public void putHiddenParams() { - List valueParameters = jvmSignature.getValueParameters(); - - if (!isStaticMethod(functionDescriptor, context)) { + if ((getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == 0) { invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); } - for (JvmMethodParameterSignature param : valueParameters) { + for (JvmMethodParameterSignature param : jvmSignature.getValueParameters()) { if (param.getKind() == JvmMethodParameterKind.VALUE) { break; } @@ -643,10 +649,6 @@ public class InlineCodegen extends CallGenerator { throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor)); } - private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) { - return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; - } - private static String descriptorName(DeclarationDescriptor descriptor) { return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index 0a6dadc5fce..29c7a9bf467 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.context.CodegenContextUtil; import org.jetbrains.kotlin.codegen.context.InlineLambdaContext; import org.jetbrains.kotlin.codegen.context.MethodContext; +import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt; import org.jetbrains.kotlin.codegen.optimization.common.UtilKt; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -84,7 +85,7 @@ public class InlineCodegenUtil { final String methodName, final String methodDescriptor, ClassId classId - ) throws ClassNotFoundException, IOException { + ) throws IOException { ClassReader cr = new ClassReader(classData); final MethodNode[] node = new MethodNode[1]; final String[] debugInfo = new String[2]; @@ -127,6 +128,15 @@ public class InlineCodegenUtil { } }, ClassReader.SKIP_FRAMES | (GENERATE_SMAP ? 0 : ClassReader.SKIP_DEBUG)); + if (node[0] == null) { + return null; + } + + if (classId.equals(IntrinsicArrayConstructorsKt.getClassId())) { + // Don't load source map for intrinsic array constructors + debugInfo[0] = null; + } + SMAP smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classId.asString(), lines[0], lines[1]); return new SMAPAndMethodNode(node[0], smap); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/ArrayConstructor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/ArrayConstructor.kt new file mode 100644 index 00000000000..5e3603c03da --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/ArrayConstructor.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2016 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.codegen.intrinsics + +import org.jetbrains.kotlin.codegen.Callable +import org.jetbrains.kotlin.codegen.CallableMethod +import org.jetbrains.kotlin.name.FqName + +object ArrayConstructor : IntrinsicMethod() { + override fun toCallable(method: CallableMethod): Callable { + return object : IntrinsicCallable(method.owner, method.valueParameterTypes, null, null) {} + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt new file mode 100644 index 00000000000..cab7796d484 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2016 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.kotlin.codegen.intrinsics + +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName + +// Bodies of methods in this file are used in InlineCodegen to inline array constructors. It is loaded via reflection at runtime. +// TODO: generate the bytecode manually instead, do not depend on the previous compiler working correctly here + +internal val classId: ClassId = + ClassId.topLevel(FqName("org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt")) + +internal val bytecode: ByteArray by lazy { + val stream = object {}.javaClass.classLoader.getResourceAsStream("${classId.asString()}.class") + stream.readBytes().apply { + stream.close() + } +} + +private inline fun Array(size: Int, init: (Int) -> T): Array { + val result = arrayOfNulls(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result as Array +} + +private inline fun DoubleArray(size: Int, init: (Int) -> Double): DoubleArray { + val result = DoubleArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun FloatArray(size: Int, init: (Int) -> Float): FloatArray { + val result = FloatArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun LongArray(size: Int, init: (Int) -> Long): LongArray { + val result = LongArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun IntArray(size: Int, init: (Int) -> Int): IntArray { + val result = IntArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun CharArray(size: Int, init: (Int) -> Char): CharArray { + val result = CharArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun ShortArray(size: Int, init: (Int) -> Short): ShortArray { + val result = ShortArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun ByteArray(size: Int, init: (Int) -> Byte): ByteArray { + val result = ByteArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} + +private inline fun BooleanArray(size: Int, init: (Int) -> Boolean): BooleanArray { + val result = BooleanArray(size) + for (i in 0..size - 1) { + result[i] = init(i) + } + return result +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java index bbfe3618f9e..8bd1845dcb4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java @@ -29,9 +29,7 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType; import org.jetbrains.kotlin.types.expressions.OperatorConventions; -import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES; -import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME; -import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME; +import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class IntrinsicMethods { @@ -150,6 +148,7 @@ public class IntrinsicMethods { declareIntrinsicFunction(arrayTypeFqName, "get", 1, ARRAY_GET); declareIntrinsicFunction(arrayTypeFqName, "clone", 0, CLONE); declareIntrinsicFunction(arrayTypeFqName, "iterator", 0, ARRAY_ITERATOR); + declareIntrinsicFunction(arrayTypeFqName, "", 2, ArrayConstructor.INSTANCE); } private void declareBinaryOp(@NotNull String methodName, int opcode) { diff --git a/compiler/compiler.pro b/compiler/compiler.pro index 1bdca979535..008005d76cc 100644 --- a/compiler/compiler.pro +++ b/compiler/compiler.pro @@ -69,6 +69,8 @@ messages/**) public protected *; } +-keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } + -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java index 246a08b58c6..9ba18a80c66 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java @@ -133,6 +133,17 @@ public class InlineUtil { return functionalExpression instanceof KtFunctionLiteral || functionalExpression instanceof KtNamedFunction; } + /** + * @return true if the descriptor is the constructor of one of 9 array classes (Array<T>, IntArray, FloatArray, ...) + * which takes the size and an initializer lambda as parameters. Such constructors are marked as 'inline' but they are not loaded + * as such because the 'inline' flag is not stored for constructors in the binary metadata. Therefore we pretend that they are inline + */ + public static boolean isArrayConstructorWithLambda(@NotNull CallableDescriptor descriptor) { + return descriptor.getValueParameters().size() == 2 && + descriptor instanceof ConstructorDescriptor && + KotlinBuiltIns.isArrayOrPrimitiveArray(((ConstructorDescriptor) descriptor).getContainingDeclaration()); + } + @Nullable public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) { DeclarationDescriptor current = strict ? descriptor.getContainingDeclaration() : descriptor; diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index be1f725a524..f52ae31aed1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -878,6 +878,10 @@ public abstract class KotlinBuiltIns { return isConstructedFromGivenClass(type, FQ_NAMES.array); } + public static boolean isArrayOrPrimitiveArray(@NotNull ClassDescriptor descriptor) { + return classFqNameEquals(descriptor, FQ_NAMES.array) || getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null; + } + public static boolean isPrimitiveArray(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return descriptor != null && getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null; diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/IntrinsicArrayConstructors.kt b/core/runtime.jvm/src/kotlin/jvm/internal/IntrinsicArrayConstructors.kt deleted file mode 100644 index 79050d1531b..00000000000 --- a/core/runtime.jvm/src/kotlin/jvm/internal/IntrinsicArrayConstructors.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2010-2016 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 kotlin.jvm.internal - -@Suppress("unused") -object IntrinsicArrayConstructors { - private inline fun Array(size: Int, init: (Int) -> T): Array { - val result = arrayOfNulls(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result as Array - } - - private inline fun DoubleArray(size: Int, init: (Int) -> Double): DoubleArray { - val result = DoubleArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun FloatArray(size: Int, init: (Int) -> Float): FloatArray { - val result = FloatArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun LongArray(size: Int, init: (Int) -> Long): LongArray { - val result = LongArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun IntArray(size: Int, init: (Int) -> Int): IntArray { - val result = IntArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun CharArray(size: Int, init: (Int) -> Char): CharArray { - val result = CharArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun ShortArray(size: Int, init: (Int) -> Short): ShortArray { - val result = ShortArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun ByteArray(size: Int, init: (Int) -> Byte): ByteArray { - val result = ByteArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } - - private inline fun BooleanArray(size: Int, init: (Int) -> Boolean): BooleanArray { - val result = BooleanArray(size) - for (i in 0..size - 1) { - result[i] = init(i) - } - return result - } -}