diff --git a/vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeClass.java b/vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeClass.java index 78fe7dbe1b..2bf19e8b6f 100644 --- a/vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeClass.java +++ b/vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeClass.java @@ -977,9 +977,12 @@ public String generateCCode(List allClasses) { } } } - if(baseClassObject != null) { + if(!isInterface) { List bm = new ArrayList(methods); - appendSuperStub(b, bm, baseClassObject); + if(baseClassObject != null) { + appendSuperStub(b, bm, baseClassObject); + } + appendDefaultInterfaceStubs(b, bm); } int offset = 0; if(clsName.equals("java_lang_Class")) { @@ -1198,6 +1201,50 @@ private void appendSuperStub(StringBuilder b, List bm, ByteCodeC } BytecodeMethod.setAcceptStaticOnEquals(false); } + + private boolean hasMethodInBaseClass(BytecodeMethod method) { + if(baseClassObject == null) { + return false; + } + if(baseClassObject.methods.contains(method)) { + return true; + } + return baseClassObject.hasMethodInBaseClass(method); + } + + private void appendDefaultInterfaceStubs(StringBuilder b, List bm) { + if(baseInterfacesObject == null) { + return; + } + BytecodeMethod.setAcceptStaticOnEquals(true); + for(ByteCodeClass baseInterface : baseInterfacesObject) { + appendDefaultInterfaceStubs(b, bm, baseInterface); + } + BytecodeMethod.setAcceptStaticOnEquals(false); + } + + private void appendDefaultInterfaceStubs(StringBuilder b, List bm, ByteCodeClass baseInterface) { + if(baseInterface == null) { + return; + } + if(baseClassObject != null && baseClassObject.doesImplement(baseInterface)) { + return; + } + for(BytecodeMethod m : baseInterface.methods) { + if(m.isAbstract() || m.isStatic() || m.isPrivate()) { + continue; + } + if(!bm.contains(m) && !hasMethodInBaseClass(m)) { + m.appendSuperCall(b, clsName); + bm.add(m); + } + } + if(baseInterface.baseInterfacesObject != null) { + for(ByteCodeClass parentInterface : baseInterface.baseInterfacesObject) { + appendDefaultInterfaceStubs(b, bm, parentInterface); + } + } + } private void appendSuperStubHeader(StringBuilder b, List bm, ByteCodeClass base) { BytecodeMethod.setAcceptStaticOnEquals(true); @@ -1213,6 +1260,40 @@ private void appendSuperStubHeader(StringBuilder b, List bm, Byt } BytecodeMethod.setAcceptStaticOnEquals(false); } + + private void appendDefaultInterfaceStubHeaders(StringBuilder b, List bm) { + if(baseInterfacesObject == null) { + return; + } + BytecodeMethod.setAcceptStaticOnEquals(true); + for(ByteCodeClass baseInterface : baseInterfacesObject) { + appendDefaultInterfaceStubHeaders(b, bm, baseInterface); + } + BytecodeMethod.setAcceptStaticOnEquals(false); + } + + private void appendDefaultInterfaceStubHeaders(StringBuilder b, List bm, ByteCodeClass baseInterface) { + if(baseInterface == null) { + return; + } + if(baseClassObject != null && baseClassObject.doesImplement(baseInterface)) { + return; + } + for(BytecodeMethod m : baseInterface.methods) { + if(m.isAbstract() || m.isStatic() || m.isPrivate()) { + continue; + } + if(!bm.contains(m) && !hasMethodInBaseClass(m)) { + m.appendMethodHeader(b, clsName); + bm.add(m); + } + } + if(baseInterface.baseInterfacesObject != null) { + for(ByteCodeClass parentInterface : baseInterface.baseInterfacesObject) { + appendDefaultInterfaceStubHeaders(b, bm, parentInterface); + } + } + } private void buildInstanceFieldList(List fieldList) { buildInstanceFieldList(fieldList, true); @@ -1363,10 +1444,13 @@ public String generateCHeader() { appendMethodsToHeader(b); - if(baseClassObject != null) { + if(!isInterface) { // append super stub List bm = new ArrayList(methods); - appendSuperStubHeader(b, bm, baseClassObject); + if(baseClassObject != null) { + appendSuperStubHeader(b, bm, baseClassObject); + } + appendDefaultInterfaceStubHeaders(b, bm); } for(BytecodeMethod m : virtualMethodList) { diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java index a0845f3c87..173661f2ab 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java @@ -129,6 +129,11 @@ void translatesDefaultInterfaceMethodImplementations() throws Exception { String implCode = impl.generateCCode(classes); assertTrue(implCode.contains("&com_example_Greeter_greet___R_java_lang_String"), "Implementing class should point vtable slot to the interface default method implementation"); + assertTrue(implCode.contains("com_example_GreeterImpl_greet___R_java_lang_String"), + "Implementing class should emit a concrete stub for default interface methods"); + String implHeader = impl.generateCHeader(); + assertTrue(implHeader.contains("com_example_GreeterImpl_greet___R_java_lang_String"), + "Implementing class header should declare the default interface stub"); } @Test