11package datadog .trace .instrumentation .jetty9 ;
22
3+ import static java .lang .Math .max ;
4+ import static net .bytebuddy .jar .asm .Opcodes .ALOAD ;
5+ import static net .bytebuddy .jar .asm .Opcodes .ASTORE ;
6+ import static net .bytebuddy .jar .asm .Opcodes .DUP ;
7+ import static net .bytebuddy .jar .asm .Opcodes .F_SAME ;
8+ import static net .bytebuddy .jar .asm .Opcodes .GOTO ;
9+ import static net .bytebuddy .jar .asm .Opcodes .H_INVOKESTATIC ;
10+
311import datadog .context .Context ;
412import datadog .trace .api .gateway .Flow ;
513import datadog .trace .bootstrap .instrumentation .api .AgentSpan ;
1018import java .io .OutputStreamWriter ;
1119import java .util .ArrayList ;
1220import java .util .List ;
13- import java .util .function .Function ;
1421import net .bytebuddy .jar .asm .Handle ;
1522import net .bytebuddy .jar .asm .Label ;
1623import net .bytebuddy .jar .asm .MethodVisitor ;
8491 */
8592public class HandleVisitor extends MethodVisitor {
8693 private static final Logger log = LoggerFactory .getLogger (HandleVisitor .class );
94+ private static final int CONTEXT_VAR = 100 ;
8795
96+ /** Whether the next store is supposed to store the Context variable. */
8897 private boolean lookForStore ;
89- private int contextVar = -1 ;
98+ /** Whether the Context variable was stored to local index {@link #CONTEXT_VAR}. */
99+ private boolean contextStored ;
100+ /** Whether the handle() method injection was successful .*/
90101 private boolean success ;
91102 private final String methodName ;
92103
@@ -118,14 +129,22 @@ DelayCertainInsMethodVisitor delayVisitorDelegate() {
118129 return (DelayCertainInsMethodVisitor ) this .mv ;
119130 }
120131
132+ @ Override
133+ public void visitLocalVariable (String name , String descriptor , String signature , Label start , Label end , int index ) {
134+ if (contextStored && index == CONTEXT_VAR ) {
135+ super .visitLocalVariable ("context" , Type .getDescriptor (Context .class ), null , start , end , CONTEXT_VAR );
136+ }
137+ super .visitLocalVariable (name , descriptor , signature , start , end , index );
138+ }
139+
121140 @ Override
122141 public void visitMethodInsn (
123142 int opcode , String owner , String name , String descriptor , boolean isInterface ) {
124143 debug ("visitMethodInsn" );
125- debug (">> contextVar : " + contextVar );
144+ debug (">> contextStored : " + contextStored );
126145 debug (">> success: " + success );
127146 debug (">> opcode: " + opcode + ", owner: " + owner + ", name: " + name + ", descriptor: " + descriptor );
128- if (contextVar == - 1 ) {
147+ if (! contextStored ) {
129148 lookForStore =
130149 !lookForStore
131150 && opcode == Opcodes .INVOKEVIRTUAL
@@ -159,21 +178,21 @@ public void visitMethodInsn(
159178 // Declare label to insert after Server.handle() call
160179 Label afterHandle = new Label ();
161180 // Inject blocking helper call
162- super .visitVarInsn (Opcodes . ALOAD , 0 );
181+ super .visitVarInsn (ALOAD , 0 );
163182 super .visitMethodInsn (
164183 Opcodes .INVOKEVIRTUAL ,
165184 "org/eclipse/jetty/server/HttpChannel" ,
166185 "getRequest" ,
167186 "()Lorg/eclipse/jetty/server/Request;" ,
168187 false );
169- super .visitVarInsn (Opcodes . ALOAD , 0 );
188+ super .visitVarInsn (ALOAD , 0 );
170189 super .visitMethodInsn (
171190 Opcodes .INVOKEVIRTUAL ,
172191 "org/eclipse/jetty/server/HttpChannel" ,
173192 "getResponse" ,
174193 "()Lorg/eclipse/jetty/server/Response;" ,
175194 false );
176- super .visitVarInsn (Opcodes . ALOAD , contextVar );
195+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
177196 super .visitMethodInsn (
178197 Opcodes .INVOKESTATIC ,
179198 Type .getInternalName (JettyBlockingHelper .class ),
@@ -189,7 +208,7 @@ public void visitMethodInsn(
189208 super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
190209 // Inject label after Server.handle() call to jump here when blocked
191210 super .visitLabel (afterHandle );
192- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
211+ super .visitFrame (F_SAME , 0 , null , 0 , null );
193212 debug ("handle bytecode injected" );
194213 this .success = true ;
195214 return ;
@@ -224,48 +243,48 @@ public void visitMethodInsn(
224243 Label beforeRegularDispatch = new Label ();
225244 Label afterRegularDispatch = new Label ();
226245
227- super .visitVarInsn (Opcodes . ALOAD , contextVar );
246+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
228247 super .visitJumpInsn (Opcodes .IFNULL , beforeRegularDispatch );
229- super .visitVarInsn (Opcodes . ALOAD , contextVar );
248+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
230249 super .visitMethodInsn (
231250 Opcodes .INVOKEINTERFACE ,
232251 "datadog/trace/bootstrap/instrumentation/api/AgentSpan" ,
233252 "getRequestBlockingAction" ,
234253 "()" + Type .getDescriptor (Flow .Action .RequestBlockingAction .class ),
235254 true );
236255 super .visitJumpInsn (Opcodes .IFNONNULL , doBlockLabel );
237- super .visitJumpInsn (Opcodes . GOTO , beforeRegularDispatch );
256+ super .visitJumpInsn (GOTO , beforeRegularDispatch );
238257
239258 super .visitLabel (doBlockLabel );
240- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
259+ super .visitFrame (F_SAME , 0 , null , 0 , null );
241260 // dispatch with a Dispatchable created from JettyBlockingHelper::block
242261 // first set up the first two arguments to dispatch (this and DispatcherType.REQUEST)
243262 List <Runnable > loadThisAndEnum = new ArrayList <>(savedVisitations .subList (0 , 2 ));
244263 mv .commitVisitations (loadThisAndEnum );
245264 // set up the arguments to the method underlying the lambda (Request, Response,
246265 // RequestBlockingAction, AgentSpan)
247- super .visitVarInsn (Opcodes . ALOAD , 0 );
266+ super .visitVarInsn (ALOAD , 0 );
248267 super .visitMethodInsn (
249268 Opcodes .INVOKEVIRTUAL ,
250269 "org/eclipse/jetty/server/HttpChannel" ,
251270 "getRequest" ,
252271 "()Lorg/eclipse/jetty/server/Request;" ,
253272 false );
254- super .visitVarInsn (Opcodes . ALOAD , 0 );
273+ super .visitVarInsn (ALOAD , 0 );
255274 super .visitMethodInsn (
256275 Opcodes .INVOKEVIRTUAL ,
257276 "org/eclipse/jetty/server/HttpChannel" ,
258277 "getResponse" ,
259278 "()Lorg/eclipse/jetty/server/Response;" ,
260279 false );
261- super .visitVarInsn (Opcodes . ALOAD , contextVar );
280+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
262281 super .visitMethodInsn (
263282 Opcodes .INVOKEINTERFACE ,
264283 "datadog/trace/bootstrap/instrumentation/api/AgentSpan" ,
265284 "getRequestBlockingAction" ,
266285 "()" + Type .getDescriptor (Flow .Action .RequestBlockingAction .class ),
267286 true );
268- super .visitVarInsn (Opcodes . ALOAD , contextVar );
287+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
269288
270289 // create the lambda
271290 super .visitInvokeDynamicInsn (
@@ -275,15 +294,15 @@ public void visitMethodInsn(
275294 + Type .getDescriptor (AgentSpan .class )
276295 + ")Lorg/eclipse/jetty/server/HttpChannel$Dispatchable;" ,
277296 new Handle (
278- Opcodes . H_INVOKESTATIC ,
297+ H_INVOKESTATIC ,
279298 "java/lang/invoke/LambdaMetafactory" ,
280299 "metafactory" ,
281300 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" ,
282301 false ),
283302 new Object [] {
284303 Type .getType ("()V" ),
285304 new Handle (
286- Opcodes . H_INVOKESTATIC ,
305+ H_INVOKESTATIC ,
287306 Type .getInternalName (JettyBlockingHelper .class ),
288307 "blockAndThrowOnFailure" ,
289308 "(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;"
@@ -297,14 +316,14 @@ public void visitMethodInsn(
297316 // invoke the dispatch method
298317 super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
299318
300- super .visitJumpInsn (Opcodes . GOTO , afterRegularDispatch );
319+ super .visitJumpInsn (GOTO , afterRegularDispatch );
301320
302321 super .visitLabel (beforeRegularDispatch );
303- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
322+ super .visitFrame (F_SAME , 0 , null , 0 , null );
304323 mv .commitVisitations (savedVisitations );
305324 super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
306325 super .visitLabel (afterRegularDispatch );
307- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
326+ super .visitFrame (F_SAME , 0 , null , 0 , null );
308327 this .success = true ;
309328 return ;
310329 }
@@ -346,15 +365,23 @@ private boolean checkDispatchMethodState(final List<Runnable> savedVisitations)
346365
347366 @ Override
348367 public void visitVarInsn (int opcode , int varIndex ) {
349- if (lookForStore && opcode == Opcodes . ASTORE ) {
368+ if (lookForStore && opcode == ASTORE ) {
350369 debug ("Found context" );
351- contextVar = varIndex ;
370+ contextStored = true ;
352371 lookForStore = false ;
372+ // Duplicate on stack and store to its own local var
373+ super .visitInsn (DUP );
374+ super .visitVarInsn (ASTORE , CONTEXT_VAR );
353375 }
354-
355376 super .visitVarInsn (opcode , varIndex );
356377 }
357378
379+ @ Override
380+ public void visitMaxs (int maxStack , int maxLocals ) {
381+ debug ("VisitMaxs stack: " + maxStack + ", locals: " + maxLocals );
382+ super .visitMaxs (maxStack , max (maxLocals , CONTEXT_VAR + 1 ));
383+ }
384+
358385 @ Override
359386 public void visitEnd () {
360387 if (!success && !"run" .equals (methodName )) {
0 commit comments