Search code examples
javaverifyerror

What does the error message "Attempt to split long or double on the stack" indicate?


I am getting the following error from my code:

Attempt to split long or double on the stack

I am clueless about the origin of this error and do not know how to debug it. What kind of problem does this indicate? How can I fix it?

[ERROR]  [Mon May 23 14:29:46 IST 2011]   [(class: org/apache/jsp/dashboard_jsp, method: _jspService signature:     (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack]  [10.97.34.222] hddlntdsz2350  [ session not set ] 
java.lang.VerifyError: (class: org/apache/jsp/dashboard_jsp, method: _jspService signature: (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:273)

Problem Code : I have created a Model as given below

public class DashboardViewModel implements Serializable {

/** defalut serialization id */
private static final long serialVersionUID = 1L;

/**
 * Collection representing all the services
 */
private Map<Long, ServiceCustomerModel> serviceDataMap;

}

On a particular JSP page, I am doing following.

for (Long serviceId : dashboardViewModel.getServices()) {
           Service service = dashboardViewModel.getService(serviceId);
}

The getServices method in the above target class is as follows.

public Set<Long> getServices() {
    return this.serviceDataMap.keySet();
}

When including the above code in jsp. I do get the error. Otherwise, it works.

Further Investigataions :

I have updated the dashboard.jsp file with the following code snippet. I am not able to identify why, But this code is working.

ArrayList<Long> test = new ArrayList<Long>();
test.addAll(dashboardViewModel.getServices());
for (long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}

Does this code makes any difference to the data?


Solution

  • The Java virtual machine performs additional verification on operations involving long and double data types, for the very simple reason that

    A value of type long or type double occupies two consecutive local variables. Such a value may only be addressed using the lesser index. For example, a value of type double stored in the local variable array at index n actually occupies the local variables with indices n and n +1; however, the local variable at index n +1 cannot be loaded from. It can be stored into. However, doing so invalidates the contents of local variable n.

    When the verifier determines that an incorrect instruction is used to access a long or a double variable (say, an instruction that attempts to treat the local variable at index n, as an integer or a float, which splits the double/long variable), then the said error is flagged.

    Not a lot can be done in this case, except to fix the bytecode generator that generated this byte code. This may be the Java compiler itself, or any of the byte code manipulation frameworks like ASM, cglib or Javassist.

    Edit:

    After viewing the stacktrace, it appears that the class in question happens to be a generated servlet (from dashboard.jsp). It would be worthwhile to check if an upgrade of the JDK involving compilation of the translated JSP will resolve the issue.