• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.binder;
18 
19 import static com.google.common.base.StandardSystemProperty.JAVA_HOME;
20 
21 import com.google.common.base.Supplier;
22 import com.google.common.base.Suppliers;
23 import com.google.common.collect.ImmutableMap;
24 import com.google.turbine.binder.bound.ModuleInfo;
25 import com.google.turbine.binder.bytecode.BytecodeBinder;
26 import com.google.turbine.binder.bytecode.BytecodeBoundClass;
27 import com.google.turbine.binder.env.Env;
28 import com.google.turbine.binder.env.SimpleEnv;
29 import com.google.turbine.binder.lookup.SimpleTopLevelIndex;
30 import com.google.turbine.binder.lookup.TopLevelIndex;
31 import com.google.turbine.binder.sym.ClassSymbol;
32 import com.google.turbine.binder.sym.ModuleSymbol;
33 import com.google.turbine.zip.Zip;
34 import java.io.IOException;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import java.nio.file.Paths;
38 import java.util.HashMap;
39 import java.util.Map;
40 import org.checkerframework.checker.nullness.qual.Nullable;
41 
42 /** Constructs a platform {@link ClassPath} from the current JDK's ct.sym file. */
43 public class CtSymClassBinder {
44 
45   @Nullable
bind(String version)46   public static ClassPath bind(String version) throws IOException {
47     Path javaHome = Paths.get(JAVA_HOME.value());
48     Path ctSym = javaHome.resolve("lib/ct.sym");
49     if (!Files.exists(ctSym)) {
50       throw new IllegalStateException("lib/ct.sym does not exist in " + javaHome);
51     }
52     Map<ClassSymbol, BytecodeBoundClass> map = new HashMap<>();
53     Map<ModuleSymbol, ModuleInfo> modules = new HashMap<>();
54     Env<ClassSymbol, BytecodeBoundClass> benv =
55         new Env<ClassSymbol, BytecodeBoundClass>() {
56           @Override
57           public BytecodeBoundClass get(ClassSymbol sym) {
58             return map.get(sym);
59           }
60         };
61     // ct.sym contains directories whose names are the concatentation of a list of target versions
62     // (e.g. 789) and which contain interface class files with a .sig extension.
63     for (Zip.Entry ze : new Zip.ZipIterable(ctSym)) {
64       String name = ze.name();
65       if (!name.endsWith(".sig")) {
66         continue;
67       }
68       int idx = name.indexOf('/');
69       if (idx == -1) {
70         continue;
71       }
72       // check if the directory matches the desired release
73       // TODO(cushon): what happens when version numbers contain more than one digit?
74       if (!ze.name().substring(0, idx).contains(version)) {
75         continue;
76       }
77       if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.sig")) {
78         ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, toByteArrayOrDie(ze));
79         modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
80         continue;
81       }
82       ClassSymbol sym = new ClassSymbol(name.substring(idx + 1, name.length() - ".sig".length()));
83       map.putIfAbsent(
84           sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, ctSym + "!" + ze.name()));
85     }
86     if (map.isEmpty()) {
87       // we didn't find any classes for the desired release
88       return null;
89     }
90     SimpleEnv<ClassSymbol, BytecodeBoundClass> env = new SimpleEnv<>(ImmutableMap.copyOf(map));
91     Env<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.copyOf(modules));
92     TopLevelIndex index = SimpleTopLevelIndex.of(env.asMap().keySet());
93     return new ClassPath() {
94       @Override
95       public Env<ClassSymbol, BytecodeBoundClass> env() {
96         return env;
97       }
98 
99       @Override
100       public Env<ModuleSymbol, ModuleInfo> moduleEnv() {
101         return moduleEnv;
102       }
103 
104       @Override
105       public TopLevelIndex index() {
106         return index;
107       }
108 
109       @Override
110       public Supplier<byte[]> resource(String input) {
111         return null;
112       }
113     };
114   }
115 
116   private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
117     return Suppliers.memoize(
118         new Supplier<byte[]>() {
119           @Override
120           public byte[] get() {
121             return ze.data();
122           }
123         });
124   }
125 }
126