1
1
package datadog .trace .instrumentation .jetty9 ;
2
2
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
+
3
11
import datadog .context .Context ;
4
12
import datadog .trace .api .gateway .Flow ;
5
13
import datadog .trace .bootstrap .instrumentation .api .AgentSpan ;
10
18
import java .io .OutputStreamWriter ;
11
19
import java .util .ArrayList ;
12
20
import java .util .List ;
13
- import java .util .function .Function ;
14
21
import net .bytebuddy .jar .asm .Handle ;
15
22
import net .bytebuddy .jar .asm .Label ;
16
23
import net .bytebuddy .jar .asm .MethodVisitor ;
84
91
*/
85
92
public class HandleVisitor extends MethodVisitor {
86
93
private static final Logger log = LoggerFactory .getLogger (HandleVisitor .class );
94
+ private static final int CONTEXT_VAR = 100 ;
87
95
96
+ /** Whether the next store is supposed to store the Context variable. */
88
97
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 .*/
90
101
private boolean success ;
91
102
private final String methodName ;
92
103
@@ -118,14 +129,22 @@ DelayCertainInsMethodVisitor delayVisitorDelegate() {
118
129
return (DelayCertainInsMethodVisitor ) this .mv ;
119
130
}
120
131
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
+
121
140
@ Override
122
141
public void visitMethodInsn (
123
142
int opcode , String owner , String name , String descriptor , boolean isInterface ) {
124
143
debug ("visitMethodInsn" );
125
- debug (">> contextVar : " + contextVar );
144
+ debug (">> contextStored : " + contextStored );
126
145
debug (">> success: " + success );
127
146
debug (">> opcode: " + opcode + ", owner: " + owner + ", name: " + name + ", descriptor: " + descriptor );
128
- if (contextVar == - 1 ) {
147
+ if (! contextStored ) {
129
148
lookForStore =
130
149
!lookForStore
131
150
&& opcode == Opcodes .INVOKEVIRTUAL
@@ -159,21 +178,21 @@ public void visitMethodInsn(
159
178
// Declare label to insert after Server.handle() call
160
179
Label afterHandle = new Label ();
161
180
// Inject blocking helper call
162
- super .visitVarInsn (Opcodes . ALOAD , 0 );
181
+ super .visitVarInsn (ALOAD , 0 );
163
182
super .visitMethodInsn (
164
183
Opcodes .INVOKEVIRTUAL ,
165
184
"org/eclipse/jetty/server/HttpChannel" ,
166
185
"getRequest" ,
167
186
"()Lorg/eclipse/jetty/server/Request;" ,
168
187
false );
169
- super .visitVarInsn (Opcodes . ALOAD , 0 );
188
+ super .visitVarInsn (ALOAD , 0 );
170
189
super .visitMethodInsn (
171
190
Opcodes .INVOKEVIRTUAL ,
172
191
"org/eclipse/jetty/server/HttpChannel" ,
173
192
"getResponse" ,
174
193
"()Lorg/eclipse/jetty/server/Response;" ,
175
194
false );
176
- super .visitVarInsn (Opcodes . ALOAD , contextVar );
195
+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
177
196
super .visitMethodInsn (
178
197
Opcodes .INVOKESTATIC ,
179
198
Type .getInternalName (JettyBlockingHelper .class ),
@@ -189,7 +208,7 @@ public void visitMethodInsn(
189
208
super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
190
209
// Inject label after Server.handle() call to jump here when blocked
191
210
super .visitLabel (afterHandle );
192
- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
211
+ super .visitFrame (F_SAME , 0 , null , 0 , null );
193
212
debug ("handle bytecode injected" );
194
213
this .success = true ;
195
214
return ;
@@ -224,48 +243,48 @@ public void visitMethodInsn(
224
243
Label beforeRegularDispatch = new Label ();
225
244
Label afterRegularDispatch = new Label ();
226
245
227
- super .visitVarInsn (Opcodes . ALOAD , contextVar );
246
+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
228
247
super .visitJumpInsn (Opcodes .IFNULL , beforeRegularDispatch );
229
- super .visitVarInsn (Opcodes . ALOAD , contextVar );
248
+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
230
249
super .visitMethodInsn (
231
250
Opcodes .INVOKEINTERFACE ,
232
251
"datadog/trace/bootstrap/instrumentation/api/AgentSpan" ,
233
252
"getRequestBlockingAction" ,
234
253
"()" + Type .getDescriptor (Flow .Action .RequestBlockingAction .class ),
235
254
true );
236
255
super .visitJumpInsn (Opcodes .IFNONNULL , doBlockLabel );
237
- super .visitJumpInsn (Opcodes . GOTO , beforeRegularDispatch );
256
+ super .visitJumpInsn (GOTO , beforeRegularDispatch );
238
257
239
258
super .visitLabel (doBlockLabel );
240
- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
259
+ super .visitFrame (F_SAME , 0 , null , 0 , null );
241
260
// dispatch with a Dispatchable created from JettyBlockingHelper::block
242
261
// first set up the first two arguments to dispatch (this and DispatcherType.REQUEST)
243
262
List <Runnable > loadThisAndEnum = new ArrayList <>(savedVisitations .subList (0 , 2 ));
244
263
mv .commitVisitations (loadThisAndEnum );
245
264
// set up the arguments to the method underlying the lambda (Request, Response,
246
265
// RequestBlockingAction, AgentSpan)
247
- super .visitVarInsn (Opcodes . ALOAD , 0 );
266
+ super .visitVarInsn (ALOAD , 0 );
248
267
super .visitMethodInsn (
249
268
Opcodes .INVOKEVIRTUAL ,
250
269
"org/eclipse/jetty/server/HttpChannel" ,
251
270
"getRequest" ,
252
271
"()Lorg/eclipse/jetty/server/Request;" ,
253
272
false );
254
- super .visitVarInsn (Opcodes . ALOAD , 0 );
273
+ super .visitVarInsn (ALOAD , 0 );
255
274
super .visitMethodInsn (
256
275
Opcodes .INVOKEVIRTUAL ,
257
276
"org/eclipse/jetty/server/HttpChannel" ,
258
277
"getResponse" ,
259
278
"()Lorg/eclipse/jetty/server/Response;" ,
260
279
false );
261
- super .visitVarInsn (Opcodes . ALOAD , contextVar );
280
+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
262
281
super .visitMethodInsn (
263
282
Opcodes .INVOKEINTERFACE ,
264
283
"datadog/trace/bootstrap/instrumentation/api/AgentSpan" ,
265
284
"getRequestBlockingAction" ,
266
285
"()" + Type .getDescriptor (Flow .Action .RequestBlockingAction .class ),
267
286
true );
268
- super .visitVarInsn (Opcodes . ALOAD , contextVar );
287
+ super .visitVarInsn (ALOAD , CONTEXT_VAR );
269
288
270
289
// create the lambda
271
290
super .visitInvokeDynamicInsn (
@@ -275,15 +294,15 @@ public void visitMethodInsn(
275
294
+ Type .getDescriptor (AgentSpan .class )
276
295
+ ")Lorg/eclipse/jetty/server/HttpChannel$Dispatchable;" ,
277
296
new Handle (
278
- Opcodes . H_INVOKESTATIC ,
297
+ H_INVOKESTATIC ,
279
298
"java/lang/invoke/LambdaMetafactory" ,
280
299
"metafactory" ,
281
300
"(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;" ,
282
301
false ),
283
302
new Object [] {
284
303
Type .getType ("()V" ),
285
304
new Handle (
286
- Opcodes . H_INVOKESTATIC ,
305
+ H_INVOKESTATIC ,
287
306
Type .getInternalName (JettyBlockingHelper .class ),
288
307
"blockAndThrowOnFailure" ,
289
308
"(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;"
@@ -297,14 +316,14 @@ public void visitMethodInsn(
297
316
// invoke the dispatch method
298
317
super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
299
318
300
- super .visitJumpInsn (Opcodes . GOTO , afterRegularDispatch );
319
+ super .visitJumpInsn (GOTO , afterRegularDispatch );
301
320
302
321
super .visitLabel (beforeRegularDispatch );
303
- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
322
+ super .visitFrame (F_SAME , 0 , null , 0 , null );
304
323
mv .commitVisitations (savedVisitations );
305
324
super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
306
325
super .visitLabel (afterRegularDispatch );
307
- super .visitFrame (Opcodes . F_SAME , 0 , null , 0 , null );
326
+ super .visitFrame (F_SAME , 0 , null , 0 , null );
308
327
this .success = true ;
309
328
return ;
310
329
}
@@ -346,15 +365,23 @@ private boolean checkDispatchMethodState(final List<Runnable> savedVisitations)
346
365
347
366
@ Override
348
367
public void visitVarInsn (int opcode , int varIndex ) {
349
- if (lookForStore && opcode == Opcodes . ASTORE ) {
368
+ if (lookForStore && opcode == ASTORE ) {
350
369
debug ("Found context" );
351
- contextVar = varIndex ;
370
+ contextStored = true ;
352
371
lookForStore = false ;
372
+ // Duplicate on stack and store to its own local var
373
+ super .visitInsn (DUP );
374
+ super .visitVarInsn (ASTORE , CONTEXT_VAR );
353
375
}
354
-
355
376
super .visitVarInsn (opcode , varIndex );
356
377
}
357
378
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
+
358
385
@ Override
359
386
public void visitEnd () {
360
387
if (!success && !"run" .equals (methodName )) {
0 commit comments