Begin to implement variable mapping

This commit is contained in:
konsoletyper 2014-08-04 23:22:41 +04:00
parent dbb807efed
commit bc911a661a
44 changed files with 715 additions and 113 deletions

View File

@ -1,16 +1,16 @@
package org.teavm.chromerdp; package org.teavm.chromerdp;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Exchanger;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.teavm.chromerdp.data.CallFrameDTO; import org.teavm.chromerdp.data.*;
import org.teavm.chromerdp.data.LocationDTO;
import org.teavm.chromerdp.data.Message;
import org.teavm.chromerdp.data.Response;
import org.teavm.chromerdp.messages.*; import org.teavm.chromerdp.messages.*;
import org.teavm.debugging.*; import org.teavm.debugging.*;
@ -266,6 +266,37 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
sendMessage(message); sendMessage(message);
} }
List<RDPLocalVariable> getScope(String scopeId) {
if (exchange == null) {
return Collections.emptyList();
}
Message message = new Message();
message.setId(messageIdGenerator.incrementAndGet());
message.setMethod("Runtime.getProperties");
GetPropertiesCommand params = new GetPropertiesCommand();
params.setObjectId(scopeId);
params.setOwnProperties(true);
message.setParams(mapper.valueToTree(params));
final Exchanger<List<RDPLocalVariable>> exchanger = new Exchanger<>();
responseHandlers.put(message.getId(), new ResponseHandler() {
@Override public void received(JsonNode node) throws IOException {
GetPropertiesResponse response = mapper.reader(GetPropertiesResponse.class).readValue(node);
// TODO: parse response
try {
exchanger.exchange(new ArrayList<RDPLocalVariable>());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
sendMessage(message);
try {
return exchanger.exchange(null);
} catch (InterruptedException e) {
return Collections.emptyList();
}
}
private <T> T parseJson(Class<T> type, JsonNode node) throws IOException { private <T> T parseJson(Class<T> type, JsonNode node) throws IOException {
return mapper.reader(type).readValue(node); return mapper.reader(type).readValue(node);
} }
@ -282,7 +313,14 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
} }
RDPCallFrame map(CallFrameDTO dto) { RDPCallFrame map(CallFrameDTO dto) {
return new RDPCallFrame(dto.getCallFrameId(), map(dto.getLocation())); String scopeId = null;
for (ScopeDTO scope : dto.getScopeChain()) {
if (scope.getType().equals("local")) {
scopeId = scope.getObject();
break;
}
}
return new RDPCallFrame(dto.getCallFrameId(), map(dto.getLocation()), new RDPScope(this, scopeId));
} }
JavaScriptLocation map(LocationDTO dto) { JavaScriptLocation map(LocationDTO dto) {

View File

@ -15,8 +15,11 @@
*/ */
package org.teavm.chromerdp; package org.teavm.chromerdp;
import java.util.Collections;
import java.util.Map;
import org.teavm.debugging.JavaScriptCallFrame; import org.teavm.debugging.JavaScriptCallFrame;
import org.teavm.debugging.JavaScriptLocation; import org.teavm.debugging.JavaScriptLocation;
import org.teavm.debugging.JavaScriptVariable;
/** /**
* *
@ -25,10 +28,13 @@ import org.teavm.debugging.JavaScriptLocation;
public class RDPCallFrame implements JavaScriptCallFrame { public class RDPCallFrame implements JavaScriptCallFrame {
private String chromeId; private String chromeId;
private JavaScriptLocation location; private JavaScriptLocation location;
private Map<String, JavaScriptVariable> variables;
public RDPCallFrame(String chromeId, JavaScriptLocation location) { public RDPCallFrame(String chromeId, JavaScriptLocation location,
Map<String, ? extends JavaScriptVariable> variables) {
this.chromeId = chromeId; this.chromeId = chromeId;
this.location = location; this.location = location;
this.variables = Collections.unmodifiableMap(variables);
} }
public String getChromeId() { public String getChromeId() {
@ -39,4 +45,9 @@ public class RDPCallFrame implements JavaScriptCallFrame {
public JavaScriptLocation getLocation() { public JavaScriptLocation getLocation() {
return location; return location;
} }
@Override
public Map<String, JavaScriptVariable> getVariables() {
return variables;
}
} }

View File

@ -0,0 +1,28 @@
package org.teavm.chromerdp;
import org.teavm.debugging.JavaScriptValue;
import org.teavm.debugging.JavaScriptVariable;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class RDPLocalVariable implements JavaScriptVariable {
private String name;
private RDPValue value;
public RDPLocalVariable(String name, RDPValue value) {
this.name = name;
this.value = value;
}
@Override
public String getName() {
return name;
}
@Override
public JavaScriptValue getValue() {
return value;
}
}

View File

@ -0,0 +1,53 @@
package org.teavm.chromerdp;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
private volatile Map<String, RDPLocalVariable> backingMap;
private ChromeRDPDebugger debugger;
private String id;
public RDPScope(ChromeRDPDebugger debugger, String id) {
this.debugger = debugger;
this.id = id;
}
@Override
public Set<Entry<String, RDPLocalVariable>> entrySet() {
initBackingMap();
return backingMap.entrySet();
}
@Override
public int size() {
initBackingMap();
return backingMap.size();
}
@Override
public RDPLocalVariable get(Object key) {
initBackingMap();
return backingMap.get(key);
}
private void initBackingMap() {
if (backingMap != null) {
return;
}
if (id == null) {
backingMap = new HashMap<>();
}
Map<String, RDPLocalVariable> newBackingMap = new HashMap<>();
for (RDPLocalVariable variable : debugger.getScope(id)) {
newBackingMap.put(variable.getName(), variable);
}
backingMap = newBackingMap;
}
}

View File

@ -0,0 +1,28 @@
package org.teavm.chromerdp;
import java.util.Collections;
import java.util.Map;
import org.teavm.debugging.JavaScriptValue;
import org.teavm.debugging.JavaScriptVariable;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class RDPValue implements JavaScriptValue {
private String representation;
public RDPValue(String representation) {
this.representation = representation;
}
@Override
public String getRepresentation() {
return representation;
}
@Override
public Map<String, JavaScriptVariable> getProperties() {
return Collections.emptyMap();
}
}

View File

@ -25,6 +25,7 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties;
public class CallFrameDTO { public class CallFrameDTO {
private String callFrameId; private String callFrameId;
private LocationDTO location; private LocationDTO location;
private ScopeDTO[] scopeChain;
public String getCallFrameId() { public String getCallFrameId() {
return callFrameId; return callFrameId;
@ -41,4 +42,12 @@ public class CallFrameDTO {
public void setLocation(LocationDTO location) { public void setLocation(LocationDTO location) {
this.location = location; this.location = location;
} }
public ScopeDTO[] getScopeChain() {
return scopeChain;
}
public void setScopeChain(ScopeDTO[] scopeChain) {
this.scopeChain = scopeChain;
}
} }

View File

@ -0,0 +1,29 @@
package org.teavm.chromerdp.data;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class PropertyDescriptorDTO {
private String name;
private RemoteObjectDTO value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public RemoteObjectDTO getValue() {
return value;
}
public void setValue(RemoteObjectDTO value) {
this.value = value;
}
}

View File

@ -0,0 +1,57 @@
package org.teavm.chromerdp.data;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class RemoteObjectDTO {
private String className;
private String description;
private String objectId;
private String type;
private JsonNode value;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getObjectId() {
return objectId;
}
public void setObjectId(String objectId) {
this.objectId = objectId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public JsonNode getValue() {
return value;
}
public void setValue(JsonNode value) {
this.value = value;
}
}

View File

@ -0,0 +1,29 @@
package org.teavm.chromerdp.data;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScopeDTO {
private String object;
private String type;
public String getObject() {
return object;
}
public void setObject(String object) {
this.object = object;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,29 @@
package org.teavm.chromerdp.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class GetPropertiesCommand {
private String objectId;
private boolean ownProperties;
public String getObjectId() {
return objectId;
}
public void setObjectId(String objectId) {
this.objectId = objectId;
}
public boolean isOwnProperties() {
return ownProperties;
}
public void setOwnProperties(boolean ownProperties) {
this.ownProperties = ownProperties;
}
}

View File

@ -0,0 +1,21 @@
package org.teavm.chromerdp.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerdp.data.PropertyDescriptorDTO;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class GetPropertiesResponse {
private PropertyDescriptorDTO[] properties;
public PropertyDescriptorDTO[] getProperties() {
return properties;
}
public void setProperties(PropertyDescriptorDTO[] properties) {
this.properties = properties;
}
}

View File

@ -33,8 +33,8 @@ public class JavacSupport implements ClassHolderTransformer {
ValueType.object("javax.tools.JavaCompiler"))); ValueType.object("javax.tools.JavaCompiler")));
Program program = new Program(); Program program = new Program();
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
program.createVariable(); program.createVariable(null);
Variable var = program.createVariable(); Variable var = program.createVariable(null);
ConstructInstruction construct = new ConstructInstruction(); ConstructInstruction construct = new ConstructInstruction();
construct.setReceiver(var); construct.setReceiver(var);
construct.setType("com.sun.tools.javac.api.JavacTool"); construct.setType("com.sun.tools.javac.api.JavacTool");

View File

@ -15,6 +15,8 @@
*/ */
package org.teavm.debugging; package org.teavm.debugging;
import java.util.Collections;
import java.util.Map;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
/** /**
@ -24,10 +26,12 @@ import org.teavm.model.MethodReference;
public class CallFrame { public class CallFrame {
private SourceLocation location; private SourceLocation location;
private MethodReference method; private MethodReference method;
private Map<String, LocalVariable> variables;
CallFrame(SourceLocation location, MethodReference method) { CallFrame(SourceLocation location, MethodReference method, Map<String, LocalVariable> variables) {
this.location = location; this.location = location;
this.method = method; this.method = method;
this.variables = Collections.unmodifiableMap(variables);
} }
public SourceLocation getLocation() { public SourceLocation getLocation() {
@ -37,4 +41,8 @@ public class CallFrame {
public MethodReference getMethod() { public MethodReference getMethod() {
return method; return method;
} }
public Map<String, LocalVariable> getVariables() {
return variables;
}
} }

View File

@ -35,11 +35,14 @@ public class DebugInformation {
Map<String, Integer> classNameMap; Map<String, Integer> classNameMap;
String[] methods; String[] methods;
Map<String, Integer> methodMap; Map<String, Integer> methodMap;
String[] variableNames;
Map<String, Integer> variableNameMap;
FileDescription[] fileDescriptions; FileDescription[] fileDescriptions;
Mapping fileMapping; Mapping fileMapping;
Mapping classMapping; Mapping classMapping;
Mapping methodMapping; Mapping methodMapping;
Mapping lineMapping; Mapping lineMapping;
Mapping[] variableMappings;
public String[] getCoveredSourceFiles() { public String[] getCoveredSourceFiles() {
return fileNames.clone(); return fileNames.clone();
@ -99,6 +102,22 @@ public class DebugInformation {
return getMethodAt(new GeneratedLocation(line, column)); return getMethodAt(new GeneratedLocation(line, column));
} }
public String getVariableMeaningAt(int line, int column, String variable) {
return getVariableMeaningAt(new GeneratedLocation(line, column), variable);
}
public String getVariableMeaningAt(GeneratedLocation location, String variable) {
Integer varIndex = variableNameMap.get(variable);
if (varIndex == null) {
return null;
}
Mapping mapping = variableMappings[varIndex];
if (mapping == null) {
return null;
}
return componentByKey(mapping, variableNames, location);
}
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
int keyIndex = indexByKey(mapping, location); int keyIndex = indexByKey(mapping, location);
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1; int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
@ -124,6 +143,7 @@ public class DebugInformation {
fileNameMap = mapArray(fileNames); fileNameMap = mapArray(fileNames);
classNameMap = mapArray(classNames); classNameMap = mapArray(classNames);
methodMap = mapArray(methods); methodMap = mapArray(methods);
variableNameMap = mapArray(variableNames);
} }
private Map<String, Integer> mapArray(String[] array) { private Map<String, Integer> mapArray(String[] array) {

View File

@ -30,10 +30,12 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
private MappedList files = new MappedList(); private MappedList files = new MappedList();
private MappedList classes = new MappedList(); private MappedList classes = new MappedList();
private MappedList methods = new MappedList(); private MappedList methods = new MappedList();
private MappedList variableNames = new MappedList();
private Mapping fileMapping = new Mapping(); private Mapping fileMapping = new Mapping();
private Mapping lineMapping = new Mapping(); private Mapping lineMapping = new Mapping();
private Mapping classMapping = new Mapping(); private Mapping classMapping = new Mapping();
private Mapping methodMapping = new Mapping(); private Mapping methodMapping = new Mapping();
private Map<Integer, Mapping> variableMappings = new HashMap<>();
private MethodDescriptor currentMethod; private MethodDescriptor currentMethod;
private String currentClass; private String currentClass;
private String currentFileName; private String currentFileName;
@ -82,6 +84,18 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
} }
} }
@Override
public void emitVariable(String sourceName, String generatedName) {
int sourceIndex = variableNames.index(sourceName);
int generatedIndex = variableNames.index(generatedName);
Mapping mapping = variableMappings.get(generatedIndex);
if (mapping == null) {
mapping = new Mapping();
variableMappings.put(generatedIndex, mapping);
}
mapping.add(locationProvider, sourceIndex);
}
public DebugInformation getDebugInformation() { public DebugInformation getDebugInformation() {
if (debugInformation == null) { if (debugInformation == null) {
debugInformation = new DebugInformation(); debugInformation = new DebugInformation();
@ -92,11 +106,18 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
debugInformation.classNameMap = classes.getIndexes(); debugInformation.classNameMap = classes.getIndexes();
debugInformation.methods = methods.getItems(); debugInformation.methods = methods.getItems();
debugInformation.methodMap = methods.getIndexes(); debugInformation.methodMap = methods.getIndexes();
debugInformation.variableNames = variableNames.getItems();
debugInformation.variableNameMap = variableNames.getIndexes();
debugInformation.fileMapping = fileMapping.build(); debugInformation.fileMapping = fileMapping.build();
debugInformation.lineMapping = lineMapping.build(); debugInformation.lineMapping = lineMapping.build();
debugInformation.classMapping = classMapping.build(); debugInformation.classMapping = classMapping.build();
debugInformation.methodMapping = methodMapping.build(); debugInformation.methodMapping = methodMapping.build();
debugInformation.variableMappings = new DebugInformation.Mapping[variableNames.list.size()];
for (int var : variableMappings.keySet()) {
Mapping mapping = variableMappings.get(var);
debugInformation.variableMappings[var] = mapping.build();
}
debugInformation.rebuildFileDescriptions(); debugInformation.rebuildFileDescriptions();
} }

View File

@ -30,4 +30,6 @@ public interface DebugInformationEmitter {
void emitMethod(MethodDescriptor method); void emitMethod(MethodDescriptor method);
void emitClass(String className); void emitClass(String className);
void emitVariable(String sourceName, String generatedName);
} }

View File

@ -36,15 +36,30 @@ class DebugInformationReader {
debugInfo.fileNames = readStrings(); debugInfo.fileNames = readStrings();
debugInfo.classNames = readStrings(); debugInfo.classNames = readStrings();
debugInfo.methods = readStrings(); debugInfo.methods = readStrings();
debugInfo.variableNames = readStrings();
debugInfo.fileMapping = readMapping(); debugInfo.fileMapping = readMapping();
debugInfo.lineMapping = readMapping(); debugInfo.lineMapping = readMapping();
debugInfo.classMapping = readMapping(); debugInfo.classMapping = readMapping();
debugInfo.methodMapping = readMapping(); debugInfo.methodMapping = readMapping();
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
debugInfo.rebuildFileDescriptions(); debugInfo.rebuildFileDescriptions();
debugInfo.rebuildMaps(); debugInfo.rebuildMaps();
return debugInfo; return debugInfo;
} }
private DebugInformation.Mapping[] readVariableMappings(int count) throws IOException {
DebugInformation.Mapping[] mappings = new DebugInformation.Mapping[count];
int varCount = readUnsignedNumber();
while (varCount-- > 0) {
int lastVar = 0;
for (int i = 0; i < mappings.length; ++i) {
lastVar += readUnsignedNumber();
mappings[lastVar] = readMapping();
}
}
return mappings;
}
private int processSign(int number) { private int processSign(int number) {
boolean negative = (number & 1) != 0; boolean negative = (number & 1) != 0;
number >>>= 1; number >>>= 1;

View File

@ -34,11 +34,37 @@ class DebugInformationWriter {
writeStringArray(debugInfo.fileNames); writeStringArray(debugInfo.fileNames);
writeStringArray(debugInfo.classNames); writeStringArray(debugInfo.classNames);
writeStringArray(debugInfo.methods); writeStringArray(debugInfo.methods);
writeStringArray(debugInfo.variableNames);
writeMapping(debugInfo.fileMapping); writeMapping(debugInfo.fileMapping);
writeMapping(debugInfo.lineMapping); writeMapping(debugInfo.lineMapping);
writeMapping(debugInfo.classMapping); writeMapping(debugInfo.classMapping);
writeMapping(debugInfo.methodMapping); writeMapping(debugInfo.methodMapping);
writeUnsignedNumber(nonNullVariableMappings(debugInfo));
writeVariableMappings(debugInfo);
}
private void writeVariableMappings(DebugInformation debugInfo) throws IOException {
int lastVar = 0;
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
DebugInformation.Mapping mapping = debugInfo.variableMappings[i];
if (mapping == null) {
continue;
}
writeUnsignedNumber(i - lastVar);
lastVar = i;
writeMapping(mapping);
}
}
private int nonNullVariableMappings(DebugInformation debugInfo) {
int count = 0;
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
if (debugInfo.variableMappings[i] != null) {
++count;
}
}
return count;
} }
private void writeStringArray(String[] array) throws IOException { private void writeStringArray(String[] array) throws IOException {

View File

@ -186,7 +186,7 @@ public class Debugger {
MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(), MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(),
jsFrame.getLocation().getColumn()) : null; jsFrame.getLocation().getColumn()) : null;
if (!empty || !wasEmpty) { if (!empty || !wasEmpty) {
frames.add(new CallFrame(loc, method)); frames.add(new CallFrame(loc, method, new HashMap<String, LocalVariable>()));
} }
wasEmpty = empty; wasEmpty = empty;
} }

View File

@ -36,6 +36,10 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
public void emitClass(String className) { public void emitClass(String className) {
} }
@Override
public void emitVariable(String sourceName, String generatedName) {
}
@Override @Override
public void setLocationProvider(LocationProvider locationProvider) { public void setLocationProvider(LocationProvider locationProvider) {
} }

View File

@ -15,10 +15,14 @@
*/ */
package org.teavm.debugging; package org.teavm.debugging;
import java.util.Map;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface JavaScriptCallFrame { public interface JavaScriptCallFrame {
JavaScriptLocation getLocation(); JavaScriptLocation getLocation();
Map<String, JavaScriptVariable> getVariables();
} }

View File

@ -0,0 +1,13 @@
package org.teavm.debugging;
import java.util.Map;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface JavaScriptValue {
String getRepresentation();
Map<String, JavaScriptVariable> getProperties();
}

View File

@ -0,0 +1,11 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface JavaScriptVariable {
String getName();
JavaScriptValue getValue();
}

View File

@ -0,0 +1,23 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class LocalVariable {
private String name;
private WatchedValue value;
LocalVariable(String name, WatchedValue value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public WatchedValue getValue() {
return value;
}
}

View File

@ -0,0 +1,13 @@
package org.teavm.debugging;
import java.util.Map;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class WatchedValue {
public abstract String getRepresentation();
public abstract Map<String, LocalVariable> getProperties();
}

View File

@ -268,6 +268,11 @@ public class Decompiler {
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer();
optimizer.optimize(methodNode, method.getProgram()); optimizer.optimize(methodNode, method.getProgram());
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers())); methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
int paramCount = method.getSignature().length;
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
methodNode.getParameterDebugNames().add(var.getDebugName());
}
return methodNode; return methodNode;
} }

View File

@ -49,7 +49,7 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer {
} }
NullCheckInstruction nullCheck = new NullCheckInstruction(); NullCheckInstruction nullCheck = new NullCheckInstruction();
nullCheck.setValue(invoke.getInstance()); nullCheck.setValue(invoke.getInstance());
Variable var = block.getProgram().createVariable(); Variable var = block.getProgram().createVariable(null);
nullCheck.setReceiver(var); nullCheck.setReceiver(var);
invoke.setInstance(var); invoke.setInstance(var);
block.getInstructions().add(i++, nullCheck); block.getInstructions().add(i++, nullCheck);

View File

@ -518,6 +518,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
public void visit(RegularMethodNode method) { public void visit(RegularMethodNode method) {
try { try {
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
for (int i = 0; i < method.getParameterDebugNames().size(); ++i) {
debugEmitter.emitVariable(method.getParameterDebugNames().get(i), variableName(i));
}
int variableCount = 0; int variableCount = 0;
for (int var : method.getVariables()) { for (int var : method.getVariables()) {
variableCount = Math.max(variableCount, var + 1); variableCount = Math.max(variableCount, var + 1);
@ -601,6 +604,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (statement.getLocation() != null) { if (statement.getLocation() != null) {
popLocation(); popLocation();
} }
if (statement.getLeftValue() instanceof VariableExpr) {
VariableExpr receiver = (VariableExpr)statement.getLeftValue();
debugEmitter.emitVariable(statement.getDebugName(), variableName(receiver.getIndex()));
}
} catch (IOException e) { } catch (IOException e) {
throw new RenderingException("IO error occured", e); throw new RenderingException("IO error occured", e);
} }

View File

@ -48,44 +48,44 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
assign(Expr.constant(null), insn.getReceiver().getIndex()); assign(Expr.constant(null), insn.getReceiver());
} }
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
assign(Expr.constant(insn.getConstant()), insn.getReceiver().getIndex()); assign(Expr.constant(insn.getConstant()), insn.getReceiver());
} }
@Override @Override
public void visit(BinaryInstruction insn) { public void visit(BinaryInstruction insn) {
int first = insn.getFirstOperand().getIndex(); int first = insn.getFirstOperand().getIndex();
int second = insn.getSecondOperand().getIndex(); int second = insn.getSecondOperand().getIndex();
int result = insn.getReceiver().getIndex(); Variable result = insn.getReceiver();
switch (insn.getOperation()) { switch (insn.getOperation()) {
case ADD: case ADD:
switch (insn.getOperandType()) { switch (insn.getOperandType()) {
@ -227,15 +227,15 @@ class StatementGenerator implements InstructionVisitor {
switch (insn.getOperandType()) { switch (insn.getOperandType()) {
case INT: case INT:
assign(castToInteger(Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex()))), assign(castToInteger(Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex()))),
insn.getReceiver().getIndex()); insn.getReceiver());
break; break;
case LONG: case LONG:
assign(Expr.unary(UnaryOperation.NEGATE_LONG, Expr.var(insn.getOperand().getIndex())), assign(Expr.unary(UnaryOperation.NEGATE_LONG, Expr.var(insn.getOperand().getIndex())),
insn.getReceiver().getIndex()); insn.getReceiver());
break; break;
default: default:
assign(Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex())), assign(Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex())),
insn.getReceiver().getIndex()); insn.getReceiver());
break; break;
} }
} }
@ -244,13 +244,14 @@ class StatementGenerator implements InstructionVisitor {
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()),
Expr.var(insn.getAssignee().getIndex())); Expr.var(insn.getAssignee().getIndex()));
stmt.setDebugName(insn.getReceiver().getDebugName());
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
statements.add(stmt); statements.add(stmt);
} }
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
assign(Expr.var(insn.getValue().getIndex()), insn.getReceiver().getIndex()); assign(Expr.var(insn.getValue().getIndex()), insn.getReceiver());
} }
@Override @Override
@ -292,7 +293,7 @@ class StatementGenerator implements InstructionVisitor {
default: default:
break; break;
} }
assign(value, insn.getReceiver().getIndex()); assign(value, insn.getReceiver());
} }
@Override @Override
@ -323,7 +324,7 @@ class StatementGenerator implements InstructionVisitor {
} }
break; break;
} }
assign(value, insn.getReceiver().getIndex()); assign(value, insn.getReceiver());
} }
@Override @Override
@ -459,13 +460,12 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void visit(ConstructArrayInstruction insn) {
assign(Expr.createArray(insn.getItemType(), Expr.var(insn.getSize().getIndex())), assign(Expr.createArray(insn.getItemType(), Expr.var(insn.getSize().getIndex())), insn.getReceiver());
insn.getReceiver().getIndex());
} }
@Override @Override
public void visit(ConstructInstruction insn) { public void visit(ConstructInstruction insn) {
assign(Expr.createObject(insn.getType()), insn.getReceiver().getIndex()); assign(Expr.createObject(insn.getType()), insn.getReceiver());
} }
@Override @Override
@ -474,7 +474,7 @@ class StatementGenerator implements InstructionVisitor {
for (int i = 0; i < dimensionExprs.length; ++i) { for (int i = 0; i < dimensionExprs.length; ++i) {
dimensionExprs[i] = Expr.var(insn.getDimensions().get(i).getIndex()); dimensionExprs[i] = Expr.var(insn.getDimensions().get(i).getIndex());
} }
assign(Expr.createArray(insn.getItemType(), dimensionExprs), insn.getReceiver().getIndex()); assign(Expr.createArray(insn.getItemType(), dimensionExprs), insn.getReceiver());
} }
@Override @Override
@ -509,28 +509,27 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
assign(Expr.unary(UnaryOperation.LENGTH, Expr.var(insn.getArray().getIndex())), insn.getReceiver().getIndex()); assign(Expr.unary(UnaryOperation.LENGTH, Expr.var(insn.getArray().getIndex())), insn.getReceiver());
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
UnwrapArrayExpr unwrapExpr = new UnwrapArrayExpr(insn.getElementType()); UnwrapArrayExpr unwrapExpr = new UnwrapArrayExpr(insn.getElementType());
unwrapExpr.setArray(Expr.var(insn.getArray().getIndex())); unwrapExpr.setArray(Expr.var(insn.getArray().getIndex()));
assign(unwrapExpr, insn.getReceiver().getIndex()); assign(unwrapExpr, insn.getReceiver());
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
MethodDescriptor cloneMethodDesc = new MethodDescriptor("clone", ValueType.object("java.lang.Object")); MethodDescriptor cloneMethodDesc = new MethodDescriptor("clone", ValueType.object("java.lang.Object"));
MethodReference cloneMethod = new MethodReference("java.lang.Object", cloneMethodDesc); MethodReference cloneMethod = new MethodReference("java.lang.Object", cloneMethodDesc);
assign(Expr.invoke(cloneMethod, Expr.var(insn.getArray().getIndex()), new Expr[0]), assign(Expr.invoke(cloneMethod, Expr.var(insn.getArray().getIndex()), new Expr[0]), insn.getReceiver());
insn.getReceiver().getIndex());
} }
@Override @Override
public void visit(GetElementInstruction insn) { public void visit(GetElementInstruction insn) {
assign(Expr.subscript(Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex())), assign(Expr.subscript(Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex())),
insn.getReceiver().getIndex()); insn.getReceiver());
} }
@Override @Override
@ -559,7 +558,7 @@ class StatementGenerator implements InstructionVisitor {
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs); invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
} }
if (insn.getReceiver() != null) { if (insn.getReceiver() != null) {
assign(invocationExpr, insn.getReceiver().getIndex()); assign(invocationExpr, insn.getReceiver());
} else { } else {
AssignmentStatement stmt = Statement.assign(null, invocationExpr); AssignmentStatement stmt = Statement.assign(null, invocationExpr);
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
@ -569,13 +568,13 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
assign(Expr.instanceOf(Expr.var(insn.getValue().getIndex()), insn.getType()), assign(Expr.instanceOf(Expr.var(insn.getValue().getIndex()), insn.getType()), insn.getReceiver());
insn.getReceiver().getIndex());
} }
private void assign(Expr source, int target) { private void assign(Expr source, Variable target) {
AssignmentStatement stmt = Statement.assign(Expr.var(target), source); AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source);
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
stmt.setDebugName(target.getDebugName());
statements.add(stmt); statements.add(stmt);
} }
@ -599,11 +598,11 @@ class StatementGenerator implements InstructionVisitor {
return Expr.unary(UnaryOperation.LONG_TO_NUM, value); return Expr.unary(UnaryOperation.LONG_TO_NUM, value);
} }
private void binary(int first, int second, int result, BinaryOperation op) { private void binary(int first, int second, Variable result, BinaryOperation op) {
assign(Expr.binary(op, Expr.var(first), Expr.var(second)), result); assign(Expr.binary(op, Expr.var(first), Expr.var(second)), result);
} }
private void intBinary(int first, int second, int result, BinaryOperation op) { private void intBinary(int first, int second, Variable result, BinaryOperation op) {
assign(castToInteger(Expr.binary(op, Expr.var(first), Expr.var(second))), result); assign(castToInteger(Expr.binary(op, Expr.var(first), Expr.var(second))), result);
} }
@ -657,7 +656,6 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), insn.getReceiver());
insn.getReceiver().getIndex());
} }
} }

View File

@ -23,6 +23,7 @@ public class AssignmentStatement extends Statement {
private Expr leftValue; private Expr leftValue;
private Expr rightValue; private Expr rightValue;
private NodeLocation location; private NodeLocation location;
private String debugName;
public Expr getLeftValue() { public Expr getLeftValue() {
return leftValue; return leftValue;
@ -48,6 +49,14 @@ public class AssignmentStatement extends Statement {
this.location = location; this.location = location;
} }
public String getDebugName() {
return debugName;
}
public void setDebugName(String debugName) {
this.debugName = debugName;
}
@Override @Override
public void acceptVisitor(StatementVisitor visitor) { public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -26,6 +26,7 @@ import org.teavm.model.MethodReference;
public class RegularMethodNode extends MethodNode { public class RegularMethodNode extends MethodNode {
private Statement body; private Statement body;
private List<Integer> variables = new ArrayList<>(); private List<Integer> variables = new ArrayList<>();
private List<String> parameterDebugNames = new ArrayList<>();
public RegularMethodNode(MethodReference reference) { public RegularMethodNode(MethodReference reference) {
super(reference); super(reference);
@ -43,6 +44,10 @@ public class RegularMethodNode extends MethodNode {
return variables; return variables;
} }
public List<String> getParameterDebugNames() {
return parameterDebugNames;
}
@Override @Override
public void acceptVisitor(MethodNodeVisitor visitor) { public void acceptVisitor(MethodNodeVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -35,8 +35,8 @@ public class Program implements ProgramReader {
return block; return block;
} }
public Variable createVariable() { public Variable createVariable(String debugName) {
Variable variable = new Variable(this); Variable variable = new Variable(this, debugName);
variable.setIndex(variables.size()); variable.setIndex(variables.size());
variables.add(variable); variables.add(variable);
variable.setRegister(lastUsedRegister++); variable.setRegister(lastUsedRegister++);

View File

@ -23,9 +23,11 @@ public class Variable implements VariableReader {
private Program program; private Program program;
private int index; private int index;
private int register; private int register;
private String debugName;
Variable(Program program) { Variable(Program program, String debugName) {
this.program = program; this.program = program;
this.debugName = debugName;
} }
@Override @Override
@ -54,4 +56,13 @@ public class Variable implements VariableReader {
public void setRegister(int register) { public void setRegister(int register) {
this.register = register; this.register = register;
} }
@Override
public String getDebugName() {
return debugName;
}
public void setDebugName(String debugName) {
this.debugName = debugName;
}
} }

View File

@ -24,5 +24,7 @@ public interface VariableReader {
ProgramReader getProgram(); ProgramReader getProgram();
String getDebugName();
int getRegister(); int getRegister();
} }

View File

@ -73,7 +73,7 @@ public final class ProgramUtils {
InstructionCopyReader insnCopier = new InstructionCopyReader(); InstructionCopyReader insnCopier = new InstructionCopyReader();
insnCopier.programCopy = copy; insnCopier.programCopy = copy;
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
copy.createVariable(); copy.createVariable(program.variableAt(i).getDebugName());
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
copy.createBasicBlock(); copy.createBasicBlock();

View File

@ -97,7 +97,7 @@ public class RegisterAllocator {
final Phi phi = incoming.getPhi(); final Phi phi = incoming.getPhi();
Program program = phi.getBasicBlock().getProgram(); Program program = phi.getBasicBlock().getProgram();
AssignInstruction copyInstruction = new AssignInstruction(); AssignInstruction copyInstruction = new AssignInstruction();
Variable firstCopy = program.createVariable(); Variable firstCopy = program.createVariable(incoming.getValue().getDebugName());
copyInstruction.setReceiver(firstCopy); copyInstruction.setReceiver(firstCopy);
copyInstruction.setAssignee(incoming.getValue()); copyInstruction.setAssignee(incoming.getValue());
BasicBlock source = blockMap.get(incoming.getSource()); BasicBlock source = blockMap.get(incoming.getSource());

View File

@ -179,7 +179,7 @@ public class LoopInvariantMotion implements MethodOptimization {
phi.getIncomings().remove(j--); phi.getIncomings().remove(j--);
if (preheaderPhi == null) { if (preheaderPhi == null) {
preheaderPhi = new Phi(); preheaderPhi = new Phi();
preheaderPhi.setReceiver(program.createVariable()); preheaderPhi.setReceiver(program.createVariable(null));
preheader.getPhis().add(preheaderPhi); preheader.getPhis().add(preheaderPhi);
} }
preheaderPhi.getIncomings().add(incoming); preheaderPhi.getIncomings().add(incoming);
@ -391,7 +391,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
ClassConstantInstruction copy = new ClassConstantInstruction(); ClassConstantInstruction copy = new ClassConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -400,7 +400,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
NullConstantInstruction copy = new NullConstantInstruction(); NullConstantInstruction copy = new NullConstantInstruction();
copy.setReceiver(var); copy.setReceiver(var);
this.copy = copy; this.copy = copy;
@ -408,7 +408,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
IntegerConstantInstruction copy = new IntegerConstantInstruction(); IntegerConstantInstruction copy = new IntegerConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -417,7 +417,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
LongConstantInstruction copy = new LongConstantInstruction(); LongConstantInstruction copy = new LongConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -426,7 +426,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
FloatConstantInstruction copy = new FloatConstantInstruction(); FloatConstantInstruction copy = new FloatConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -435,7 +435,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
DoubleConstantInstruction copy = new DoubleConstantInstruction(); DoubleConstantInstruction copy = new DoubleConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -444,7 +444,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable(insn.getReceiver().getDebugName());
StringConstantInstruction copy = new StringConstantInstruction(); StringConstantInstruction copy = new StringConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);

View File

@ -40,11 +40,11 @@ public final class Parser {
Program program = programParser.parse(node, className); Program program = programParser.parse(node, className);
new UnreachableBasicBlockEliminator().optimize(program); new UnreachableBasicBlockEliminator().optimize(program);
SSATransformer ssaProducer = new SSATransformer(); SSATransformer ssaProducer = new SSATransformer();
ssaProducer.transformToSSA(program, method.getParameterTypes()); ssaProducer.transformToSSA(program, programParser, method.getParameterTypes());
method.setProgram(program); method.setProgram(program);
parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations);
while (program.variableCount() <= method.parameterCount()) { while (program.variableCount() <= method.parameterCount()) {
program.createVariable(); program.createVariable(null);
} }
return method; return method;
} }

View File

@ -20,13 +20,14 @@ import org.objectweb.asm.*;
import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.*;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.InstructionTransitionExtractor; import org.teavm.model.util.InstructionTransitionExtractor;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class ProgramParser { public class ProgramParser implements VariableDebugInformation {
static final byte ROOT = 0; static final byte ROOT = 0;
static final byte SINGLE = 1; static final byte SINGLE = 1;
static final byte DOUBLE_FIRST_HALF = 2; static final byte DOUBLE_FIRST_HALF = 2;
@ -48,6 +49,9 @@ public class ProgramParser {
private int currentLineNumber; private int currentLineNumber;
private boolean lineNumberChanged; private boolean lineNumberChanged;
private InstructionLocation lastInsnLocation; private InstructionLocation lastInsnLocation;
private Map<Integer, List<LocalVariableNode>> localVariableMap = new HashMap<>();
private Map<Instruction, String> variableDebugNames = new HashMap<>();
private Map<Integer, String> parameterNames = new HashMap<>();
private static class Step { private static class Step {
public final int source; public final int source;
@ -113,11 +117,29 @@ public class ProgramParser {
} }
int signatureVars = countSignatureVariables(method.desc); int signatureVars = countSignatureVariables(method.desc);
while (program.variableCount() <= signatureVars) { while (program.variableCount() <= signatureVars) {
program.createVariable(); program.createVariable(getVariableDebugName(program.variableCount(), 0));
}
for (int i = 0; i < signatureVars; ++i) {
parameterNames.put(i, getVariableDebugName(i, 0));
} }
return program; return program;
} }
private String getVariableDebugName(int var, int location) {
List<LocalVariableNode> nodes = localVariableMap.get(var);
if (nodes == null) {
return null;
}
for (LocalVariableNode node : nodes) {
int start = labelIndexes.get(node.start.getLabel());
int end = labelIndexes.get(node.end.getLabel());
if (location >= start && location < end) {
return node.name;
}
}
return null;
}
private int countSignatureVariables(String desc) { private int countSignatureVariables(String desc) {
int count = 1; int count = 1;
for (Type paramType : Type.getArgumentTypes(desc)) { for (Type paramType : Type.getArgumentTypes(desc)) {
@ -159,6 +181,16 @@ public class ProgramParser {
return depth; return depth;
} }
@Override
public String getDefinitionDebugName(Instruction insn) {
return variableDebugNames.get(insn);
}
@Override
public String getParameterDebugName(int index) {
return parameterNames.get(index);
}
private void prepare(MethodNode method) { private void prepare(MethodNode method) {
InsnList instructions = method.instructions; InsnList instructions = method.instructions;
minLocal = 0; minLocal = 0;
@ -177,6 +209,14 @@ public class ProgramParser {
lineNumbers.put(lineNumberNode.start.getLabel(), lineNumberNode.line); lineNumbers.put(lineNumberNode.start.getLabel(), lineNumberNode.line);
} }
} }
for (LocalVariableNode localVar : method.localVariables) {
List<LocalVariableNode> vars = localVariableMap.get(localVar.index);
if (vars == null) {
vars = new ArrayList<>();
localVariableMap.put(localVar.index, vars);
}
vars.add(localVar);
}
targetInstructions = new ArrayList<>(instructions.size()); targetInstructions = new ArrayList<>(instructions.size());
targetInstructions.addAll(Collections.<List<Instruction>>nCopies(instructions.size(), null)); targetInstructions.addAll(Collections.<List<Instruction>>nCopies(instructions.size(), null));
basicBlocks.addAll(Collections.<BasicBlock>nCopies(instructions.size(), null)); basicBlocks.addAll(Collections.<BasicBlock>nCopies(instructions.size(), null));
@ -250,6 +290,20 @@ public class ProgramParser {
} }
private void assemble() { private void assemble() {
DefinitionExtractor defExtractor = new DefinitionExtractor();
for (int i = 0; i < targetInstructions.size(); ++i) {
List<Instruction> instructionList = targetInstructions.get(i);
for (Instruction insn : instructionList) {
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
String debugName = getVariableDebugName(var.getIndex(), i);
if (debugName != null) {
variableDebugNames.put(insn, debugName);
}
}
}
}
BasicBlock basicBlock = null; BasicBlock basicBlock = null;
for (int i = 0; i < basicBlocks.size(); ++i) { for (int i = 0; i < basicBlocks.size(); ++i) {
BasicBlock newBasicBlock = basicBlocks.get(i); BasicBlock newBasicBlock = basicBlocks.get(i);
@ -300,7 +354,7 @@ public class ProgramParser {
private Variable getVariable(int index) { private Variable getVariable(int index) {
while (index >= program.variableCount()) { while (index >= program.variableCount()) {
program.createVariable(); program.createVariable(null);
} }
return program.variableAt(index); return program.variableAt(index);
} }

View File

@ -38,12 +38,14 @@ public class SSATransformer {
private Phi[][] phiMap; private Phi[][] phiMap;
private int[][] phiIndexMap; private int[][] phiIndexMap;
private ValueType[] arguments; private ValueType[] arguments;
private VariableDebugInformation variableDebugInfo;
public void transformToSSA(Program program, ValueType[] arguments) { public void transformToSSA(Program program, VariableDebugInformation variableDebugInfo, ValueType[] arguments) {
if (program.basicBlockCount() == 0) { if (program.basicBlockCount() == 0) {
return; return;
} }
this.program = program; this.program = program;
this.variableDebugInfo = variableDebugInfo;
this.arguments = arguments; this.arguments = arguments;
cfg = ProgramUtils.buildControlFlowGraphWithoutTryCatch(program); cfg = ProgramUtils.buildControlFlowGraphWithoutTryCatch(program);
domTree = GraphUtils.buildDominatorTree(cfg); domTree = GraphUtils.buildDominatorTree(cfg);
@ -55,6 +57,9 @@ public class SSATransformer {
phiMap[i] = new Phi[program.variableCount()]; phiMap[i] = new Phi[program.variableCount()];
phiIndexMap[i] = new int[program.variableCount()]; phiIndexMap[i] = new int[program.variableCount()];
} }
for (int i = 0; i < program.variableCount(); ++i) {
program.variableAt(i).setDebugName(variableDebugInfo.getParameterDebugName(i));
}
applySignature(); applySignature();
domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree); domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree);
estimatePhis(); estimatePhis();
@ -136,16 +141,17 @@ public class SSATransformer {
processed[currentBlock.getIndex()] = true; processed[currentBlock.getIndex()] = true;
variableMap = Arrays.copyOf(task.variables, task.variables.length); variableMap = Arrays.copyOf(task.variables, task.variables.length);
for (Phi phi : currentBlock.getPhis()) { for (Phi phi : currentBlock.getPhis()) {
Variable var = program.createVariable(); Variable var = program.createVariable(phi.getReceiver().getDebugName());
variableMap[phi.getReceiver().getIndex()] = var; variableMap[phi.getReceiver().getIndex()] = var;
phi.setReceiver(var); phi.setReceiver(var);
} }
if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) { if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) {
Phi phi = new Phi(); Phi phi = new Phi();
phi.setReceiver(program.createVariable()); phi.setReceiver(program.createVariable(null));
for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) { for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) {
variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver(); variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver();
tryCatch.setExceptionVariable(program.createVariable()); tryCatch.setExceptionVariable(program.createVariable(
tryCatch.getExceptionVariable().getDebugName()));
Incoming incoming = new Incoming(); Incoming incoming = new Incoming();
incoming.setSource(tryCatch.getProtectedBlock()); incoming.setSource(tryCatch.getProtectedBlock());
incoming.setValue(tryCatch.getExceptionVariable()); incoming.setValue(tryCatch.getExceptionVariable());
@ -210,8 +216,8 @@ public class SSATransformer {
} }
} }
private Variable define(Variable var) { private Variable define(Variable var, String debugName) {
Variable result = program.createVariable(); Variable result = program.createVariable(debugName);
variableMap[var.getIndex()] = result; variableMap[var.getIndex()] = result;
return result; return result;
} }
@ -231,56 +237,56 @@ public class SSATransformer {
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(BinaryInstruction insn) { public void visit(BinaryInstruction insn) {
insn.setFirstOperand(use(insn.getFirstOperand())); insn.setFirstOperand(use(insn.getFirstOperand()));
insn.setSecondOperand(use(insn.getSecondOperand())); insn.setSecondOperand(use(insn.getSecondOperand()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(NegateInstruction insn) { public void visit(NegateInstruction insn) {
insn.setOperand(use(insn.getOperand())); insn.setOperand(use(insn.getOperand()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
insn.setAssignee(use(insn.getAssignee())); insn.setAssignee(use(insn.getAssignee()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -318,12 +324,12 @@ public class SSATransformer {
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void visit(ConstructArrayInstruction insn) {
insn.setSize(use(insn.getSize())); insn.setSize(use(insn.getSize()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(ConstructInstruction insn) { public void visit(ConstructInstruction insn) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -332,7 +338,7 @@ public class SSATransformer {
for (int i = 0; i < dimensions.size(); ++i) { for (int i = 0; i < dimensions.size(); ++i) {
dimensions.set(i, use(dimensions.get(i))); dimensions.set(i, use(dimensions.get(i)));
} }
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -340,7 +346,7 @@ public class SSATransformer {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
insn.setInstance(use(insn.getInstance())); insn.setInstance(use(insn.getInstance()));
} }
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -355,7 +361,7 @@ public class SSATransformer {
public void visit(GetElementInstruction insn) { public void visit(GetElementInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setIndex(use(insn.getIndex())); insn.setIndex(use(insn.getIndex()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -375,50 +381,50 @@ public class SSATransformer {
insn.setInstance(use(insn.getInstance())); insn.setInstance(use(insn.getInstance()));
} }
if (insn.getReceiver() != null) { if (insn.getReceiver() != null) {
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
} }
@Override @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(CastNumberInstruction insn) { public void visit(CastNumberInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(CastIntegerInstruction insn) { public void visit(CastIntegerInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
@Override @Override
@ -428,7 +434,7 @@ public class SSATransformer {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn)));
} }
}; };
} }

View File

@ -0,0 +1,13 @@
package org.teavm.parsing;
import org.teavm.model.Instruction;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface VariableDebugInformation {
String getDefinitionDebugName(Instruction insn);
String getParameterDebugName(int index);
}

View File

@ -44,13 +44,13 @@ public class JCLHacks implements ClassHolderTransformer {
MethodHolder method = new MethodHolder(desc); MethodHolder method = new MethodHolder(desc);
Program program = new Program(); Program program = new Program();
for (int i = 0; i < desc.parameterCount(); ++i) { for (int i = 0; i < desc.parameterCount(); ++i) {
program.createVariable(); program.createVariable(null);
} }
if (!staticMethod) { if (!staticMethod) {
program.createVariable(); program.createVariable(null);
} }
program.createVariable(); program.createVariable(null);
Variable var = program.createVariable(); Variable var = program.createVariable(null);
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
ConstructInstruction cons = new ConstructInstruction(); ConstructInstruction cons = new ConstructInstruction();
cons.setType("java.lang.SecurityException"); cons.setType("java.lang.SecurityException");
@ -75,8 +75,8 @@ public class JCLHacks implements ClassHolderTransformer {
private MethodHolder createThreadSleep() { private MethodHolder createThreadSleep() {
MethodHolder method = new MethodHolder("sleep", ValueType.LONG, ValueType.VOID); MethodHolder method = new MethodHolder("sleep", ValueType.LONG, ValueType.VOID);
Program program = new Program(); Program program = new Program();
program.createVariable(); program.createVariable(null);
program.createVariable(); program.createVariable(null);
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
ExitInstruction exit = new ExitInstruction(); ExitInstruction exit = new ExitInstruction();
block.getInstructions().add(exit); block.getInstructions().add(exit);

View File

@ -81,7 +81,7 @@ class JavascriptNativeProcessor {
if (isProperGetter(method.getDescriptor())) { if (isProperGetter(method.getDescriptor())) {
String propertyName = method.getName().charAt(0) == 'i' ? cutPrefix(method.getName(), 2) : String propertyName = method.getName().charAt(0) == 'i' ? cutPrefix(method.getName(), 2) :
cutPrefix(method.getName(), 3); cutPrefix(method.getName(), 3);
Variable result = invoke.getReceiver() != null ? program.createVariable() : null; Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null;
addPropertyGet(propertyName, invoke.getInstance(), result); addPropertyGet(propertyName, invoke.getInstance(), result);
if (result != null) { if (result != null) {
result = unwrap(result, method.getResultType()); result = unwrap(result, method.getResultType());
@ -96,7 +96,7 @@ class JavascriptNativeProcessor {
} }
} else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) { } else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) {
if (isProperGetIndexer(method.getDescriptor())) { if (isProperGetIndexer(method.getDescriptor())) {
Variable result = invoke.getReceiver() != null ? program.createVariable() : null; Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null;
addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0), addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0),
method.parameterType(0)), result); method.parameterType(0)), result);
if (result != null) { if (result != null) {
@ -143,7 +143,7 @@ class JavascriptNativeProcessor {
"a proper native JavaScript method or constructor declaration"); "a proper native JavaScript method or constructor declaration");
} }
} }
Variable result = invoke.getReceiver() != null ? program.createVariable() : null; Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null;
InvokeInstruction newInvoke = new InvokeInstruction(); InvokeInstruction newInvoke = new InvokeInstruction();
ValueType[] signature = new ValueType[method.parameterCount() + 3]; ValueType[] signature = new ValueType[method.parameterCount() + 3];
Arrays.fill(signature, ValueType.object(JSObject.class.getName())); Arrays.fill(signature, ValueType.object(JSObject.class.getName()));
@ -226,7 +226,7 @@ class JavascriptNativeProcessor {
} }
private Variable addString(String str) { private Variable addString(String str) {
Variable var = program.createVariable(); Variable var = program.createVariable(null);
StringConstantInstruction nameInsn = new StringConstantInstruction(); StringConstantInstruction nameInsn = new StringConstantInstruction();
nameInsn.setReceiver(var); nameInsn.setReceiver(var);
nameInsn.setConstant(str); nameInsn.setConstant(str);
@ -261,7 +261,7 @@ class JavascriptNativeProcessor {
} else if (className.equals("java.lang.String")) { } else if (className.equals("java.lang.String")) {
return unwrap(var, "unwrapString", ValueType.object("java.lang.String")); return unwrap(var, "unwrapString", ValueType.object("java.lang.String"));
} else { } else {
Variable result = program.createVariable(); Variable result = program.createVariable(null);
CastInstruction castInsn = new CastInstruction(); CastInstruction castInsn = new CastInstruction();
castInsn.setReceiver(result); castInsn.setReceiver(result);
castInsn.setValue(var); castInsn.setValue(var);
@ -274,7 +274,7 @@ class JavascriptNativeProcessor {
} }
private Variable unwrap(Variable var, String methodName, ValueType resultType) { private Variable unwrap(Variable var, String methodName, ValueType resultType) {
Variable result = program.createVariable(); Variable result = program.createVariable(null);
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.object(JSObject.class.getName()), insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.object(JSObject.class.getName()),
resultType)); resultType));
@ -301,7 +301,7 @@ class JavascriptNativeProcessor {
throw new RuntimeException("Wrong functor: " + type.getName()); throw new RuntimeException("Wrong functor: " + type.getName());
} }
String name = type.getMethods().iterator().next().getName(); String name = type.getMethods().iterator().next().getName();
Variable functor = program.createVariable(); Variable functor = program.createVariable(null);
Variable nameVar = addStringWrap(addString(name)); Variable nameVar = addStringWrap(addString(name));
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), "function", insn.setMethod(new MethodReference(JS.class.getName(), "function",
@ -321,7 +321,7 @@ class JavascriptNativeProcessor {
return var; return var;
} }
} }
Variable result = program.createVariable(); Variable result = program.createVariable(null);
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), "wrap", type, insn.setMethod(new MethodReference(JS.class.getName(), "wrap", type,
ValueType.object(JSObject.class.getName()))); ValueType.object(JSObject.class.getName())));

View File

@ -131,7 +131,7 @@ class ResourceProgramTransformer {
} else if (type instanceof ValueType.Object) { } else if (type instanceof ValueType.Object) {
switch (((ValueType.Object)type).getClassName()) { switch (((ValueType.Object)type).getClassName()) {
case "java.lang.String": { case "java.lang.String": {
Variable resultVar = insn.getProgram().createVariable(); Variable resultVar = insn.getProgram().createVariable(null);
getProperty(insn, property, instructions, resultVar); getProperty(insn, property, instructions, resultVar);
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
@ -143,7 +143,7 @@ class ResourceProgramTransformer {
return instructions; return instructions;
} }
default: { default: {
Variable resultVar = insn.getProgram().createVariable(); Variable resultVar = insn.getProgram().createVariable(null);
getProperty(insn, property, instructions, resultVar); getProperty(insn, property, instructions, resultVar);
CastInstruction castInsn = new CastInstruction(); CastInstruction castInsn = new CastInstruction();
castInsn.setReceiver(insn.getReceiver()); castInsn.setReceiver(insn.getReceiver());
@ -159,7 +159,7 @@ class ResourceProgramTransformer {
private void getProperty(InvokeInstruction insn, String property, List<Instruction> instructions, private void getProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
Variable resultVar) { Variable resultVar) {
Variable nameVar = program.createVariable(); Variable nameVar = program.createVariable(null);
StringConstantInstruction nameInsn = new StringConstantInstruction(); StringConstantInstruction nameInsn = new StringConstantInstruction();
nameInsn.setConstant(property); nameInsn.setConstant(property);
nameInsn.setReceiver(nameVar); nameInsn.setReceiver(nameVar);
@ -176,7 +176,7 @@ class ResourceProgramTransformer {
private void getAndCastProperty(InvokeInstruction insn, String property, List<Instruction> instructions, private void getAndCastProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
Class<?> primitive) { Class<?> primitive) {
Variable resultVar = program.createVariable(); Variable resultVar = program.createVariable(null);
getProperty(insn, property, instructions, resultVar); getProperty(insn, property, instructions, resultVar);
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
@ -220,7 +220,7 @@ class ResourceProgramTransformer {
} else if (type instanceof ValueType.Object) { } else if (type instanceof ValueType.Object) {
switch (((ValueType.Object)type).getClassName()) { switch (((ValueType.Object)type).getClassName()) {
case "java.lang.String": { case "java.lang.String": {
Variable castVar = insn.getProgram().createVariable(); Variable castVar = insn.getProgram().createVariable(null);
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString", castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString",
@ -242,7 +242,7 @@ class ResourceProgramTransformer {
private void setProperty(InvokeInstruction insn, String property, List<Instruction> instructions, private void setProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
Variable valueVar) { Variable valueVar) {
Variable nameVar = program.createVariable(); Variable nameVar = program.createVariable(null);
StringConstantInstruction nameInsn = new StringConstantInstruction(); StringConstantInstruction nameInsn = new StringConstantInstruction();
nameInsn.setConstant(property); nameInsn.setConstant(property);
nameInsn.setReceiver(nameVar); nameInsn.setReceiver(nameVar);
@ -259,7 +259,7 @@ class ResourceProgramTransformer {
private void castAndSetProperty(InvokeInstruction insn, String property, List<Instruction> instructions, private void castAndSetProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
Class<?> primitive) { Class<?> primitive) {
Variable castVar = program.createVariable(); Variable castVar = program.createVariable(null);
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
String primitiveCapitalized = primitive.getName(); String primitiveCapitalized = primitive.getName();