Add Kotlin hack to avoid using regexp in

String.toFloatOrNull and String.toDoubleOrNull
This commit is contained in:
Alexey Andreev 2022-02-01 08:46:35 +03:00
parent e4a408d26e
commit 3728645665

View File

@ -22,50 +22,94 @@ import org.teavm.model.BasicBlock;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassHolderTransformerContext;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader;
import org.teavm.model.Program;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.util.ProgramUtils;
public class KotlinHacks implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
if (cls.getName().equals("kotlin.jvm.internal.Lambda")
|| cls.getName().equals("kotlin.coroutines.jvm.internal.BaseContinuationImpl")) {
List<MethodHolder> methodsToRemove = new ArrayList<>();
for (MethodHolder method : cls.getMethods()) {
if (method.getName().equals("toString")) {
methodsToRemove.add(method);
}
}
for (MethodHolder method : methodsToRemove) {
cls.removeMethod(method);
}
patchContinuation(cls);
} else if (cls.getName().equals("kotlin.jvm.internal.Reflection")) {
for (MethodHolder method : cls.getMethods()) {
if (method.getLevel() == AccessLevel.PUBLIC && method.hasModifier(ElementModifier.STATIC)
&& method.getName().equals("renderLambdaToString")
&& method.getResultType().isObject(String.class)) {
Program program = new Program();
patchReflection(cls);
} else if (cls.getName().equals("kotlin.text.StringsKt__StringNumberConversionsJVMKt")) {
patchStrings(cls, context.getHierarchy().getClassSource());
}
}
private void patchContinuation(ClassHolder cls) {
List<MethodHolder> methodsToRemove = new ArrayList<>();
for (MethodHolder method : cls.getMethods()) {
if (method.getName().equals("toString")) {
methodsToRemove.add(method);
}
}
for (MethodHolder method : methodsToRemove) {
cls.removeMethod(method);
}
}
private void patchReflection(ClassHolder cls) {
for (MethodHolder method : cls.getMethods()) {
if (method.getLevel() == AccessLevel.PUBLIC && method.hasModifier(ElementModifier.STATIC)
&& method.getName().equals("renderLambdaToString")
&& method.getResultType().isObject(String.class)) {
Program program = new Program();
program.createVariable();
for (int i = 0; i < method.parameterCount(); ++i) {
program.createVariable();
for (int i = 0; i < method.parameterCount(); ++i) {
program.createVariable();
}
BasicBlock block = program.createBasicBlock();
}
BasicBlock block = program.createBasicBlock();
StringConstantInstruction stringConstant = new StringConstantInstruction();
stringConstant.setReceiver(program.createVariable());
stringConstant.setConstant("lambda");
block.add(stringConstant);
StringConstantInstruction stringConstant = new StringConstantInstruction();
stringConstant.setReceiver(program.createVariable());
stringConstant.setConstant("lambda");
block.add(stringConstant);
ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(stringConstant.getReceiver());
block.add(exit);
ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(stringConstant.getReceiver());
block.add(exit);
method.setProgram(program);
method.setProgram(program);
}
}
}
private void patchStrings(ClassHolder cls, ClassReaderSource source) {
ClassReader templateClass = source.get(KotlinStrings.class.getName());
for (MethodHolder method : cls.getMethods()) {
if (method.getName().equals("toDoubleOrNull") || method.getName().equals("toFloatOrNull")) {
MethodReader templateMethod = templateClass.getMethod(method.getDescriptor());
if (templateMethod != null) {
method.setProgram(ProgramUtils.copy(templateMethod.getProgram()));
}
}
}
}
static class KotlinStrings {
static Float toFloatOrNull(String value) {
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
return null;
}
}
static Double toDoubleOrNull(String value) {
try {
return Double.parseDouble(value);
} catch (NumberFormatException e) {
return null;
}
}
}
}