Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2012-06

Android SDK's DX reports that a local is invalid

5 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Sven Barth

Hello together and especially hello Jonas,

I'm currently playing around with Android again. Mostly to implement a backup/restore procedure for my TrainLog application as I want to update my device (official ICS update, yippieh!) and don't plan to lose all my collected train counts...

Nevertheless I added a routine to my application, but when I try to "dx" the generated class file I get an error about an invalid locale.

Here is the offending method (extracted, but error is reproduceable) [it's based on Java code mentioned here:
http://stackoverflow.com/a/6542214 ]:

=== unit begin ===

unit Test;
{$mode objfpc}{$H+}
{$modeswitch unicodestrings}
interface
uses
   AndroidR14;
type
   TTest = class
   private
     procedure CopyFile(aSrc, aDest: JIFile);
   end;
implementation
procedure TTest.CopyFile(aSrc, aDest: JIFile);
var
   outstr: JIFileOutputStream;
   instr: JIFileInputStream;
   outchannel, inchannel: JNCFileChannel;
begin
   outstr := JIFileOutputStream.Create(aDest);
   instr := JIFileInputStream.Create(aSrc);
   try
     inchannel := instr.getChannel;
     outchannel := outstr.getChannel;
     inchannel.transferTo(0, inchannel.size, outchannel as
JNCWritableByteChannel);
   finally
     try
       if Assigned(inchannel) then
         inchannel.close;
     finally
       if Assigned(outchannel) then
         outchannel.close;
     end;
   end;
end;
end.

=== unit end ===

The output of "dx" when called with "--dex --output=classes.dex lib/" (where lib is the directory I set for FPC's "-FE" option) is the following:

=== output begin ===

EXCEPTION FROM SIMULATION:
local 0006: invalid

...at bytecode offset 00000092
locals[0000]: LTTest;
locals[0001]: Ljava/io/File;
locals[0002]: Ljava/io/File;
locals[0003]: Ljava/io/FileOutputStream;
locals[0004]: Ljava/io/FileInputStream;
locals[0005]: <invalid>
locals[0006]: <invalid>
locals[0007]: Ljava/lang/Object;
locals[0008]: <invalid>
locals[0009]: <invalid>
locals[000a]: <invalid>
locals[000b]: <invalid>
locals[000c]: type{java.lang.Object}
locals[000d]: <invalid>
locals[000e]: <invalid>
locals[000f]: <invalid>
...while working on block 0092
...while working on method CopyFile:(Ljava/io/File;Ljava/io/File;)V ...while processing CopyFile (Ljava/io/File;Ljava/io/File;)V ...while processing TTest.class

1 error; aborting

=== output end ===

I'm using revision 21737 (pretty up to date ^^)

Regards,
Sven

Reply by email

Sven Barth
to Sven Barth
Sven Barth wrote 98 lines
Hello together and especially hello Jonas, I'm currently playing around with Android again. Mostly to implement a backup/restore procedure for my TrainLog application as I want to update my device (official ICS update, yippieh!) and don't plan to lose all my collected train counts... Nevertheless I added a routine to my application, but when I try to "dx" the generated class file I get an error about an invalid locale. Here is the offending method (extracted, but error is reproduceable) [it's based on Java code mentioned here: http://stackoverflow.com/a/6542214 ]: === unit begin === unit Test; {$mode objfpc}{$H+} {$modeswitch unicodestrings} interface uses AndroidR14; type TTest = class private procedure CopyFile(aSrc, aDest: JIFile); end; implementation procedure TTest.CopyFile(aSrc, aDest: JIFile); var outstr: JIFileOutputStream; instr: JIFileInputStream; outchannel, inchannel: JNCFileChannel; begin outstr := JIFileOutputStream.Create(aDest); instr := JIFileInputStream.Create(aSrc); try inchannel := instr.getChannel; outchannel := outstr.getChannel; inchannel.transferTo(0, inchannel.size, outchannel as JNCWritableByteChannel); finally try if Assigned(inchannel) then inchannel.close; finally if Assigned(outchannel) then outchannel.close; end; end; end; end. === unit end === The output of "dx" when called with "--dex --output=classes.dex lib/" (where lib is the directory I set for FPC's "-FE" option) is the following: === output begin === EXCEPTION FROM SIMULATION: local 0006: invalid ...at bytecode offset 00000092 locals[0000]: LTTest; locals[0001]: Ljava/io/File; locals[0002]: Ljava/io/File; locals[0003]: Ljava/io/FileOutputStream; locals[0004]: Ljava/io/FileInputStream; locals[0005]: <invalid> locals[0006]: <invalid> locals[0007]: Ljava/lang/Object; locals[0008]: <invalid> locals[0009]: <invalid> locals[000a]: <invalid> locals[000b]: <invalid> locals[000c]: type{java.lang.Object} locals[000d]: <invalid> locals[000e]: <invalid> locals[000f]: <invalid> ...while working on block 0092 ...while working on method CopyFile:(Ljava/io/File;Ljava/io/File;)V ...while processing CopyFile (Ljava/io/File;Ljava/io/File;)V ...while processing TTest.class 1 error; aborting === output end === I'm using revision 21737 (pretty up to date ^^)

Update: It seems that dx dislikes the nested "try ... finally ... end" block inside the outer's block "finally ... end".

Regards,
Sven

Reply by email

Sven Barth
to Sven Barth
Sven Barth wrote 103 lines
On 30.06.2012 16:34, Sven Barth wrote: > Hello together and especially hello Jonas, > > I'm currently playing around with Android again. Mostly to implement a > backup/restore procedure for my TrainLog application as I want to update > my device (official ICS update, yippieh!) and don't plan to lose all my > collected train counts... > > Nevertheless I added a routine to my application, but when I try to "dx" > the generated class file I get an error about an invalid locale. > > Here is the offending method (extracted, but error is reproduceable) > [it's based on Java code mentioned here: > http://stackoverflow.com/a/6542214 ]: > > === unit begin === > > unit Test; > > {$mode objfpc}{$H+} > {$modeswitch unicodestrings} > > interface > > uses > AndroidR14; > > type > TTest = class > private > procedure CopyFile(aSrc, aDest: JIFile); > end; > > implementation > > procedure TTest.CopyFile(aSrc, aDest: JIFile); > var > outstr: JIFileOutputStream; > instr: JIFileInputStream; > outchannel, inchannel: JNCFileChannel; > begin > outstr := JIFileOutputStream.Create(aDest); > instr := JIFileInputStream.Create(aSrc); > > try > inchannel := instr.getChannel; > outchannel := outstr.getChannel; > inchannel.transferTo(0, inchannel.size, outchannel as > JNCWritableByteChannel); > finally > try > if Assigned(inchannel) then > inchannel.close; > finally > if Assigned(outchannel) then > outchannel.close; > end; > end; > end; > > end. > > === unit end === > > The output of "dx" when called with "--dex --output=classes.dex lib/" > (where lib is the directory I set for FPC's "-FE" option) is the > following: > > === output begin === > > EXCEPTION FROM SIMULATION: > local 0006: invalid > > ...at bytecode offset 00000092 > locals[0000]: LTTest; > locals[0001]: Ljava/io/File; > locals[0002]: Ljava/io/File; > locals[0003]: Ljava/io/FileOutputStream; > locals[0004]: Ljava/io/FileInputStream; > locals[0005]: <invalid> > locals[0006]: <invalid> > locals[0007]: Ljava/lang/Object; > locals[0008]: <invalid> > locals[0009]: <invalid> > locals[000a]: <invalid> > locals[000b]: <invalid> > locals[000c]: type{java.lang.Object} > locals[000d]: <invalid> > locals[000e]: <invalid> > locals[000f]: <invalid> > ...while working on block 0092 > ...while working on method CopyFile:(Ljava/io/File;Ljava/io/File;)V > ...while processing CopyFile (Ljava/io/File;Ljava/io/File;)V > ...while processing TTest.class > > 1 error; aborting > > === output end === > > I'm using revision 21737 (pretty up to date ^^) Update: It seems that dx dislikes the nested "try ... finally ... end" block inside the outer's block "finally ... end".

Correction: even without the nested try-finally, but with within it moved to the outer finally-end the error still occurs. So it seems that there is some problem with the code generated for the finally block...

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth: Hello together and especially hello Jonas, I'm currently playing around with Android…
Sven Barth wrote 23 lines
procedure TTest.CopyFile(aSrc, aDest: JIFile); var outstr: JIFileOutputStream; instr: JIFileInputStream; outchannel, inchannel: JNCFileChannel; begin outstr := JIFileOutputStream.Create(aDest); instr := JIFileInputStream.Create(aSrc); try inchannel := instr.getChannel; outchannel := outstr.getChannel; inchannel.transferTo(0, inchannel.size, outchannel as JNCWritableByteChannel); finally try if Assigned(inchannel) then inchannel.close; finally if Assigned(outchannel) then outchannel.close; end; end; end;

The problem is that Android (and the JVM) assume that it's possible that an exception occurs inside instr.getChannel. In that case, inchannel will not be initialized inside the finally block, and you're not allowed to use any potentially uninitialized data. So you have to explicitly set inchannel and outchannel to nil before the first try-block.

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 28 lines
On 30 Jun 2012, at 16:34, Sven Barth wrote: > procedure TTest.CopyFile(aSrc, aDest: JIFile); > var > outstr: JIFileOutputStream; > instr: JIFileInputStream; > outchannel, inchannel: JNCFileChannel; > begin > outstr := JIFileOutputStream.Create(aDest); > instr := JIFileInputStream.Create(aSrc); > > try > inchannel := instr.getChannel; > outchannel := outstr.getChannel; > inchannel.transferTo(0, inchannel.size, outchannel as JNCWritableByteChannel); > finally > try > if Assigned(inchannel) then > inchannel.close; > finally > if Assigned(outchannel) then > outchannel.close; > end; > end; > end; The problem is that Android (and the JVM) assume that it's possible that an exception occurs inside instr.getChannel. In that case, inchannel will not be initialized inside the finally block, and you're not allowed to use any potentially uninitialized data. So you have to explicitly set inchannel and outchannel to nil before the first try-block.

Aha! That explains and solves the problem. Thank you.

Regards,
Sven

Reply by email