• 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 javax.annotation.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   }
110 
111   private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
112     return Suppliers.memoize(
113         new Supplier<byte[]>() {
114           @Override
115           public byte[] get() {
116             return ze.data();
117           }
118         });
119   }
120 }
121