CORDA-1945: properly support double-width interp stack slots in superclasses when synthesising (#3859)

* Fix for CORDA-1945

* Revert irrelevant style change
This commit is contained in:
Dominic Fox 2018-08-29 17:43:17 +01:00 committed by GitHub
parent 60d28b412f
commit 4337537791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 9 deletions

View File

@ -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<Schema>()
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, "<init>", "(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, "<init>", "()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, "<init>", "($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)

View File

@ -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(