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;
}
@@ -0,0 +1,31 @@
class A {
class object {
var xi = 0
var xin : Int? = 0
var xinn : Int? = null
var xl = 0.toLong()
var xln : Long? = 0.toLong()
var xlnn : Long? = null
var xb = 0.toByte()
var xbn : Byte? = 0.toByte()
var xbnn : Byte? = null
var xf = 0.toFloat()
var xfn : Float? = 0.toFloat()
var xfnn : Float? = null
var xd = 0.toDouble()
var xdn : Double? = 0.toDouble()
var xdnn : Double? = null
var xs = 0.toShort()
var xsn : Short? = 0.toShort()
var xsnn : Short? = null
}
}
fun box() : String {
return "OK"
}
@@ -0,0 +1,27 @@
var xi = 0
var xin : Int? = 0
var xinn : Int? = null
var xl = 0.toLong()
var xln : Long? = 0.toLong()
var xlnn : Long? = null
var xb = 0.toByte()
var xbn : Byte? = 0.toByte()
var xbnn : Byte? = null
var xf = 0.toFloat()
var xfn : Float? = 0.toFloat()
var xfnn : Float? = null
var xd = 0.toDouble()
var xdn : Double? = 0.toDouble()
var xdnn : Double? = null
var xs = 0.toShort()
var xsn : Short? = 0.toShort()
var xsnn : Short? = null
fun box() : String {
return "OK"
}
@@ -457,6 +457,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/classes"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("boxPrimitiveTypeInClinitOfClassObject.kt")
public void testBoxPrimitiveTypeInClinitOfClassObject() throws Exception {
doTest("compiler/testData/codegen/box/classes/boxPrimitiveTypeInClinitOfClassObject.kt");
}
@TestMetadata("classObject.kt")
public void testClassObject() throws Exception {
doTest("compiler/testData/codegen/box/classes/classObject.kt");
@@ -2621,6 +2626,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/namespace"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("boxPrimitiveTypeInClinit.kt")
public void testBoxPrimitiveTypeInClinit() throws Exception {
doTest("compiler/testData/codegen/box/namespace/boxPrimitiveTypeInClinit.kt");
}
@TestMetadata("checkCast.kt")
public void testCheckCast() throws Exception {
doTest("compiler/testData/codegen/box/namespace/checkCast.kt");