Skip to content

Commit 791c2ef

Browse files
authored
Test default interface stub generation (#4431)
1 parent 5dab9fb commit 791c2ef

File tree

2 files changed

+93
-4
lines changed

2 files changed

+93
-4
lines changed

vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeClass.java

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -977,9 +977,12 @@ public String generateCCode(List<ByteCodeClass> allClasses) {
977977
}
978978
}
979979
}
980-
if(baseClassObject != null) {
980+
if(!isInterface) {
981981
List<BytecodeMethod> bm = new ArrayList<BytecodeMethod>(methods);
982-
appendSuperStub(b, bm, baseClassObject);
982+
if(baseClassObject != null) {
983+
appendSuperStub(b, bm, baseClassObject);
984+
}
985+
appendDefaultInterfaceStubs(b, bm);
983986
}
984987
int offset = 0;
985988
if(clsName.equals("java_lang_Class")) {
@@ -1198,6 +1201,50 @@ private void appendSuperStub(StringBuilder b, List<BytecodeMethod> bm, ByteCodeC
11981201
}
11991202
BytecodeMethod.setAcceptStaticOnEquals(false);
12001203
}
1204+
1205+
private boolean hasMethodInBaseClass(BytecodeMethod method) {
1206+
if(baseClassObject == null) {
1207+
return false;
1208+
}
1209+
if(baseClassObject.methods.contains(method)) {
1210+
return true;
1211+
}
1212+
return baseClassObject.hasMethodInBaseClass(method);
1213+
}
1214+
1215+
private void appendDefaultInterfaceStubs(StringBuilder b, List<BytecodeMethod> bm) {
1216+
if(baseInterfacesObject == null) {
1217+
return;
1218+
}
1219+
BytecodeMethod.setAcceptStaticOnEquals(true);
1220+
for(ByteCodeClass baseInterface : baseInterfacesObject) {
1221+
appendDefaultInterfaceStubs(b, bm, baseInterface);
1222+
}
1223+
BytecodeMethod.setAcceptStaticOnEquals(false);
1224+
}
1225+
1226+
private void appendDefaultInterfaceStubs(StringBuilder b, List<BytecodeMethod> bm, ByteCodeClass baseInterface) {
1227+
if(baseInterface == null) {
1228+
return;
1229+
}
1230+
if(baseClassObject != null && baseClassObject.doesImplement(baseInterface)) {
1231+
return;
1232+
}
1233+
for(BytecodeMethod m : baseInterface.methods) {
1234+
if(m.isAbstract() || m.isStatic() || m.isPrivate()) {
1235+
continue;
1236+
}
1237+
if(!bm.contains(m) && !hasMethodInBaseClass(m)) {
1238+
m.appendSuperCall(b, clsName);
1239+
bm.add(m);
1240+
}
1241+
}
1242+
if(baseInterface.baseInterfacesObject != null) {
1243+
for(ByteCodeClass parentInterface : baseInterface.baseInterfacesObject) {
1244+
appendDefaultInterfaceStubs(b, bm, parentInterface);
1245+
}
1246+
}
1247+
}
12011248

12021249
private void appendSuperStubHeader(StringBuilder b, List<BytecodeMethod> bm, ByteCodeClass base) {
12031250
BytecodeMethod.setAcceptStaticOnEquals(true);
@@ -1213,6 +1260,40 @@ private void appendSuperStubHeader(StringBuilder b, List<BytecodeMethod> bm, Byt
12131260
}
12141261
BytecodeMethod.setAcceptStaticOnEquals(false);
12151262
}
1263+
1264+
private void appendDefaultInterfaceStubHeaders(StringBuilder b, List<BytecodeMethod> bm) {
1265+
if(baseInterfacesObject == null) {
1266+
return;
1267+
}
1268+
BytecodeMethod.setAcceptStaticOnEquals(true);
1269+
for(ByteCodeClass baseInterface : baseInterfacesObject) {
1270+
appendDefaultInterfaceStubHeaders(b, bm, baseInterface);
1271+
}
1272+
BytecodeMethod.setAcceptStaticOnEquals(false);
1273+
}
1274+
1275+
private void appendDefaultInterfaceStubHeaders(StringBuilder b, List<BytecodeMethod> bm, ByteCodeClass baseInterface) {
1276+
if(baseInterface == null) {
1277+
return;
1278+
}
1279+
if(baseClassObject != null && baseClassObject.doesImplement(baseInterface)) {
1280+
return;
1281+
}
1282+
for(BytecodeMethod m : baseInterface.methods) {
1283+
if(m.isAbstract() || m.isStatic() || m.isPrivate()) {
1284+
continue;
1285+
}
1286+
if(!bm.contains(m) && !hasMethodInBaseClass(m)) {
1287+
m.appendMethodHeader(b, clsName);
1288+
bm.add(m);
1289+
}
1290+
}
1291+
if(baseInterface.baseInterfacesObject != null) {
1292+
for(ByteCodeClass parentInterface : baseInterface.baseInterfacesObject) {
1293+
appendDefaultInterfaceStubHeaders(b, bm, parentInterface);
1294+
}
1295+
}
1296+
}
12161297

12171298
private void buildInstanceFieldList(List<ByteCodeField> fieldList) {
12181299
buildInstanceFieldList(fieldList, true);
@@ -1363,10 +1444,13 @@ public String generateCHeader() {
13631444

13641445
appendMethodsToHeader(b);
13651446

1366-
if(baseClassObject != null) {
1447+
if(!isInterface) {
13671448
// append super stub
13681449
List<BytecodeMethod> bm = new ArrayList<BytecodeMethod>(methods);
1369-
appendSuperStubHeader(b, bm, baseClassObject);
1450+
if(baseClassObject != null) {
1451+
appendSuperStubHeader(b, bm, baseClassObject);
1452+
}
1453+
appendDefaultInterfaceStubHeaders(b, bm);
13701454
}
13711455

13721456
for(BytecodeMethod m : virtualMethodList) {

vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ void translatesDefaultInterfaceMethodImplementations() throws Exception {
129129
String implCode = impl.generateCCode(classes);
130130
assertTrue(implCode.contains("&com_example_Greeter_greet___R_java_lang_String"),
131131
"Implementing class should point vtable slot to the interface default method implementation");
132+
assertTrue(implCode.contains("com_example_GreeterImpl_greet___R_java_lang_String"),
133+
"Implementing class should emit a concrete stub for default interface methods");
134+
String implHeader = impl.generateCHeader();
135+
assertTrue(implHeader.contains("com_example_GreeterImpl_greet___R_java_lang_String"),
136+
"Implementing class header should declare the default interface stub");
132137
}
133138

134139
@Test

0 commit comments

Comments
 (0)