Improve slf4j substitution

This commit is contained in:
konsoletyper 2015-03-24 21:16:59 +03:00
parent f5d09be35e
commit 457bd16b11
2 changed files with 65 additions and 66 deletions

View File

@ -15,12 +15,10 @@
*/
package org.teavm.extras.slf4j;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.SubstituteLoggerFactory;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.ModelUtils;
/**
*
@ -32,71 +30,22 @@ public class LoggerFactoryTransformer implements ClassHolderTransformer {
if (!cls.getName().equals(LoggerFactory.class.getName())) {
return;
}
addCacheField(cls);
modifyClinit(cls);
replaceGetFactory(cls);
cls.removeField(cls.getField("TEMP_FACTORY"));
substitute(cls, innerSource);
}
private void addCacheField(ClassHolder cls) {
FieldHolder cacheField = new FieldHolder("loggerFactoryCache");
cacheField.setLevel(AccessLevel.PRIVATE);
cacheField.getModifiers().add(ElementModifier.STATIC);
cacheField.setType(ValueType.object(TeaVMLoggerFactory.class.getName()));
cls.addField(cacheField);
private void substitute(ClassHolder cls, ClassReaderSource classSource) {
ClassReader subst = classSource.get(TeaVMLoggerFactorySubstitution.class.getName());
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
cls.removeField(field);
}
private void modifyClinit(ClassHolder cls) {
MethodHolder clinit = cls.getMethod(new MethodDescriptor("<clinit>", void.class));
BasicBlock clinitBlock = clinit.getProgram().basicBlockAt(0);
Variable factoryVar = clinit.getProgram().createVariable();
ConstructInstruction construct = new ConstructInstruction();
construct.setType(TeaVMLoggerFactory.class.getName());
construct.setReceiver(factoryVar);
clinitBlock.getInstructions().add(0, construct);
InvokeInstruction init = new InvokeInstruction();
init.setInstance(factoryVar);
init.setMethod(new MethodReference(TeaVMLoggerFactory.class, "<init>", void.class));
init.setType(InvocationType.SPECIAL);
clinitBlock.getInstructions().add(1, init);
PutFieldInstruction put = new PutFieldInstruction();
put.setValue(factoryVar);
put.setField(new FieldReference(LoggerFactory.class.getName(), "loggerFactoryCache"));
clinitBlock.getInstructions().add(2, put);
Program program = clinit.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
Instruction insn = block.getInstructions().get(j);
if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction)insn;
if (invoke.getMethod().getClassName().equals(SubstituteLoggerFactory.class.getName())) {
block.getInstructions().set(j, new EmptyInstruction());
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
cls.removeMethod(method);
}
} else if (insn instanceof PutFieldInstruction) {
PutFieldInstruction putField = (PutFieldInstruction)insn;
if (putField.getField().getFieldName().equals("TEMP_FACTORY")) {
block.getInstructions().set(j, new EmptyInstruction());
for (FieldReader field : subst.getFields()) {
cls.addField(ModelUtils.copyField(field));
}
for (MethodReader method : subst.getMethods()) {
cls.addMethod(ModelUtils.copyMethod(method));
}
}
}
}
private void replaceGetFactory(ClassHolder cls) {
MethodHolder method = cls.getMethod(new MethodDescriptor("getILoggerFactory", ILoggerFactory.class));
Program program = new Program();
BasicBlock block = program.createBasicBlock();
Variable cacheVar = program.createVariable();
GetFieldInstruction get = new GetFieldInstruction();
get.setField(new FieldReference(LoggerFactory.class.getName(), "loggerFactoryCache"));
get.setFieldType(ValueType.object(ILoggerFactory.class.getName()));
get.setReceiver(cacheVar);
block.getInstructions().add(get);
ExitInstruction exit = new ExitInstruction();
exit.setValueToReturn(cacheVar);
block.getInstructions().add(exit);
method.setProgram(program);
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.extras.slf4j;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
/**
*
* @author Alexey Andreev
*/
public final class TeaVMLoggerFactorySubstitution {
private static Map<String, TeaVMLogger> loggers = new HashMap<>();
private static TeaVMLoggerFactory loggerFactory = new TeaVMLoggerFactory();
private TeaVMLoggerFactorySubstitution() {
}
public static Logger getLogger(String name) {
TeaVMLogger logger = loggers.get(name);
if (logger == null) {
logger = new TeaVMLogger(name);
loggers.put(name, logger);
}
return logger;
}
public static Logger getLogger(Class<?> clazz) {
return getLogger(clazz.getName());
}
public static ILoggerFactory getILoggerFactory() {
return loggerFactory;
}
}