0

Here is my sample java code.

package com.test;

import javax.servlet.http.HttpServletRequest;

public class TestASMIns
{
    public void process(HttpServletRequest request)
    {
        String userName;
        if(request.getParameterMap().containsKey("username"))
        {
            userName = request.getParameter("username");
        }
        else
        {
            userName = "UNKNOWN";
        }
        System.out.println(userName);
    }
}

In above example local variable userName declared inside of method body. AFAIK bytecode instruction for above code should contain only one LocalVariableNode for variable 'userName'(Since it is not declared within any inner scope/block). But bytecode instruction for LocalVariableTable contains duplicate entry for variable 'userName'. Can someone shed some light on this.

Here is the bytecode instructions: (generated using javap)

  public void process(javax.servlet.http.HttpServletRequest);
    descriptor: (Ljavax/servlet/http/HttpServletRequest;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=2
         0: aload_1
         1: invokeinterface #16,  1           // InterfaceMethod javax/servlet/http/HttpServletRequest.getParameterMap:()Ljava/util/Map;
         6: ldc           #22                 // String username
         8: invokeinterface #24,  2           // InterfaceMethod java/util/Map.containsKey:(Ljava/lang/Object;)Z
        13: ifeq          28
        16: aload_1
        17: ldc           #22                 // String username
        19: invokeinterface #30,  2           // InterfaceMethod javax/servlet/http/HttpServletRequest.getParameter:(Ljava/lang/String;)Ljava/lang/String;
        24: astore_2
        25: goto          31
        28: ldc           #34                 // String UNKNOWN
        30: astore_2
        31: getstatic     #36                 // Field java/lang/System.out:Ljava/io/PrintStream;
        34: aload_2
        35: invokevirtual #42                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        38: return
      LineNumberTable:
        line 10: 0
        line 12: 16
        line 13: 25
        line 16: 28
        line 18: 31
        line 19: 38
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      39     0  this   Lcom/test/TestASMIns;
            0      39     1 request   Ljavax/servlet/http/HttpServletRequest;
           25       3     2 userName   Ljava/lang/String;
           31       8     2 userName   Ljava/lang/String;
      StackMapTable: number_of_entries = 2
        frame_type = 28 /* same */
        frame_type = 252 /* append */
          offset_delta = 2
          locals = [ class java/lang/String ]
}
Parthi P
  • 65
  • 1
  • 8
  • 1
    A local variable is considered defined only in ranges of bytecodes where it has been assigned a value, i.e. is not uninitialized garbage. Since you didn't initialize it in the declaration, it is unassigned from 0 through 24, assigned at 25 (one instruction with length 3), unassigned from 28 through 30, and assigned from 31 through 38. – dave_thompson_085 Aug 10 '17 at 20:00
  • @dave_thompson_085 Thanks for the clarification. Tried initializing **String userName = null;** gives expected result. But i have one doubt. In above example the value initialized with if condition blocks should accessible till end of the method body right? i.e both **userName** LocalVariable should contain range through 38 right? Why if(true) block LocalVariable ends with index 30? – Parthi P Aug 11 '17 at 05:04
  • Reason has been explained here https://stackoverflow.com/questions/26632799/do-unused-local-variables-in-a-method-acquire-memory-in-jvm – Parthi P Aug 11 '17 at 16:53
  • 1
    At index `13`, there is a conditional jump `ifeq` to the location `28` that will be taken if `containsKey` returns `false`. If taken, there will be no valid value for `userName` yet. The instructions `28: ldc #34; 30: astore_2` are storing the constant string `"UNKNOWN"` to it so *after* the completion of the `astore_2` instruction, there will be a valid value. Therefore, for the range `[28 - 30]`, the variable has no valid value. But this is irrelevant to the used memory, as the slot number 2 will be reserved throughout the entire method execution whether containing a valid value or not. – Holger Sep 05 '17 at 15:31

0 Answers0