2

When you access an own instance field via the this reference (for example, an object or int field from a private method), the generated Android Dalvik bytecode will contain an iget bytecode instruction:

iget v2, p0, Lcom/example/myapp/MyClass;->status:I

This is the same instruction which is emitted when you access another object's field (i.e. not via the this pointer), so it doesn't seem to distinguish between other objects and yourself. In bytecode, this is understandable, but the JIT could do more.

Checking the Android source code, I don't see that the null check is automatically eliminated by the JIT for such cases (i.e. when you access this). It is eliminated in basic blocks for already-null-checked Dalvik registers, fine, but (to me) it seems it could also be eliminated for the this access (even if it's the first instruction of a basic block, or any instruction, as this cannot be null).

What am I missing? Is it for security/runtime typesafety reasons? Or I simply overlook the source code? Why cannot the VM (JIT) handle this in a distinguished way? (I understand native code obviously can't, because this is a memory address just like anything else.)


EDIT: as far as I can see, "already-null-checked" flags are cleared each time a basic block ends in the dvm. What I'm saying is that the "already-null-checked" flag for registers which hold this could be pre-set to 1 (and the value would not need to be cleared even during transitions between basic blocks).

Thomas Calc
  • 2,994
  • 3
  • 30
  • 56

1 Answers1

1

From the bytecode's perspective, accessing fields on the "this" object is no different than accessing them on any other object - you still have to pass in a register that contains the "this" reference. Since there's no way to guarantee that the register being passed in will actually contain a non-null value, it still has to perform the nullness check, just like for any other object.

JesusFreke
  • 19,784
  • 5
  • 65
  • 68
  • I understand, but the JIT, on the other hand, knows a lot more stuff. It does many optimizations (like redundant null check elimination), so I wonder why it can't just set by default the "null-checked-already" flag for the Dalvik register of *this*. – Thomas Calc Apr 20 '13 at 02:09
  • There is no single "this" register - except upon on method entry. You can assign a different value to that register, or copy/move the this reference to a different register, etc. – JesusFreke Apr 20 '13 at 02:10
  • Yes, but the JIT generates the register allocations (during native code generation), so it will always know where the *this* pointer is stored at a given moment. What am I missing? – Thomas Calc Apr 20 '13 at 02:12
  • Well, what you could probably do would be to treat the initial "this" register the same as a null-checked register, which I think is what you're trying to get at. I'm not sure offhand how much analysis the JIT compiler does - i.e. if it propagates the nullness of a register when copying it. But it does seem reasonable to me to treat the initial "this" register as if it had been null-checked already. – JesusFreke Apr 20 '13 at 02:15
  • I mean, it knows exactly what value is stored in which register at every moment. Otherwise, it wouldn't be able to perform "redundant null-check elimination" -- because for that, it needs to know which registers were already null-checked somewhere in the same basic block. So, (in theory) it could "propagate" the non-nullness of this, yeah. – Thomas Calc Apr 20 '13 at 02:16
  • I mailed the designer of Dalvik (he is also on stackoverflow), hopefully we'll get an answer soon. I've just upvoted your answer, also as an appreciation for the useful discussion in comments. – Thomas Calc Apr 20 '13 at 02:24
  • Yeah, my original answer isn't as applicable, after better understanding your question :) – JesusFreke Apr 20 '13 at 03:46
  • 1
    @ThomasCalc Your analysis is probably right, my "probably" caveat being that I haven't actively worked on Dalvik for about two years. – danfuzz Apr 20 '13 at 19:39
  • Thanks, danfuzz. So you assume (unless it was added in the meantime) that there is a null check emitted for the *this* register as well? – Thomas Calc Apr 20 '13 at 20:07