diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 81c5cbef9ae..71acad3ba6a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.codegen; import com.google.common.collect.Lists; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.util.ArrayUtil; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.binding.CalculatedClosure; @@ -43,7 +44,6 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.OverrideResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; @@ -1214,7 +1214,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generatePrimaryConstructorImpl( @Nullable ConstructorDescriptor constructorDescriptor, - @NotNull ExpressionCodegen codegen, + @NotNull final ExpressionCodegen codegen, @Nullable MutableClosure closure ) { List paramDescrs = constructorDescriptor != null @@ -1269,12 +1269,22 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { boolean generateInitializerInOuter = isClassObjectWithBackingFieldsInOuter(descriptor); if (generateInitializerInOuter) { - ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this); + final ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this); //generate object$ parentCodegen.genInitSingleton(descriptor, StackValue.singleton(descriptor, typeMapper)); - generateInitializers(parentCodegen.createOrGetClInitCodegen(), myClass.getDeclarations(), bindingContext, state); + generateInitializers(myClass.getDeclarations(), new Function0() { + @Override + public ExpressionCodegen invoke() { + return parentCodegen.createOrGetClInitCodegen(); + } + }); } else { - generateInitializers(codegen, myClass.getDeclarations(), bindingContext, state); + generateInitializers(myClass.getDeclarations(), new Function0() { + @Override + public ExpressionCodegen invoke() { + return codegen; + } + }); } iv.visitInsn(RETURN); @@ -1658,131 +1668,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.astore(OBJECT_TYPE); } - public static void generateInitializers( - @NotNull ExpressionCodegen codegen, @NotNull List declarations, - @NotNull BindingContext bindingContext, @NotNull GenerationState state - ) { - JetTypeMapper typeMapper = state.getTypeMapper(); - for (JetDeclaration declaration : declarations) { - if (declaration instanceof JetProperty) { - if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) { - initializeProperty(codegen, bindingContext, (JetProperty) declaration); - } - } - else if (declaration instanceof JetClassInitializer) { - codegen.gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE); - } - } - } - - - public static void initializeProperty( - @NotNull ExpressionCodegen codegen, - @NotNull BindingContext bindingContext, - @NotNull JetProperty property - ) { - - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); - assert propertyDescriptor != null; - - JetExpression initializer = property.getDelegateExpressionOrInitializer(); - assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; - - JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor); - - StackValue.StackValueWithSimpleReceiver propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER); - - if (!propValue.isStatic) { - codegen.v.load(0, OBJECT_TYPE); - } - - Type type = codegen.expressionType(initializer); - if (jetType.isNullable()) { - type = boxType(type); - } - codegen.gen(initializer, type); - - propValue.store(type, codegen.v); - } - - public static boolean shouldWriteFieldInitializer(PropertyDescriptor descriptor, JetTypeMapper mapper) { - //final field of primitive or String type - if (!descriptor.isVar()) { - Type type = mapper.mapType(descriptor); - return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName()); - } - return false; - } - - public static boolean shouldInitializeProperty( - @NotNull JetProperty property, - @NotNull JetTypeMapper typeMapper - ) { - JetExpression initializer = property.getDelegateExpressionOrInitializer(); - if (initializer == null) return false; - - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property); - assert propertyDescriptor != null; - - CompileTimeConstant compileTimeValue = propertyDescriptor.getCompileTimeInitializer(); - if (compileTimeValue == null) return true; - - //TODO: OPTIMIZATION: don't initialize static final fields - - Object value = compileTimeValue.getValue(); - JetType jetType = getPropertyOrDelegateType(typeMapper.getBindingContext(), property, propertyDescriptor); - Type type = typeMapper.mapType(jetType); - return !skipDefaultValue(propertyDescriptor, value, type); - } - - @NotNull - private static JetType getPropertyOrDelegateType(@NotNull BindingContext bindingContext, @NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) { - JetExpression delegateExpression = property.getDelegateExpression(); - if (delegateExpression != null) { - JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression); - assert delegateType != null : "Type of delegate expression should be recorded"; - return delegateType; - } - return descriptor.getType(); - } - - private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) { - if (isPrimitive(type)) { - if (!propertyDescriptor.getType().isNullable() && value instanceof Number) { - if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) { - return true; - } - if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) { - return true; - } - if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) { - return true; - } - if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) { - return true; - } - if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) { - return true; - } - if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) { - return true; - } - } - if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) { - return true; - } - if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) { - return true; - } - } - else { - if (value == null) { - return true; - } - } - return false; - } - protected void generateDelegates(ClassDescriptor toClass, StackValue field) { for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { if (declaration instanceof CallableMemberDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index c2b43e89ad7..82b9b83de3d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.progress.ProcessCanceledException; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.context.ClassContext; @@ -30,18 +31,26 @@ import org.jetbrains.jet.lang.descriptors.annotations.Annotations; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.SpecialNames; import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.storage.LockBasedStorageManager; +import org.jetbrains.jet.storage.NotNullLazyValue; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; import java.util.Collections; +import java.util.List; +import static org.jetbrains.jet.codegen.AsmUtil.boxType; +import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC; -public class MemberCodegen extends ParentCodegenAwareImpl { +public abstract class MemberCodegen extends ParentCodegenAwareImpl { protected final FieldOwnerContext context; protected final ClassBuilder v; protected ExpressionCodegen clInit; @@ -168,4 +177,108 @@ public class MemberCodegen extends ParentCodegenAwareImpl { } return clInit; } + + protected void generateInitializers(@NotNull List declarations, @NotNull Function0 createCodegen) { + NotNullLazyValue codegen = LockBasedStorageManager.NO_LOCKS.createLazyValue(createCodegen); + for (JetDeclaration declaration : declarations) { + if (declaration instanceof JetProperty) { + if (shouldInitializeProperty((JetProperty) declaration)) { + initializeProperty(codegen.invoke(), (JetProperty) declaration); + } + } + else if (declaration instanceof JetClassInitializer) { + codegen.invoke().gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE); + } + } + } + + protected void initializeProperty(@NotNull ExpressionCodegen codegen, @NotNull JetProperty property) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); + assert propertyDescriptor != null; + + JetExpression initializer = property.getDelegateExpressionOrInitializer(); + assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; + + JetType jetType = getPropertyOrDelegateType(property, propertyDescriptor); + + StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER); + + if (!propValue.isStatic) { + codegen.v.load(0, OBJECT_TYPE); + } + + Type type = codegen.expressionType(initializer); + if (jetType.isNullable()) { + type = boxType(type); + } + codegen.gen(initializer, type); + + propValue.store(type, codegen.v); + } + + protected boolean shouldInitializeProperty(@NotNull JetProperty property) { + JetExpression initializer = property.getDelegateExpressionOrInitializer(); + if (initializer == null) return false; + + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); + assert propertyDescriptor != null; + + CompileTimeConstant compileTimeValue = propertyDescriptor.getCompileTimeInitializer(); + if (compileTimeValue == null) return true; + + //TODO: OPTIMIZATION: don't initialize static final fields + + Object value = compileTimeValue.getValue(); + JetType jetType = getPropertyOrDelegateType(property, propertyDescriptor); + Type type = typeMapper.mapType(jetType); + return !skipDefaultValue(propertyDescriptor, value, type); + } + + @NotNull + private JetType getPropertyOrDelegateType(@NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) { + JetExpression delegateExpression = property.getDelegateExpression(); + if (delegateExpression != null) { + JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression); + assert delegateType != null : "Type of delegate expression should be recorded"; + return delegateType; + } + return descriptor.getType(); + } + + private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) { + if (isPrimitive(type)) { + if (!propertyDescriptor.getType().isNullable() && value instanceof Number) { + if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) { + return true; + } + if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) { + return true; + } + if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) { + return true; + } + if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) { + return true; + } + if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) { + return true; + } + if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) { + return true; + } + } + if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) { + return true; + } + if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) { + return true; + } + } + else { + if (value == null) { + return true; + } + } + return false; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java index e0c3b2606d0..9efd357a491 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java @@ -16,8 +16,8 @@ package org.jetbrains.jet.codegen; -import com.google.common.collect.Lists; import com.intellij.util.ArrayUtil; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.codegen.context.FieldOwnerContext; import org.jetbrains.jet.codegen.state.GenerationState; @@ -58,36 +58,28 @@ public class PackagePartCodegen extends MemberCodegen { writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.PACKAGE_PART); - for (JetDeclaration declaration : jetFile.getDeclarations()) { + List declarations = jetFile.getDeclarations(); + + for (JetDeclaration declaration : declarations) { if (declaration instanceof JetNamedFunction || declaration instanceof JetProperty) { genFunctionOrProperty((JetTypeParameterListOwner) declaration, v); } } - generateStaticInitializers(); + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + generateInitializers(declarations, new Function0() { + @Override + public ExpressionCodegen invoke() { + return createOrGetClInitCodegen(); + } + }); + + if (clInit != null) { + clInit.v.visitInsn(RETURN); + FunctionCodegen.endVisit(clInit.v, "static initializer for package", jetFile); + } + } v.done(); } - - private void generateStaticInitializers() { - List properties = Lists.newArrayList(); - for (JetDeclaration declaration : jetFile.getDeclarations()) { - if (declaration instanceof JetProperty) { - JetProperty property = (JetProperty) declaration; - if (ImplementationBodyCodegen.shouldInitializeProperty(property, typeMapper)) { - properties.add(property); - } - } - } - if (properties.isEmpty()) return; - - ExpressionCodegen codegen = createOrGetClInitCodegen(); - - for (JetProperty property : properties) { - ImplementationBodyCodegen.initializeProperty(codegen, bindingContext, property); - } - - codegen.v.visitInsn(RETURN); - FunctionCodegen.endVisit(codegen.v, "static initializer for package", jetFile); - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index e04eb78c32e..175c2fc1118 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -247,7 +247,7 @@ public class PropertyCodegen extends GenerationStateAware { private FieldVisitor generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { Object value = null; - if (ImplementationBodyCodegen.shouldWriteFieldInitializer(propertyDescriptor, typeMapper)) { + if (shouldWriteFieldInitializer(propertyDescriptor)) { CompileTimeConstant initializer = propertyDescriptor.getCompileTimeInitializer(); if (initializer != null) { value = initializer.getValue(); @@ -257,6 +257,15 @@ public class PropertyCodegen extends GenerationStateAware { return generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value); } + private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) { + //final field of primitive or String type + if (!descriptor.isVar()) { + Type type = typeMapper.mapType(descriptor); + return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName()); + } + return false; + } + private void generateGetter(@Nullable JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable JetPropertyAccessor getter) { generateAccessor(p, getter, descriptor.getGetter() != null ? descriptor.getGetter() diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java index ad8d491625c..f09c343e73a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java @@ -16,11 +16,9 @@ package org.jetbrains.jet.codegen; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.org.objectweb.asm.MethodVisitor; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.FieldOwnerContext; import org.jetbrains.jet.codegen.context.MethodContext; @@ -34,13 +32,16 @@ import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetScript; import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.org.objectweb.asm.MethodVisitor; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.Collections; import java.util.List; -import static org.jetbrains.org.objectweb.asm.Opcodes.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; +import static org.jetbrains.org.objectweb.asm.Opcodes.*; // SCRIPT: script code generator public class ScriptCodegen extends MemberCodegen { @@ -113,7 +114,7 @@ public class ScriptCodegen extends MemberCodegen { @NotNull ScriptDescriptor scriptDescriptor, @NotNull ClassDescriptor classDescriptorForScript, @NotNull ClassBuilder classBuilder, - @NotNull MethodContext context + @NotNull final MethodContext context ) { Type blockType = typeMapper.mapType(scriptDescriptor.getScriptCodeDescriptor().getReturnType()); @@ -129,7 +130,7 @@ public class ScriptCodegen extends MemberCodegen { mv.visitCode(); - InstructionAdapter instructionAdapter = new InstructionAdapter(mv); + final InstructionAdapter instructionAdapter = new InstructionAdapter(mv); Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); assert classType != null; @@ -139,7 +140,7 @@ public class ScriptCodegen extends MemberCodegen { instructionAdapter.load(0, classType); - FrameMap frameMap = context.prepareFrame(typeMapper); + final FrameMap frameMap = context.prepareFrame(typeMapper); for (ScriptDescriptor importedScript : earlierScripts) { frameMap.enter(importedScript, OBJECT_TYPE); @@ -153,11 +154,12 @@ public class ScriptCodegen extends MemberCodegen { frameMap.enter(parameter, argTypes[i + add]); } - ImplementationBodyCodegen.generateInitializers( - new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state, this), - scriptDeclaration.getDeclarations(), - bindingContext, - state); + generateInitializers(scriptDeclaration.getDeclarations(), new Function0() { + @Override + public ExpressionCodegen invoke() { + return new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state, ScriptCodegen.this); + } + }); int offset = 1;