< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java

Print this page

        

*** 23,41 **** --- 23,45 ---- * questions. */ package com.sun.tools.javac.comp; + import sun.invoke.util.BytecodeName; + import java.util.*; import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Stream; + import java.util.stream.Collectors; import com.sun.source.tree.CaseTree.CaseKind; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Kinds.KindSelector; import com.sun.tools.javac.code.Scope.WriteableScope; + import com.sun.tools.javac.comp.Resolve.MethodResolutionContext; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.main.Option.PkgInfo; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*;
*** 56,69 **** import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF; import static com.sun.tools.javac.jvm.ByteCodes.*; - import com.sun.tools.javac.tree.JCTree.JCBreak; - import com.sun.tools.javac.tree.JCTree.JCCase; - import com.sun.tools.javac.tree.JCTree.JCExpression; - import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT; import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This pass translates away some syntactic sugar: inner classes, --- 60,69 ----
*** 803,812 **** --- 803,827 ---- */ private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) { return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil()); } + private Symbol findMethodOrFailSilently( + DiagnosticPosition pos, + Env<AttrContext> env, + Type site, + Name name, + List<Type> argtypes, + List<Type> typeargtypes) { + MethodResolutionContext resolveContext = rs.new MethodResolutionContext(); + resolveContext.internalResolution = true; + resolveContext.silentFail = true; + Symbol sym = rs.resolveQualifiedMethod(resolveContext, pos, env, site.tsym, + site, name, argtypes, typeargtypes); + return sym; + } + /** Anon inner classes are used as access constructor tags. * accessConstructorTag will use an existing anon class if one is available, * and synthethise a class (with makeEmptyClass) if one is not available. * However, there is a small possibility that an existing class will not * be generated as expected if it is inside a conditional with a constant
*** 2189,2198 **** --- 2204,2217 ---- // If this is an enum definition if ((tree.mods.flags & ENUM) != 0 && (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0) visitEnumDef(tree); + if ((tree.mods.flags & RECORD) != 0) { + visitRecordDef(tree); + } + // If this is a nested class, define a this$n field for // it and add to proxies. JCVariableDecl otdef = null; if (currentClass.hasOuterInstance()) otdef = outerThisDef(tree.pos, currentClass);
*** 2258,2267 **** --- 2277,2317 ---- // Return empty block {} as a placeholder for an inner class. result = make_at(tree.pos()).Block(SYNTHETIC, List.nil()); } + List<JCTree> accessors(JCClassDecl tree) { + ListBuffer<JCTree> buffer = new ListBuffer<>(); + tree.defs.stream() + .filter(t -> t.hasTag(VARDEF)) + .map(t -> (JCVariableDecl)t) + .filter(vd -> vd.sym.accessors.nonEmpty()) + .forEach(vd -> { + for (Pair<Accessors.Kind, MethodSymbol> accessor : vd.sym.accessors) { + MethodSymbol accessorSym = accessor.snd; + if ((accessorSym.flags() & Flags.MANDATED) != 0) { + make_at(tree.pos()); + switch (accessor.fst) { + case GET: + buffer.add(make.MethodDef(accessorSym, make.Block(0, + List.of(make.Return(make.Ident(vd.sym)))))); + break; + case SET: + buffer.add(make.MethodDef(accessorSym, make.Block(0, + List.of(make.Exec( + make.Assign(make.Ident(vd.sym), make.Ident(accessorSym.params.head)) + .setType(vd.sym.type)))))); + break; + default: + Assert.error("Cannot get here!"); + } + } + } + }); + return buffer.toList(); + } + /** Translate an enum class. */ private void visitEnumDef(JCClassDecl tree) { make_at(tree.pos()); // add the supertype, if needed
*** 2413,2422 **** --- 2463,2733 ---- varDef.args = varDef.args. prepend(makeLit(syms.intType, ordinal)). prepend(makeLit(syms.stringType, var.name.toString())); } + /** Translate a record. */ + private void visitRecordDef(JCClassDecl tree) { + make_at(tree.pos()); + List<VarSymbol> vars = types.recordVars(tree.type); + Pool.MethodHandle[] getterMethHandles = new Pool.MethodHandle[vars.size()]; + int index = 0; + for (VarSymbol var : vars) { + if (var.owner != tree.sym) { + var = new VarSymbol(var.flags_field, var.name, var.type, tree.sym); + } + getterMethHandles[index] = new Pool.MethodHandle(ClassFile.REF_getField, var, types); + index++; + } + + tree.defs = tree.defs.appendList(accessors(tree)); + tree.defs = tree.defs.appendList(List.of( + recordEquals(tree, getterMethHandles), + recordToString(tree, vars, getterMethHandles), + recordHashCode(tree, getterMethHandles), + recordExtractor(tree, getterMethHandles), + recordReadResolve(tree) + )); + } + + JCTree recordToString(JCClassDecl tree, List<VarSymbol> vars, Pool.MethodHandle[] getterMethHandles) { + make_at(tree.pos()); + + MethodSymbol msym = lookupMethod(tree.pos(), + names.toString, + tree.sym.type, + List.nil()); + if ((msym.flags() & RECORD) != 0) { + Name bootstrapName = names.makeToString; + Object[] staticArgsValues = new Object[2 + getterMethHandles.length]; + staticArgsValues[0] = tree.sym; + String concatNames = vars.stream() + .map(v -> v.name) + .collect(Collectors.joining(";", "", "")); + staticArgsValues[1] = concatNames; + int index = 2; + for (Object mho : getterMethHandles) { + staticArgsValues[index] = mho; + index++; + } + + List<Type> staticArgTypes = List.of(syms.classType, + syms.stringType, + new ArrayType(syms.methodHandleType, syms.arrayClass)); + + JCFieldAccess qualifier = makeIndyQualifier(syms.objectMethodBuildersType, + tree, msym, staticArgTypes, staticArgsValues, bootstrapName, false); + + VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym); + + JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this))); + proxyCall.type = qualifier.type; + return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall)))); + } else { + return make.Block(SYNTHETIC, List.nil()); + } + } + + JCTree recordHashCode(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) { + make_at(tree.pos()); + MethodSymbol msym = lookupMethod(tree.pos(), + names.hashCode, + tree.sym.type, + List.nil()); + if ((msym.flags() & RECORD) != 0) { + Name bootstrapName = names.makeHashCode; + Object[] staticArgsValues = new Object[1 + getterMethHandles.length]; + staticArgsValues[0] = tree.sym; + int index = 1; + for (Object mho : getterMethHandles) { + staticArgsValues[index] = mho; + index++; + } + + List<Type> staticArgTypes = List.of(syms.classType, + new ArrayType(syms.methodHandleType, syms.arrayClass)); + + JCFieldAccess qualifier = makeIndyQualifier( + syms.objectMethodBuildersType, tree, msym, + staticArgTypes, staticArgsValues, bootstrapName, + false); + + VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym); + + JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this))); + proxyCall.type = qualifier.type; + return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall)))); + } else { + return make.Block(SYNTHETIC, List.nil()); + } + } + + JCTree recordExtractor(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) { + make_at(tree.pos()); + List<Type> fieldTypes = TreeInfo.types(TreeInfo.recordFields(tree)); + String argsTypeSig = '(' + argsTypeSig(fieldTypes) + ')'; + String extractorStr = BytecodeName.toBytecodeName("$pattern$" + tree.sym.name + "$" + argsTypeSig); + Name extractorName = names.fromString(extractorStr); + // public Extractor extractorName () { return ???; } + MethodType extractorMT = new MethodType(List.nil(), syms.extractorType, List.nil(), syms.methodClass); + MethodSymbol extractorSym = new MethodSymbol( + Flags.PUBLIC | Flags.RECORD | Flags.STATIC, + extractorName, extractorMT, tree.sym); + tree.sym.members().enter(extractorSym); + + Name bootstrapName = names.makeLazyExtractor; + Object[] staticArgsValues = new Object[1 + getterMethHandles.length]; + /** this method descriptor should have the same arguments as the record constructor and its + * return type should be the same as the type of the record + */ + MethodType mt = new MethodType(fieldTypes, tree.type, List.nil(), syms.methodClass); + staticArgsValues[0] = mt; + int index = 1; + for (Object mho : getterMethHandles) { + staticArgsValues[index] = mho; + index++; + } + + List<Type> staticArgTypes = List.of(syms.methodTypeType, + new ArrayType(syms.methodHandleType, syms.arrayClass)); + JCFieldAccess qualifier = makeIndyQualifier( + syms.extractorType, tree, extractorSym, staticArgTypes, + staticArgsValues, bootstrapName, true); + + JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.nil()); + proxyCall.type = qualifier.type; + return make.MethodDef(extractorSym, make.Block(0, List.of(make.Return(proxyCall)))); + } + + JCTree recordReadResolve(JCClassDecl tree) { + make_at(tree.pos()); + Symbol msym = findMethodOrFailSilently( + tree.pos(), + attrEnv, + tree.sym.type, + names.readResolve, + List.nil(), + List.nil()); + if (!msym.kind.isResolutionError() && (msym.flags() & RECORD) != 0) { + List<JCExpression> args = TreeInfo.recordFields(tree).map(vd -> make.Ident(vd)); + return make.MethodDef((MethodSymbol)msym, make.Block(0, List.of(make.Return(makeNewClass(tree.sym.type, args))))); + } else { + return make.Block(SYNTHETIC, List.nil()); + } + } + + private String argsTypeSig(List<Type> typeList) { + LowerSignatureGenerator sg = new LowerSignatureGenerator(); + sg.assembleSig(typeList); + return sg.toString(); + } + + /** + * Signature Generation + */ + private class LowerSignatureGenerator extends Types.SignatureGenerator { + + /** + * An output buffer for type signatures. + */ + StringBuilder sb = new StringBuilder(); + + LowerSignatureGenerator() { + super(types); + } + + @Override + protected void append(char ch) { + sb.append(ch); + } + + @Override + protected void append(byte[] ba) { + sb.append(new String(ba)); + } + + @Override + protected void append(Name name) { + sb.append(name.toString()); + } + + @Override + public String toString() { + return sb.toString(); + } + } + + JCTree recordEquals(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) { + make_at(tree.pos()); + MethodSymbol msym = lookupMethod(tree.pos(), + names.equals, + tree.sym.type, + List.of(syms.objectType)); + + if ((msym.flags() & RECORD) != 0) { + Name bootstrapName = names.makeEquals; + Object[] staticArgsValues = new Object[1 + getterMethHandles.length]; + staticArgsValues[0] = tree.sym; + int index = 1; + for (Object mho : getterMethHandles) { + staticArgsValues[index] = mho; + index++; + } + + List<Type> staticArgTypes = List.of(syms.classType, + new ArrayType(syms.methodHandleType, syms.arrayClass)); + + JCFieldAccess qualifier = makeIndyQualifier( + syms.objectMethodBuildersType, tree, msym, + staticArgTypes, staticArgsValues, bootstrapName, false); + + VarSymbol o = msym.params.head; + o.adr = 0; + VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym); + + JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this), make.Ident(o))); + proxyCall.type = qualifier.type; + return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall)))); + } else { + return make.Block(SYNTHETIC, List.nil()); + } + } + + JCFieldAccess makeIndyQualifier( + Type site, + JCClassDecl tree, + MethodSymbol msym, + List<Type> staticArgTypes, + Object[] staticArgValues, + Name bootstrapName, + boolean isStatic) { + List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, + syms.stringType, + syms.methodTypeType).appendList(staticArgTypes); + + Symbol bsm = rs.resolveInternalMethod(tree.pos(), attrEnv, site, + bootstrapName, bsm_staticArgs, List.nil()); + + MethodType indyType = msym.type.asMethodType(); + indyType = new MethodType( + isStatic ? List.nil() : indyType.argtypes.prepend(tree.sym.type), + indyType.restype, + indyType.thrown, + syms.methodClass + ); + DynamicMethodSymbol dynSym = new DynamicMethodSymbol(bootstrapName, + syms.noSymbol, + ClassFile.REF_invokeStatic, + (MethodSymbol)bsm, + indyType, + staticArgValues); + JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bootstrapName); + qualifier.sym = dynSym; + qualifier.type = msym.type.asMethodType().restype; + return qualifier; + } + public void visitMethodDef(JCMethodDecl tree) { if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) { // Add "String $enum$name, int $enum$ordinal" to the beginning of the // argument list for each constructor of an enum. JCVariableDecl nameParam = make_at(tree.pos()).
< prev index next >