Skip to content

Commit a3628a5

Browse files
Optimize BytecodeTranslator for barebone C methods (#4359)
Fixed #3380 * Optimize BytecodeTranslator for barebone C methods - Implemented `checkBarebone` to identify simple methods (no sync, native, exceptions, allocations). - Modified `BytecodeMethod` to skip `DEFINE_METHOD_STACK` and other VM overhead for barebone methods. - Updated variable generation to use `olocals_`/`ilocals_` directly. - Updated `BasicInstruction` to use direct C `return` instead of `releaseForReturn` macros. - Added safety check to prevent optimization if internal locals exist but debug info is missing. * Fix C compilation errors in barebone method optimization - Replaced usages of `locals[X]` with `olocals_X_` (and primitive equivalents) in code generated by `optimize()` for barebone methods via `fixUpBarebone`. - Updated `VarOp.java` to support primitive types (`ILOAD`, `ISTORE`, etc.) using direct C variables in barebone mode. - Exposed necessary fields in `CustomJump`, `CustomInstruction`, and `CustomInvoke` to facilitate post-optimization fixups. * Fix C compilation errors in barebone optimization for primitive types and 'this' access - Updated `VarOp.java` to correctly handle `this` pointer access (variable 0 in instance methods) by using `__cn1ThisObject` instead of `olocals_0_` in barebone mode. - Fixed `VarOp.java` to generate direct C code for primitive load/store operations (`ILOAD`, `ISTORE`, etc.) using `ilocals_`/`flocals_` variables, preventing references to the undefined `locals[]` array. - Updated `BytecodeMethod.java` to run a `fixUpBarebone` pass that rewrites `locals[...]` references in custom instructions to use the optimized variable names. - Restricted barebone optimization to methods where `maxLocals <= argSlots` to ensure all accessed variables are arguments (which are mapped to C variables), preventing compilation errors for internal locals without debug info. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 269e17b commit a3628a5

File tree

7 files changed

+384
-37
lines changed

7 files changed

+384
-37
lines changed

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

Lines changed: 229 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public static void setDependencyGraph(MethodDependencyGraph dependencyGraph) {
106106
private final static Set<String> virtualMethodsInvoked = new TreeSet<String>();
107107
private String desc;
108108
private boolean eliminated;
109+
private boolean barebone;
109110

110111

111112
static boolean optimizerOn;
@@ -115,6 +116,150 @@ public static void setDependencyGraph(MethodDependencyGraph dependencyGraph) {
115116
optimizerOn = op == null || op.equalsIgnoreCase("on");
116117
//optimizerOn = false;
117118
}
119+
120+
public boolean isBarebone() {
121+
return barebone;
122+
}
123+
124+
private boolean checkBarebone() {
125+
if(synchronizedMethod || nativeMethod || hasExceptionHandlingOrMethodCalls() || localVariables.size() > 0) {
126+
return false;
127+
}
128+
int argSlots = 0;
129+
if(!staticMethod) {
130+
argSlots++;
131+
}
132+
for(ByteCodeMethodArg arg : arguments) {
133+
argSlots++;
134+
if(arg.isDoubleOrLong()) {
135+
argSlots++;
136+
}
137+
}
138+
if(maxLocals > argSlots) {
139+
return false;
140+
}
141+
for(Instruction i : instructions) {
142+
if(i instanceof LabelInstruction || i instanceof LineNumber || i instanceof IInc ||
143+
i instanceof Jump || i instanceof CustomJump || i instanceof LocalVariable) {
144+
continue;
145+
}
146+
if(i instanceof BasicInstruction) {
147+
int op = i.getOpcode();
148+
switch(op) {
149+
case Opcodes.SIPUSH:
150+
case Opcodes.BIPUSH:
151+
case Opcodes.ICONST_0:
152+
case Opcodes.ICONST_1:
153+
case Opcodes.ICONST_2:
154+
case Opcodes.ICONST_3:
155+
case Opcodes.ICONST_4:
156+
case Opcodes.ICONST_5:
157+
case Opcodes.ICONST_M1:
158+
case Opcodes.LCONST_0:
159+
case Opcodes.LCONST_1:
160+
case Opcodes.FCONST_0:
161+
case Opcodes.FCONST_1:
162+
case Opcodes.FCONST_2:
163+
case Opcodes.DCONST_0:
164+
case Opcodes.DCONST_1:
165+
case Opcodes.RETURN:
166+
case Opcodes.IRETURN:
167+
case Opcodes.LRETURN:
168+
case Opcodes.FRETURN:
169+
case Opcodes.DRETURN:
170+
case Opcodes.ARETURN:
171+
case Opcodes.NOP:
172+
case Opcodes.POP:
173+
case Opcodes.POP2:
174+
case Opcodes.DUP:
175+
case Opcodes.DUP2:
176+
case Opcodes.DUP_X1:
177+
case Opcodes.DUP2_X1:
178+
case Opcodes.DUP_X2:
179+
case Opcodes.DUP2_X2:
180+
case Opcodes.SWAP:
181+
case Opcodes.IADD:
182+
case Opcodes.LADD:
183+
case Opcodes.FADD:
184+
case Opcodes.DADD:
185+
case Opcodes.ISUB:
186+
case Opcodes.LSUB:
187+
case Opcodes.FSUB:
188+
case Opcodes.DSUB:
189+
case Opcodes.IMUL:
190+
case Opcodes.LMUL:
191+
case Opcodes.FMUL:
192+
case Opcodes.DMUL:
193+
case Opcodes.IDIV:
194+
case Opcodes.LDIV:
195+
case Opcodes.FDIV:
196+
case Opcodes.DDIV:
197+
case Opcodes.IREM:
198+
case Opcodes.LREM:
199+
case Opcodes.FREM:
200+
case Opcodes.DREM:
201+
case Opcodes.INEG:
202+
case Opcodes.LNEG:
203+
case Opcodes.FNEG:
204+
case Opcodes.DNEG:
205+
case Opcodes.ISHL:
206+
case Opcodes.LSHL:
207+
case Opcodes.ISHR:
208+
case Opcodes.LSHR:
209+
case Opcodes.IUSHR:
210+
case Opcodes.LUSHR:
211+
case Opcodes.IAND:
212+
case Opcodes.LAND:
213+
case Opcodes.IOR:
214+
case Opcodes.LOR:
215+
case Opcodes.IXOR:
216+
case Opcodes.LXOR:
217+
case Opcodes.I2L:
218+
case Opcodes.I2F:
219+
case Opcodes.I2D:
220+
case Opcodes.L2I:
221+
case Opcodes.L2F:
222+
case Opcodes.L2D:
223+
case Opcodes.F2I:
224+
case Opcodes.F2L:
225+
case Opcodes.F2D:
226+
case Opcodes.D2I:
227+
case Opcodes.D2L:
228+
case Opcodes.D2F:
229+
case Opcodes.I2B:
230+
case Opcodes.I2C:
231+
case Opcodes.I2S:
232+
case Opcodes.LCMP:
233+
case Opcodes.FCMPG:
234+
case Opcodes.FCMPL:
235+
case Opcodes.DCMPL:
236+
case Opcodes.DCMPG:
237+
continue;
238+
}
239+
return false;
240+
}
241+
if(i instanceof VarOp) {
242+
continue;
243+
}
244+
if(i instanceof ArithmeticExpression) {
245+
continue;
246+
}
247+
if(i instanceof Field) {
248+
int op = i.getOpcode();
249+
if(op == Opcodes.GETFIELD) {
250+
continue;
251+
}
252+
if(op == Opcodes.PUTFIELD) {
253+
if(((Field)i).isObject()) {
254+
return false;
255+
}
256+
continue;
257+
}
258+
}
259+
return false;
260+
}
261+
return true;
262+
}
118263

119264
public BytecodeMethod(String clsName, int access, String name, String desc, String signature, String[] exceptions) {
120265
methodName = name;
@@ -603,6 +748,42 @@ private boolean hasLocalVariableWithIndex(char qualifier, int index) {
603748
return false;
604749
}
605750

751+
private void fixUpBarebone() {
752+
for (Instruction i : instructions) {
753+
if (i instanceof CustomJump) {
754+
CustomJump cj = (CustomJump)i;
755+
String cmp = cj.getCustomCompareCode();
756+
if (cmp != null) {
757+
cj.setCustomCompareCode(cmp.replaceAll("locals\\[(\\d+)\\]\\.data\\.o", "olocals_$1_"));
758+
}
759+
} else if (i instanceof CustomIntruction) {
760+
CustomIntruction ci = (CustomIntruction)i;
761+
String code = ci.getCode();
762+
if (code != null) {
763+
ci.setCode(code.replaceAll("locals\\[(\\d+)\\]\\.data\\.o", "olocals_$1_"));
764+
}
765+
String complexCode = ci.getComplexCode();
766+
if (complexCode != null) {
767+
ci.setComplexCode(complexCode.replaceAll("locals\\[(\\d+)\\]\\.data\\.o", "olocals_$1_"));
768+
}
769+
} else if (i instanceof CustomInvoke) {
770+
CustomInvoke ci = (CustomInvoke)i;
771+
String target = ci.getTargetObjectLiteral();
772+
if (target != null) {
773+
ci.setTargetObjectLiteral(target.replaceAll("locals\\[(\\d+)\\]\\.data\\.o", "olocals_$1_"));
774+
}
775+
String[] args = ci.getLiteralArgs();
776+
if (args != null) {
777+
for (int j=0; j<args.length; j++) {
778+
if (args[j] != null) {
779+
ci.setLiteralArg(j, args[j].replaceAll("locals\\[(\\d+)\\]\\.data\\.o", "olocals_$1_"));
780+
}
781+
}
782+
}
783+
}
784+
}
785+
}
786+
606787
public void appendMethodC(StringBuilder b) {
607788
if(nativeMethod) {
608789
return;
@@ -626,10 +807,14 @@ public void appendMethodC(StringBuilder b) {
626807
}
627808

628809
if(hasInstructions) {
810+
barebone = checkBarebone();
811+
if (barebone) {
812+
fixUpBarebone();
813+
}
629814
Set<String> added = new HashSet<String>();
630815
for (LocalVariable lv : localVariables) {
631816
String variableName = lv.getQualifier() + "locals_"+lv.getIndex()+"_";
632-
if (!added.contains(variableName) && lv.getQualifier() != 'o') {
817+
if (!added.contains(variableName) && (barebone || lv.getQualifier() != 'o')) {
633818
added.add(variableName);
634819
b.append(" volatile ");
635820
switch (lv.getQualifier()) {
@@ -641,30 +826,36 @@ public void appendMethodC(StringBuilder b) {
641826
b.append("JAVA_FLOAT"); break;
642827
case 'd' :
643828
b.append("JAVA_DOUBLE"); break;
829+
case 'o' :
830+
b.append("JAVA_OBJECT"); break;
644831
}
645832
b.append(" ").append(lv.getQualifier()).append("locals_").append(lv.getIndex()).append("_ = 0; /* ").append(lv.getOrigName()).append(" */\n");
646833
}
647834
}
648835

649-
if(staticMethod) {
650-
if(methodName.equals("__CLINIT__")) {
651-
b.append(" DEFINE_METHOD_STACK(");
836+
if(!barebone) {
837+
if(staticMethod) {
838+
if(methodName.equals("__CLINIT__")) {
839+
b.append(" DEFINE_METHOD_STACK(");
840+
} else {
841+
b.append(" __STATIC_INITIALIZER_");
842+
b.append(clsName.replace('/', '_').replace('$', '_'));
843+
b.append("(threadStateData);\n DEFINE_METHOD_STACK(");
844+
}
652845
} else {
653-
b.append(" __STATIC_INITIALIZER_");
654-
b.append(clsName.replace('/', '_').replace('$', '_'));
655-
b.append("(threadStateData);\n DEFINE_METHOD_STACK(");
846+
b.append(" DEFINE_INSTANCE_METHOD_STACK(");
656847
}
848+
b.append(maxStack);
849+
b.append(", ");
850+
b.append(maxLocals);
851+
b.append(", 0, ");
852+
b.append(Parser.addToConstantPool(clsName));
853+
b.append(", ");
854+
b.append(Parser.addToConstantPool(methodName));
855+
b.append(");\n");
657856
} else {
658-
b.append(" DEFINE_INSTANCE_METHOD_STACK(");
857+
b.append(" struct elementStruct* SP = &threadStateData->threadObjectStack[threadStateData->threadObjectStackOffset];\n");
659858
}
660-
b.append(maxStack);
661-
b.append(", ");
662-
b.append(maxLocals);
663-
b.append(", 0, ");
664-
b.append(Parser.addToConstantPool(clsName));
665-
b.append(", ");
666-
b.append(Parser.addToConstantPool(methodName));
667-
b.append(");\n");
668859
int startOffset = 0;
669860
if(synchronizedMethod) {
670861
if(staticMethod) {
@@ -676,25 +867,34 @@ public void appendMethodC(StringBuilder b) {
676867
}
677868
}
678869
if(!staticMethod) {
679-
b.append(" locals[0].data.o = __cn1ThisObject; locals[0].type = CN1_TYPE_OBJECT; ");
870+
if(!barebone) {
871+
b.append(" locals[0].data.o = __cn1ThisObject; locals[0].type = CN1_TYPE_OBJECT; ");
872+
}
680873
startOffset++;
681874
}
682875
int localsOffset = startOffset;
683876
for(int iter = 0 ; iter < arguments.size() ; iter++) {
684877
ByteCodeMethodArg arg = arguments.get(iter);
685878
if (arg.getQualifier() == 'o') {
686-
b.append(" locals[");
687-
b.append(localsOffset);
688-
b.append("].data.");
879+
if(barebone) {
880+
b.append(" JAVA_OBJECT olocals_");
881+
b.append(localsOffset);
882+
b.append("_ = __cn1Arg");
883+
b.append(iter + 1);
884+
b.append(";\n");
885+
} else {
886+
b.append(" locals[");
887+
b.append(localsOffset);
888+
b.append("].data.");
689889

690-
b.append(arg.getQualifier());
691-
b.append(" = __cn1Arg");
692-
b.append(iter + 1);
693-
b.append(";\n");
694-
b.append(" locals[");
695-
b.append(localsOffset);
696-
b.append("].type = CN1_TYPE_OBJECT;\n");
697-
890+
b.append(arg.getQualifier());
891+
b.append(" = __cn1Arg");
892+
b.append(iter + 1);
893+
b.append(";\n");
894+
b.append(" locals[");
895+
b.append(localsOffset);
896+
b.append("].type = CN1_TYPE_OBJECT;\n");
897+
}
698898
} else {
699899
b.append(" ");
700900
if (!hasLocalVariableWithIndex(arg.getQualifier(), localsOffset)) {
@@ -739,6 +939,7 @@ public void appendMethodC(StringBuilder b) {
739939
TryCatch.reset();
740940
BasicInstruction.setHasInstructions(hasInstructions);
741941
for(Instruction i : instructions) {
942+
i.setMethod(this);
742943
i.setMaxes(maxStack, maxLocals);
743944
i.appendInstruction(b, instructions);
744945
}

0 commit comments

Comments
 (0)