Ok, I figured it out. This seems to be a serious bug in the dalvik
bytecode verifier being overzealous, since it runs fine in every other
JVM.

In the function calcMultiRange() shown above, if you assign "prevRange
= range" instead of null on the 5 line, the verify error goes away.
>From a control flow perspective, the array dereference in the else
clause (prevRange[prevIndex]) will never be an NPE because the else
clause won't execute until the second iteration of the for-loop, in
which cause the prevRange variable will not be null. Even more
bizarrely, the verify error occurs if compiled with javac, but not if
compiled via JDT in Eclipse Ganymede.

This is a kind of heisenbug, in that it can show up in perfectly
reasonable looking code, that passes all unit tests with 100%
coverage, but bite you when you deploy, and the diagnostics produced
in logcat don't make it easy to track down the problem. I tracked it
down myself by selectively commenting out parts of the function until
I zeroed into the prevRange deference.

-Ray


On Oct 28, 5:45 pm, Ray Cromwell <[EMAIL PROTECTED]> wrote:
> Hi all,
>   I'm having a strange issue where if I compile my class files with
> Eclipse ADT, my app works, but if I compile it using javac, I get a
> VerifyError. Here's what logcat says:
>
> /ActivityManager(   53): Start proc com.timefire.timescope.android for
> activity com.timefire.timescope.android/.ChronoscopeActivity: pid=464
> uid=10017 gids={}
> D/dalvikvm(  464): GC freed 749 objects / 58208 bytes in 51ms
> D/dalvikvm(  464): GC freed 74 objects / 12304 bytes in 40ms
> W/dalvikvm(  464): VFY: register2 v8-9 values 0,4
> W/dalvikvm(  464): VFY: register2 v10-11 values 0,0
> W/dalvikvm(  464): VFY:  rejecting opcode 0x6e at 0x002b
> W/dalvikvm(  464): VFY:  rejected Lorg/timepedia/chronoscope/client/
> data/DefaultMipMapStrategy;.calcMultiRange ([D)Lorg/timepedia/
> chronoscope/client/data/Array2D;
> W/dalvikvm(  464): Verifier rejected class Lorg/timepedia/chronoscope/
> client/data/DefaultMipMapStrategy;
> D/AndroidRuntime(  464): Shutting down VM
> W/dalvikvm(  464): threadid=3: thread exiting with uncaught exception
> (group=0x40010e28)
> E/AndroidRuntime(  464): Uncaught handler: thread main exiting due to
> uncaught exception
> E/AndroidRuntime(  464): java.lang.VerifyError:
> org.timepedia.chronoscope.client.data.DefaultMipMapStrategy
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.data.DatasetRequest.<init>(DatasetRequest. 
> java:
> 81)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.data.DatasetRequest
> $Basic.<init>(DatasetRequest.java:22)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.data.mock.MockDatasetFactory.getBasicDatas 
> et(MockDatasetFactory.java:
> 42)
> E/AndroidRuntime(  464):        at
> com.timefire.timescope.android.ChronoscopeActivity$SampleView
> $1.onViewReady(ChronoscopeActivity.java:63)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.canvas.View.allCanvasReady(View.java:
> 283)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.canvas.View$1.onCanvasReady(View.java:
> 203)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.canvas.Canvas.attach(Canvas.java:38)
> E/AndroidRuntime(  464):        at
> com.timefire.timescope.android.AndroidCanvas.attach(AndroidCanvas.java:
> 121)
> E/AndroidRuntime(  464):        at
> org.timepedia.chronoscope.client.canvas.View.onAttach(View.java:193)
> E/AndroidRuntime(  464):        at
> com.timefire.timescope.android.ChronoscopeActivity
> $SampleView.onLayout(ChronoscopeActivity.java:79)
> E/AndroidRuntime(  464):        at android.view.View.layout(View.java:5637)
> E/AndroidRuntime(  464):        at
> android.widget.FrameLayout.onLayout(FrameLayout.java:294)
> E/AndroidRuntime(  464):        at android.view.View.layout(View.java:5637)
> E/AndroidRuntime(  464):        at
> android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
> E/AndroidRuntime(  464):        at
> android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
> E/AndroidRuntime(  464):        at
> android.widget.LinearLayout.onLayout(LinearLayout.java:920)
> E/AndroidRuntime(  464):        at android.view.View.layout(View.java:5637)
> E/AndroidRuntime(  464):        at
> android.widget.FrameLayout.onLayout(FrameLayout.java:294)
> E/AndroidRuntime(  464):        at android.view.View.layout(View.java:5637)
> E/AndroidRuntime(  464):        at
> android.view.ViewRoot.performTraversals(ViewRoot.java:771)
> E/AndroidRuntime(  464):        at
> android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
> E/AndroidRuntime(  464):        at
> android.os.Handler.dispatchMessage(Handler.java:88)
> E/AndroidRuntime(  464):        at android.os.Looper.loop(Looper.java:123)
> E/AndroidRuntime(  464):        at
> android.app.ActivityThread.main(ActivityThread.java:3742)
> E/AndroidRuntime(  464):        at
> java.lang.reflect.Method.invokeNative(Native Method)
> E/AndroidRuntime(  464):        at
> java.lang.reflect.Method.invoke(Method.java:515)
> E/AndroidRuntime(  464):        at com.android.internal.os.ZygoteInit
> $MethodAndArgsCaller.run(ZygoteInit.java:739)
> E/AndroidRuntime(  464):        at
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
> E/AndroidRuntime(  464):        at dalvik.system.NativeStart.main(Native
> Method)
>
> Here's the offending method:
> public Array2D calcMultiRange(double[] range) {
>     ArgChecker.isGT(range.length, 0, "range.length");
>     int numSamples = range.length;
>     int numLevels = calcNumLevels(numSamples);
>     double[][] multiRange = new double[numLevels][];
>     double[] prevRange = null;
>
>     for (int level = 0; level < numLevels; level++) {
>       double[] currRange = new double[numSamples];
>       if (level == 0) {
>         for (int i = 0; i < numSamples; i++) {
>           currRange[i] = range[i];
>         }
>       } else {
>         for (int i = 0; i < numSamples; i++) {
>           int prevIndex = i * 2;
>           currRange[i] = calcRangeValue(prevRange[prevIndex],
>               prevRange[prevIndex + 1]);
>         }
>       }
>
>       multiRange[level] = currRange;
>       prevRange = currRange;
>       numSamples /= 2;
>     }
>
>     return new JavaArray2D(multiRange);
>   }
>
> Which is triggered by this initializer is another class:
>   private MipMapStrategy defaultMipMapStrategy =
> DefaultMipMapStrategy.MEAN;
>
> Changing to constructor based initialization changes nothing. I also
> stubbed out the calcMultiRange() method to return null, and still got
> the same error. There are no missing classes as far as I can tell.
>
> Anyway else hit this issue? The workaround (for me) it to have ant/
> maven compile using Eclipse or Jikes.
>
> -Ray
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to