private static MemberDefinition getClassLiteralCache(Environment env, Context ctx, String className, ClassDefinition c) { // Given a class name, look for a static field to cache it. // className lname // pkg.Foo class$pkg$Foo // [Lpkg.Foo; array$Lpkg$Foo // [[Lpkg.Foo; array$$Lpkg$Foo // [I array$I // [[I array$$I String lname; if (!className.startsWith(SIG_ARRAY)) { lname = prefixClass + className.replace('.', '$'); } else { lname = prefixArray + className.substring(1); lname = lname.replace(SIGC_ARRAY, '$'); // [[[I => array$$$I if (className.endsWith(SIG_ENDCLASS)) { // [Lpkg.Foo; => array$Lpkg$Foo lname = lname.substring(0, lname.length() - 1); lname = lname.replace('.', '$'); } // else [I => array$I or some such; lname is already OK } Identifier fname = Identifier.lookup(lname); // The class to put the cache in is now given as an argument. // // ClassDefinition c = ctx.field.getClassDefinition(); // while (c.isInnerClass()) { // c = c.getOuterClass(); MemberDefinition cfld; try { cfld = c.getVariable(env, fname, c); } catch (ClassNotFound ee) { return null; } catch (AmbiguousMember ee) { return null; } // Ignore inherited field. Each top-level class // containing a given class literal must have its own copy, // both for reasons of binary compatibility and to prevent // access violations should the superclass be in another // package. Part of fix 4106051. if (cfld != null && cfld.getClassDefinition() == c) { return cfld; } // Since each class now has its own copy, we might as well // tighten up the access to private (previously default). // Part of fix for 4106051. // ** Temporarily retract this, as it tickles 4098316. return env.makeMemberDefinition(env, c.getWhere(), c, null, M_STATIC | M_SYNTHETIC, // M_PRIVATE, Type.tClassDesc, fname, null, null, null); } private Expression makeClassLiteralCacheRef(Environment env, Context ctx, MemberDefinition lookup, MemberDefinition cfld, String className) { Expression ccls = new TypeExpression(where, cfld.getClassDefinition() .getType()); Expression cache = new FieldExpression(where, ccls, cfld); Expression cacheOK = new NotEqualExpression(where, cache.copyInline(ctx), new NullExpression(where)); Expression lcls = new TypeExpression(where, lookup.getClassDefinition() .getType()); Expression name = new StringExpression(where, className); Expression namearg[] = { name }; Expression setCache = new MethodExpression(where, lcls, lookup, namearg); setCache = new AssignExpression(where, cache.copyInline(ctx), setCache); return new ConditionalExpression(where, cacheOK, cache, setCache); } private Expression makeClassLiteralInlineRef(Environment env, Context ctx, MemberDefinition lookup, String className) { Expression lcls = new TypeExpression(where, lookup.getClassDefinition().getType()); Expression name = new StringExpression(where, className); Expression namearg[] = { name }; Expression getClass = new MethodExpression(where, lcls, lookup, namearg); return getClass; } /** * Check if constant: Will it inline away? */ public boolean isConstant() { if (implementation != null) return implementation.isConstant(); if ((field != null) && (right == null || right instanceof TypeExpression || (right.op == THIS && right.where == where))) { return field.isConstant(); } return false; } /** * Inline */ public Expression inline(Environment env, Context ctx) { if (implementation != null) return implementation.inline(env, ctx); // A field expression may have the side effect of causing // a NullPointerException, so evaluate it even though // the value is not needed. Similarly, static field dereferences // may cause class initialization, so they mustn't be omitted // either. // // However, NullPointerException can't happen and initialization must // already have occured if you are dotting into 'this'. So // allow fields of 'this' to be eliminated as a special case. Expression e = inlineValue(env, ctx); if (e instanceof FieldExpression) { FieldExpression fe = (FieldExpression) e; if ((fe.right != null) && (fe.right.op==THIS)) return null; // It should be possible to split this into two checks: one using // isNonNull() for non-statics and a different check for statics. // That would make the inlining slightly less conservative by // allowing, for example, dotting into String constants. } return e; } public Expression inlineValue(Environment env, Context ctx) { if (implementation != null) return implementation.inlineValue(env, ctx); try { if (field == null) { return this; } if (field.isFinal()) { Expression e = (Expression)field.getValue(env); if ((e != null) && e.isConstant()) { // remove bogus line-number info e = e.copyInline(ctx); e.where = where; return new CommaExpression(where, right, e).inlineValue(env, ctx); } } if (right != null) { if (field.isStatic()) { Expression e = right.inline(env, ctx); right = null; if (e != null) { return new CommaExpression(where, e, this); } } else { right = right.inlineValue(env, ctx); } } return this; } catch (ClassNotFound e) { throw new CompilerError(e); } } public Expression inlineLHS(Environment env, Context ctx) { if (implementation != null) return implementation.inlineLHS(env, ctx); if (right != null) { if (field.isStatic()) { Expression e = right.inline(env, ctx); right = null; if (e != null) { return new CommaExpression(where, e, this); } } else { right = right.inlineValue(env, ctx); } } return this; } public Expression copyInline(Context ctx) { if (implementation != null) return implementation.copyInline(ctx); return super.copyInline(ctx); } /** * The cost of inlining this expression */ public int costInline(int thresh, Environment env, Context ctx) { if (implementation != null) return implementation.costInline(thresh, env, ctx); if (ctx == null) { return 3 + ((right == null) ? 0 : right.costInline(thresh, env, ctx)); } // ctxClass is the current class trying to inline this method ClassDefinition ctxClass = ctx.field.getClassDefinition(); try { // We only allow the inlining if the current class can access // the field, the field's class, and right's declared type. if ( ctxClass.permitInlinedAccess(env, field.getClassDeclaration()) && ctxClass.permitInlinedAccess(env, field)) { if (right == null) { return 3; } else { ClassDeclaration rt = env.getClassDeclaration(right.type); if (ctxClass.permitInlinedAccess(env, rt)) { return 3 + right.costInline(thresh, env, ctx); } } } } catch (ClassNotFound e) { } return thresh; } /** * Code */ int codeLValue(Environment env, Context ctx, Assembler asm) { if (implementation != null) throw new CompilerError("codeLValue"); if (field.isStatic()) { if (right != null) { right.code(env, ctx, asm); return 1; } return 0; } right.codeValue(env, ctx, asm); return 1; } void codeLoad(Environment env, Context ctx, Assembler asm) { if (field == null) { throw new CompilerError("should not be null"); } if (field.isStatic()) { asm.add(where, opc_getstatic, field); } else { asm.add(where, opc_getfield, field); } } void codeStore(Environment env, Context ctx, Assembler asm) { if (field.isStatic()) { asm.add(where, opc_putstatic, field); } else { asm.add(where, opc_putfield, field); } } public void codeValue(Environment env, Context ctx, Assembler asm) { codeLValue(env, ctx, asm); codeLoad(env, ctx, asm); } /** * Print */ public void print(PrintStream out) { out.print("("); if (right != null) { right.print(out); } else { out.print("<empty>"); } out.print("." + id + ")"); if (implementation != null) { out.print("/IMPL="); implementation.print(out); } }}Lines 1001–1282 of 1282. Previous lines
private static MemberDefinition getClassLiteralCache(Environment env, Context ctx, String className, ClassDefinition c) { // Given a class name, look for a static field to cache it. // className lname // pkg.Foo class$pkg$Foo // [Lpkg.Foo; array$Lpkg$Foo // [[Lpkg.Foo; array$$Lpkg$Foo // [I array$I // [[I array$$I String lname; if (!className.startsWith(SIG_ARRAY)) { lname = prefixClass + className.replace('.', '$'); } else { lname = prefixArray + className.substring(1); lname = lname.replace(SIGC_ARRAY, '$'); // [[[I => array$$$I if (className.endsWith(SIG_ENDCLASS)) { // [Lpkg.Foo; => array$Lpkg$Foo lname = lname.substring(0, lname.length() - 1); lname = lname.replace('.', '$'); } // else [I => array$I or some such; lname is already OK } Identifier fname = Identifier.lookup(lname); // The class to put the cache in is now given as an argument. // // ClassDefinition c = ctx.field.getClassDefinition(); // while (c.isInnerClass()) { // c = c.getOuterClass(); MemberDefinition cfld; try { cfld = c.getVariable(env, fname, c); } catch (ClassNotFound ee) { return null; } catch (AmbiguousMember ee) { return null; } // Ignore inherited field. Each top-level class // containing a given class literal must have its own copy, // both for reasons of binary compatibility and to prevent // access violations should the superclass be in another // package. Part of fix 4106051. if (cfld != null && cfld.getClassDefinition() == c) { return cfld; } // Since each class now has its own copy, we might as well // tighten up the access to private (previously default). // Part of fix for 4106051. // ** Temporarily retract this, as it tickles 4098316. return env.makeMemberDefinition(env, c.getWhere(), c, null, M_STATIC | M_SYNTHETIC, // M_PRIVATE, Type.tClassDesc, fname, null, null, null); } private Expression makeClassLiteralCacheRef(Environment env, Context ctx, MemberDefinition lookup, MemberDefinition cfld, String className) { Expression ccls = new TypeExpression(where, cfld.getClassDefinition() .getType()); Expression cache = new FieldExpression(where, ccls, cfld); Expression cacheOK = new NotEqualExpression(where, cache.copyInline(ctx), new NullExpression(where)); Expression lcls = new TypeExpression(where, lookup.getClassDefinition() .getType()); Expression name = new StringExpression(where, className); Expression namearg[] = { name }; Expression setCache = new MethodExpression(where, lcls, lookup, namearg); setCache = new AssignExpression(where, cache.copyInline(ctx), setCache); return new ConditionalExpression(where, cacheOK, cache, setCache); } private Expression makeClassLiteralInlineRef(Environment env, Context ctx, MemberDefinition lookup, String className) { Expression lcls = new TypeExpression(where, lookup.getClassDefinition().getType()); Expression name = new StringExpression(where, className); Expression namearg[] = { name }; Expression getClass = new MethodExpression(where, lcls, lookup, namearg); return getClass; } /** * Check if constant: Will it inline away? */ public boolean isConstant() { if (implementation != null) return implementation.isConstant(); if ((field != null) && (right == null || right instanceof TypeExpression || (right.op == THIS && right.where == where))) { return field.isConstant(); } return false; } /** * Inline */ public Expression inline(Environment env, Context ctx) { if (implementation != null) return implementation.inline(env, ctx); // A field expression may have the side effect of causing // a NullPointerException, so evaluate it even though // the value is not needed. Similarly, static field dereferences // may cause class initialization, so they mustn't be omitted // either. // // However, NullPointerException can't happen and initialization must // already have occured if you are dotting into 'this'. So // allow fields of 'this' to be eliminated as a special case. Expression e = inlineValue(env, ctx); if (e instanceof FieldExpression) { FieldExpression fe = (FieldExpression) e; if ((fe.right != null) && (fe.right.op==THIS)) return null; // It should be possible to split this into two checks: one using // isNonNull() for non-statics and a different check for statics. // That would make the inlining slightly less conservative by // allowing, for example, dotting into String constants. } return e; } public Expression inlineValue(Environment env, Context ctx) { if (implementation != null) return implementation.inlineValue(env, ctx); try { if (field == null) { return this; } if (field.isFinal()) { Expression e = (Expression)field.getValue(env); if ((e != null) && e.isConstant()) { // remove bogus line-number info e = e.copyInline(ctx); e.where = where; return new CommaExpression(where, right, e).inlineValue(env, ctx); } } if (right != null) { if (field.isStatic()) { Expression e = right.inline(env, ctx); right = null; if (e != null) { return new CommaExpression(where, e, this); } } else { right = right.inlineValue(env, ctx); } } return this; } catch (ClassNotFound e) { throw new CompilerError(e); } } public Expression inlineLHS(Environment env, Context ctx) { if (implementation != null) return implementation.inlineLHS(env, ctx); if (right != null) { if (field.isStatic()) { Expression e = right.inline(env, ctx); right = null; if (e != null) { return new CommaExpression(where, e, this); } } else { right = right.inlineValue(env, ctx); } } return this; } public Expression copyInline(Context ctx) { if (implementation != null) return implementation.copyInline(ctx); return super.copyInline(ctx); } /** * The cost of inlining this expression */ public int costInline(int thresh, Environment env, Context ctx) { if (implementation != null) return implementation.costInline(thresh, env, ctx); if (ctx == null) { return 3 + ((right == null) ? 0 : right.costInline(thresh, env, ctx)); } // ctxClass is the current class trying to inline this method ClassDefinition ctxClass = ctx.field.getClassDefinition(); try { // We only allow the inlining if the current class can access // the field, the field's class, and right's declared type. if ( ctxClass.permitInlinedAccess(env, field.getClassDeclaration()) && ctxClass.permitInlinedAccess(env, field)) { if (right == null) { return 3; } else { ClassDeclaration rt = env.getClassDeclaration(right.type); if (ctxClass.permitInlinedAccess(env, rt)) { return 3 + right.costInline(thresh, env, ctx); } } } } catch (ClassNotFound e) { } return thresh; } /** * Code */ int codeLValue(Environment env, Context ctx, Assembler asm) { if (implementation != null) throw new CompilerError("codeLValue"); if (field.isStatic()) { if (right != null) { right.code(env, ctx, asm); return 1; } return 0; } right.codeValue(env, ctx, asm); return 1; } void codeLoad(Environment env, Context ctx, Assembler asm) { if (field == null) { throw new CompilerError("should not be null"); } if (field.isStatic()) { asm.add(where, opc_getstatic, field); } else { asm.add(where, opc_getfield, field); } } void codeStore(Environment env, Context ctx, Assembler asm) { if (field.isStatic()) { asm.add(where, opc_putstatic, field); } else { asm.add(where, opc_putfield, field); } } public void codeValue(Environment env, Context ctx, Assembler asm) { codeLValue(env, ctx, asm); codeLoad(env, ctx, asm); } /** * Print */ public void print(PrintStream out) { out.print("("); if (right != null) { right.print(out); } else { out.print("<empty>"); } out.print("." + id + ")"); if (implementation != null) { out.print("/IMPL="); implementation.print(out); } } }