Bug 566053 - [otdre] improve stepping experience when debugging through
OT/J dispatch code
- weave TeamManager.getMemberId() to set STEP_OVER_LINENUMBER
- enable earliest possible weaving with fast-lane treatment
- standalone: trigger loading from the agent
- OT/Equinox: is triggered during extension reading via team scanning
diff --git a/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
index 54d46c7..6dea262 100644
--- a/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.objectteams.otredyn
Automatic-Module-Name: org.eclipse.objectteams.otredyn
-Bundle-Version: 1.4.1.qualifier
+Bundle-Version: 1.4.2.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.objectteams.otredyn.bytecode,
diff --git a/plugins/org.eclipse.objectteams.otredyn/otredyn.jardesc b/plugins/org.eclipse.objectteams.otredyn/otredyn.jardesc
index 15674e6..f72ce13 100644
--- a/plugins/org.eclipse.objectteams.otredyn/otredyn.jardesc
+++ b/plugins/org.eclipse.objectteams.otredyn/otredyn.jardesc
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="org.eclipse.objectteams.otdt/lib/otredyn.jar"/>
- <options buildIfNeeded="true" compress="true" descriptionLocation="/org.eclipse.objectteams.otredyn/otre.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/org.eclipse.objectteams.otredyn/otredyn.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MarkAsStepOverAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MarkAsStepOverAdapter.java
new file mode 100644
index 0000000..5d35f8e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MarkAsStepOverAdapter.java
@@ -0,0 +1,63 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2020 GK Software SE
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.util.SMAPConstants;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.LineNumberNode;
+import org.objectweb.asm.tree.MethodNode;
+
+public class MarkAsStepOverAdapter extends AbstractTransformableClassNode {
+
+ private Method[] methods;
+
+ public MarkAsStepOverAdapter(Method[] methods) {
+ this.methods = methods;
+ }
+
+ @Override
+ protected boolean transform() {
+ for (Method method : this.methods) {
+ MethodNode orgMethod = getMethod(method);
+ for (AbstractInsnNode insnNode : orgMethod.instructions) {
+ if (insnNode instanceof LineNumberNode)
+ ((LineNumberNode) insnNode).line = SMAPConstants.STEP_OVER_LINENUMBER;
+ }
+ }
+ return true;
+ }
+
+ public static byte[] transformTeamManager(byte[] classfileBuffer, ClassLoader loader) {
+ if (!IS_DEBUG)
+ return classfileBuffer;
+
+ Method[] methodsToMark = new Method[] { new Method("getMemberId", "(ILjava/lang/Class;)I") };
+ MarkAsStepOverAdapter adapter = new MarkAsStepOverAdapter(methodsToMark);
+ ClassReader reader = new ClassReader(classfileBuffer);
+ reader.accept(adapter, ClassReader.SKIP_FRAMES);
+ if (adapter.transform()) {
+ LoaderAwareClassWriter writer = new LoaderAwareClassWriter(reader, ClassWriter.COMPUTE_FRAMES, loader);
+ adapter.accept(writer);
+ return writer.toByteArray();
+ }
+ return classfileBuffer;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
index 84b6484..7c6e928 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
@@ -29,6 +29,7 @@
import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
import org.eclipse.objectteams.otredyn.bytecode.ClassRepository;
+import org.eclipse.objectteams.otredyn.bytecode.asm.MarkAsStepOverAdapter;
import org.eclipse.objectteams.otredyn.bytecode.asm.WeavableRegionReader;
import org.eclipse.objectteams.otredyn.transformer.IWeavingContext;
import org.eclipse.objectteams.runtime.IReweavingTask;
@@ -90,9 +91,20 @@
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
+ String sourceClassName = className.replace('/','.');
+
+ if (sourceClassName.equals("org.eclipse.objectteams.otredyn.runtime.TeamManager")) {
+ // This special class needs to bypass our regular infra, because we have live code references to it,
+ // which would trigger unsound re-entrance.
+ // All we want is modifying some line numbers for better debugging experience.
+ return MarkAsStepOverAdapter.transformTeamManager(classfileBuffer, loader);
+ }
+ if (className.equals("org/objectteams/ITeamManager")) {
+ return null; // during loading of TeamManager avoid to trigger code below that needs TeamManager already
+ }
+
ClassRepository classRepo = ClassRepository.getInstance();
AbstractBoundClass clazz = classRepo.peekBoundClass(classId);
- String sourceClassName = className.replace('/','.');
if (!weavingContext.isWeavable(sourceClassName, true, true) || loader == null) {
if (clazz != null) {
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
index 93952ae..6af1b36 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
@@ -19,6 +19,7 @@
import java.lang.instrument.Instrumentation;
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.tree.InsnNode;
@@ -38,6 +39,7 @@
checkASM();
otTransformer = new ObjectTeamsTransformer();
instCopy.addTransformer(otTransformer);
+ TeamManager.class.getName(); // trigger earliest possible weaving
}
private static void checkASM() {
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
index bc429a1..3d3128c 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
@@ -20,7 +20,6 @@
import java.util.HashSet;
import java.util.List;
-import org.eclipse.objectteams.otredyn.runtime.TeamManager;
import org.objectteams.IBoundBase2;
import org.objectteams.ILiftingParticipant;
import org.objectteams.ITeam;
@@ -41,7 +40,7 @@
public final static String OBJECT_SLASH = Object.class.getName().replace('.', '/');
public final static String CLASS_SLASH = Class.class.getName().replace('.', '/');
public final static String I_BOUND_BASE_DOT = IBoundBase2.class.getName();
- public final static String TEAM_MANAGER_SLASH = TeamManager.class.getName().replace('.', '/');
+ public final static String TEAM_MANAGER_SLASH = "org/eclipse/objectteams/otredyn/runtime/TeamManager"; // don't touch special class TeamManager, which is woven itself
public final static String ITEAM_SLASH = ITeam.class.getName().replace('.', '/');
public final static String TEAM_SLASH = Team.class.getName().replace('.', '/');
public final static String LIST_SLASH = List.class.getName().replace('.', '/');