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('.', '/');