From 4337537791a02b1a2471936d83d443300322647d Mon Sep 17 00:00:00 2001 From: Dominic Fox <40790090+distributedleetravis@users.noreply.github.com> Date: Wed, 29 Aug 2018 17:43:17 +0100 Subject: [PATCH] CORDA-1945: properly support double-width interp stack slots in superclasses when synthesising (#3859) * Fix for CORDA-1945 * Revert irrelevant style change --- .../internal/carpenter/ClassCarpenter.kt | 16 +++++++------- .../internal/carpenter/ClassCarpenterTest.kt | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt index 315ad35a50..f1a422f22e 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenter.kt @@ -130,8 +130,8 @@ class ClassCarpenterImpl @JvmOverloads constructor (override val whitelist: Clas */ override fun build(schema: Schema): Class<*> { validateSchema(schema) - // Walk up the inheritance hierarchy and then start walking back down once we either hit the top, or - // find a class we haven't generated yet. + // Walk up the inheritance hierarchy until we hit either the top or a class we've already generated, + // then walk back down it generating classes. val hierarchy = ArrayList() hierarchy += schema var cursor = schema.superclass @@ -306,16 +306,16 @@ class ClassCarpenterImpl @JvmOverloads constructor (override val whitelist: Clas visitInsn(DUP) var idx = 0 - schema.fields.forEach { + schema.fields.keys.forEach { key -> visitInsn(DUP) visitIntInsn(BIPUSH, idx) visitTypeInsn(NEW, schema.jvmName) visitInsn(DUP) - visitLdcInsn(it.key) + visitLdcInsn(key) visitIntInsn(BIPUSH, idx++) visitMethodInsn(INVOKESPECIAL, schema.jvmName, "", "(L$jlString;I)V", false) visitInsn(DUP) - visitFieldInsn(PUTSTATIC, schema.jvmName, it.key, "L${schema.jvmName};") + visitFieldInsn(PUTSTATIC, schema.jvmName, key, "L${schema.jvmName};") visitInsn(AASTORE) } @@ -381,20 +381,18 @@ class ClassCarpenterImpl @JvmOverloads constructor (override val whitelist: Clas visitCode() // Calculate the super call. - val superclassFields = schema.superclass?.fieldsIncludingSuperclasses() ?: emptyMap() visitVarInsn(ALOAD, 0) val sc = schema.superclass + var slot = 1 if (sc == null) { visitMethodInsn(INVOKESPECIAL, jlObject, "", "()V", false) } else { - var slot = 1 - superclassFields.values.forEach { slot += load(slot, it) } + slot = sc.fieldsIncludingSuperclasses().values.fold(slot) { acc, field -> acc + load(acc, field) } val superDesc = sc.descriptorsIncludingSuperclasses().values.joinToString("") visitMethodInsn(INVOKESPECIAL, sc.jvmName, "", "($superDesc)V", false) } // Assign the fields from parameters. - var slot = 1 + superclassFields.size for ((name, field) in schema.fields) { (field as ClassField).nullTest(this, slot) diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt index e74206e5b0..ac510642d7 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/carpenter/ClassCarpenterTest.kt @@ -129,6 +129,27 @@ class ClassCarpenterTest { assertEquals("B{a=xa, b=xb}", i.toString()) } + /** + * Tests the fix for [Corda-1945](https://r3-cev.atlassian.net/secure/RapidBoard.jspa?rapidView=83&modal=detail&selectedIssue=CORDA-1945) + */ + @Test + fun `superclasses with double-size primitive constructor parameters`() { + val schema1 = ClassSchema( + "gen.A", + mapOf("a" to NonNullableField(Long::class.javaPrimitiveType!!))) + + val schema2 = ClassSchema( + "gen.B", + mapOf("b" to NonNullableField(String::class.java)), + schema1) + + val clazz = cc.build(schema2) + val i = clazz.constructors[0].newInstance(1L, "xb") as SimpleFieldAccess + assertEquals(1L, i["a"]) + assertEquals("xb", i["b"]) + assertEquals("B{a=1, b=xb}", i.toString()) + } + @Test fun interfaces() { val schema1 = ClassSchema(