Unify properties initialization for init and clinit

This commit is contained in:
Natalia.Ukhorskaya
2013-04-17 14:49:53 +04:00
parent 57b161b08a
commit f2b3be7416
6 changed files with 134 additions and 51 deletions
@@ -1600,30 +1600,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
JetTypeMapper typeMapper = state.getTypeMapper();
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetProperty) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, declaration);
assert propertyDescriptor != null;
if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) {
JetExpression initializer = ((JetProperty) declaration).getInitializer();
if (initializer != null) {
CompileTimeConstant<?> compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer);
JetType jetType = propertyDescriptor.getType();
if (compileTimeValue != null) {
Object value = compileTimeValue.getValue();
Type type = typeMapper.mapType(jetType);
if (skipDefaultValue(propertyDescriptor, value, type)) continue;
}
iv.load(0, OBJECT_TYPE);
Type type = codegen.expressionType(initializer);
if (jetType.isNullable()) {
type = boxType(type);
}
codegen.gen(initializer, type);
// @todo write directly to the field. Fix test excloset.jet::test6
JvmClassName owner = typeMapper.getOwner(propertyDescriptor, OwnerKind.IMPLEMENTATION, isCallInsideSameModuleAsDeclared(propertyDescriptor, codegen.context));
Type propType = typeMapper.mapType(jetType);
StackValue.property(propertyDescriptor, owner,
propType, false, null, null, state).store(propType, iv);
}
if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
initializeProperty(codegen, bindingContext, iv, (JetProperty) declaration, false);
}
}
else if (declaration instanceof JetClassInitializer) {
@@ -1632,6 +1610,52 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
public static void initializeProperty(
@NotNull ExpressionCodegen codegen,
@NotNull BindingContext bindingContext,
@NotNull InstructionAdapter iv,
@NotNull JetProperty property,
boolean isStatic
) {
if (!isStatic) {
iv.load(0, OBJECT_TYPE);
}
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
assert propertyDescriptor != null;
JetExpression initializer = property.getInitializer();
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
JetType jetType = propertyDescriptor.getType();
Type type = codegen.expressionType(initializer);
if (jetType.isNullable()) {
type = boxType(type);
}
codegen.gen(initializer, type);
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null);
propValue.store(propValue.type, iv);
}
public static boolean shouldInitializeProperty(
@NotNull JetProperty property,
@NotNull JetTypeMapper typeMapper
) {
JetExpression initializer = property.getInitializer();
if (initializer == null) return false;
CompileTimeConstant<?> compileTimeValue = typeMapper.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
if (compileTimeValue == null) return true;
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property);
assert propertyDescriptor != null;
Object value = compileTimeValue.getValue();
Type type = typeMapper.mapType(propertyDescriptor.getType());
return !skipDefaultValue(propertyDescriptor, value, type);
}
private static boolean skipDefaultValue(PropertyDescriptor propertyDescriptor, Object value, Type type) {
if (isPrimitive(type)) {
if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen;
import com.google.common.collect.Lists;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.io.FileUtil;
@@ -26,7 +27,6 @@ import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
@@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import java.io.File;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.asm4.Opcodes.*;
@@ -160,9 +161,7 @@ public class NamespaceCodegen extends MemberCodegen {
}
}
if (hasNonConstantPropertyInitializers()) {
generateStaticInitializers(builder, file);
}
generateStaticInitializers(builder, file);
builder.done();
}
@@ -207,6 +206,9 @@ public class NamespaceCodegen extends MemberCodegen {
}
private void generateStaticInitializers(@NotNull ClassBuilder builder, @NotNull JetFile file) {
List<JetProperty> properties = collectPropertiesToInitialize(file);
if (properties.isEmpty()) return;
MethodVisitor mv = builder.newMethod(file, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
@@ -214,18 +216,9 @@ public class NamespaceCodegen extends MemberCodegen {
FrameMap frameMap = new FrameMap();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state);
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) {
JetExpression initializer = ((JetProperty) declaration).getInitializer();
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
PropertyDescriptor descriptor =
(PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
assert descriptor != null;
codegen.genToJVMStack(initializer);
StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null);
propValue.store(propValue.type, new InstructionAdapter(mv));
}
}
for (JetDeclaration declaration : properties) {
ImplementationBodyCodegen.
initializeProperty(codegen, state.getBindingContext(), new InstructionAdapter(mv), (JetProperty) declaration, true);
}
mv.visitInsn(RETURN);
@@ -234,18 +227,16 @@ public class NamespaceCodegen extends MemberCodegen {
}
}
private boolean hasNonConstantPropertyInitializers() {
for (JetFile file : files) {
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) {
JetExpression initializer = ((JetProperty) declaration).getInitializer();
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
return true;
}
}
@NotNull
private List<JetProperty> collectPropertiesToInitialize(@NotNull JetFile file) {
List<JetProperty> result = Lists.newArrayList();
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty &&
ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
result.add((JetProperty) declaration);
}
}
return false;
return result;
}
public void done() {
@@ -97,7 +97,7 @@ public class PropertyCodegen extends GenerationStateAware {
Object value = null;
JetExpression initializer = p instanceof JetProperty ? ((JetProperty) p).getInitializer() : null;
if (initializer != null) {
if (initializer instanceof JetConstantExpression) {
if (initializer instanceof JetConstantExpression && !propertyDescriptor.getType().isNullable()) {
CompileTimeConstant<?> compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer);
value = compileTimeValue != null ? compileTimeValue.getValue() : null;
}