(Condy) Folded of local variables are still considered when calculating the max number of local vars of a method
Vicente Romero
vicente.romero at oracle.com
Tue Sep 4 13:18:27 UTC 2018
On 09/03/2018 06:40 AM, Maurizio Cimadamore wrote:
>
>
> On 02/09/18 19:02, Brian Goetz wrote:
>> It sounds like the dead-code elimination is done after we construct
>> the LV tables?
> I think the issue is that, for javac, the local variable still exists
> (e.g. there's a LocalItem for it), it is just never loaded, so you
> never see it in the resulting code. But that means that it will be
> taken into account when generating local var slots number (**).
>
> In a way, javac doesn't actively perform any dead code elimination -
> it's the turning of all variable initializer into constants (which are
> dealt with by ldc) which turns code generation lazy, meaning that bits
> will only be generated when needed. So, the resulting code gives you
> the feeling of dead code elimination, but in reality there is no piece
> of code where javac says: it's ok to ditch this local variable. In
> other word, DCE is an emergent property of the way in which we lazily
> generate code.
>
> You can reproduce a similar behavior with this Java program which only
> involves string constants:
>
> class Test {
> static foo() {
> String hello = "Hello!";
> }
> }
>
> This gives:
>
>
> static void foo();
> descriptor: ()V
> flags: ACC_STATIC
> Code:
> stack=0, *locals=1,* args_size=0
> 0: return
> LineNumberTable:
> line 4: 0
>
>
> (**) I thought that debug info (e.g. LocalVariableTable) would be
> affected too, but in reality when debug info is enabled, const folding
> is disabled for var initializer - and the enhanced condy folding
> support respects that invariant, so nothing to look at there.
>
> In order to get rid of this behavior we would need to look at avoiding
> the call to code.newLocal in Gen::visitVarDef:
>
> public void visitVarDef(JCVariableDecl tree) {
> VarSymbol v = tree.sym;
> code.newLocal(v); // <----------------------
> if (tree.init != null) {
> checkStringConstant(tree.init.pos(), v.getConstValue());
> if (v.getConstValue() == null || varDebugInfo) {
> Assert.check(code.isStatementStart());
> genExpr(tree.init, v.erasure(types)).load();
> items.makeLocalItem(v).store();
> Assert.check(code.isStatementStart());
> }
> }
> checkDimension(tree.pos(), v.type);
> }
>
>
> As that is what's updating the compiler internal state. In principle,
> if a variable holds a constant value, then javac will always load that
> constant value instead of loading the variable, see Gen::gnExpr:
>
> if (tree.type.constValue() != null) {
> // Short circuit any expressions which are constants
> tree.accept(classReferenceVisitor);
> checkStringConstant(tree.pos(), tree.type.constValue());
> result = items.makeImmediateItem(tree.type,
> tree.type.constValue());
> } else {
> this.pt = pt;
> tree.accept(this);
> }
>
> But maybe there are other cases/invariants that would be broken by
> skipping the Code::newLocal call entirely - this means we'll have to
> do some experiments with the code in order to rectify this. As you can
> see, this problem is a general problem with constant folding, and is
> not something specific to the Amber condy-folding branch (although I
> agree that the new support magnifies the problem quite a bit).
I will be doing some experiments to check if there are side effects from
removing the call to Code::newLocal
>
> Cheers
> Maurizio
Vicente
>>
>> On 9/2/2018 1:58 PM, Remi Forax wrote:
>>> Hi all,
>>> while trying to reproduce a bug in ASM using the constant API +
>>> Intrinsics.ldc, i've spot a discrepancy,
>>> using the follwing example,
>>>
>>> package jdk12;
>>>
>>> import java.lang.constant.ClassDesc;
>>> import java.lang.constant.DirectMethodHandleDesc.Kind;
>>> import java.lang.constant.DynamicConstantDesc;
>>> import java.lang.constant.MethodHandleDesc;
>>> import java.lang.constant.MethodTypeDesc;
>>> import java.lang.invoke.Intrinsics;
>>> import java.lang.invoke.MethodHandles.Lookup;
>>>
>>> public class ConstantDynamicExample {
>>> public static long primitiveExample() {
>>> MethodTypeDesc methodDescriptor =
>>> MethodTypeDesc.ofDescriptor("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)J");
>>> DynamicConstantDesc<Long> dynamicConstant =
>>> DynamicConstantDesc.of(
>>> MethodHandleDesc.of(Kind.STATIC,
>>> ClassDesc.of("jdk12.ConstantDynamicExample"), "bsm",
>>> methodDescriptor));
>>> return Intrinsics.ldc(dynamicConstant);
>>> }
>>>
>>> private static long bsm(Lookup lookup, String name, Class<?> type) {
>>> return 3L;
>>> }
>>> public static void main(String[] args) {
>>> System.out.println(primitiveExample());
>>> }
>>> }
>>>
>>>
>>> Using javap, you can see that the dynamicConstant is folded but the
>>> number of local variable (locals=2) still count the variables that
>>> doesn't exist anymore
>>>
>>> public static long primitiveExample();
>>> descriptor: ()J
>>> flags: (0x0009) ACC_PUBLIC, ACC_STATIC
>>> Code:
>>> stack=2, locals=2, args_size=0
>>> 0: ldc2_w #2 // Dynamic #0:_:J
>>> 3: lreturn
>>> LineNumberTable:
>>> line 43: 0
>>>
>>> regards,
>>> Rémi
>>
>
More information about the amber-dev
mailing list