15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.jshell;
27
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.LinkedHashSet;
32 import java.util.List;
33 import java.util.Set;
34 import java.util.stream.Stream;
35 import jdk.jshell.Snippet.Kind;
36 import jdk.jshell.Snippet.Status;
37 import jdk.jshell.Snippet.SubKind;
38 import jdk.jshell.TaskFactory.AnalyzeTask;
39 import jdk.jshell.TaskFactory.CompileTask;
40 import static java.util.stream.Collectors.toList;
41 import static java.util.stream.Collectors.toSet;
42 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
43 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
44 import static jdk.jshell.Snippet.Status.OVERWRITTEN;
45 import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
46 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
47 import static jdk.jshell.Snippet.Status.REJECTED;
48 import static jdk.jshell.Snippet.Status.VALID;
49 import static jdk.jshell.Util.PARSED_LOCALE;
50 import static jdk.jshell.Util.expunge;
51
52 /**
53 * Tracks the compilation and load of a new or updated snippet.
54 * @author Robert Field
55 */
56 final class Unit {
57
58 private final JShell state;
59 private final Snippet si;
60 private final Snippet siOld;
61 private final boolean isDependency;
62 private final boolean isNew;
63 private final Snippet causalSnippet;
64 private final DiagList generatedDiagnostics;
65
66 private int seq;
67 private String classNameInitial;
68 private Wrap activeGuts;
69 private Status status;
70 private Status prevStatus;
71 private boolean signatureChanged;
72 private DiagList compilationDiagnostics;
73 private DiagList recompilationDiagnostics = null;
74 private List<String> unresolved;
75 private SnippetEvent replaceOldEvent;
76 private List<SnippetEvent> secondaryEvents;
77 private boolean isAttemptingCorral;
78 private List<String> toRedefine;
79 private boolean dependenciesNeeded;
80
81 Unit(JShell state, Snippet si, Snippet causalSnippet,
82 DiagList generatedDiagnostics) {
83 this.state = state;
84 this.si = si;
85 this.isDependency = causalSnippet != null;
86 this.siOld = isDependency
87 ? si
88 : state.maps.getSnippet(si.key());
89 this.isNew = siOld == null;
90 this.causalSnippet = causalSnippet;
91 this.generatedDiagnostics = generatedDiagnostics;
92
93 this.seq = isNew? 0 : siOld.sequenceNumber();
94 this.classNameInitial = isNew? "<none>" : siOld.className();
95 this.prevStatus = (isNew || isDependency)
96 ? si.status()
97 : siOld.status();
98 si.setSequenceNumber(seq);
244 } else if (isRecoverable()) {
245 if (isAttemptingCorral && !recompilationDiagnostics.hasErrors()) {
246 status = RECOVERABLE_DEFINED;
247 } else {
248 status = RECOVERABLE_NOT_DEFINED;
249 }
250 } else {
251 status = REJECTED;
252 }
253 checkForOverwrite(at);
254
255 state.debug(DBG_GEN, "setStatus() %s - status: %s\n",
256 si, status);
257 }
258
259 boolean isDefined() {
260 return status.isDefined();
261 }
262
263 /**
264 * Process the class information from the last compile.
265 * Requires loading of returned list.
266 * @return the list of classes to load
267 */
268 Stream<String> classesToLoad(List<String> classnames) {
269 toRedefine = new ArrayList<>();
270 List<String> toLoad = new ArrayList<>();
271 if (status.isDefined() && !isImport()) {
272 // Classes should only be loaded/redefined if the compile left them
273 // in a defined state. Imports do not have code and are not loaded.
274 for (String cn : classnames) {
275 switch (state.executionControl().getClassStatus(cn)) {
276 case UNKNOWN:
277 // If not loaded, add to the list of classes to load.
278 toLoad.add(cn);
279 dependenciesNeeded = true;
280 break;
281 case NOT_CURRENT:
282 // If loaded but out of date, add to the list of classes to attempt redefine.
283 toRedefine.add(cn);
284 break;
285 case CURRENT:
286 // Loaded and current, so nothing to do
287 break;
288 }
289 }
290 }
291 return toLoad.stream();
292 }
293
294 /**
295 * Redefine classes needing redefine.
296 * classesToLoad() must be called first.
297 * @return true if all redefines succeeded (can be vacuously true)
298 */
299 boolean doRedefines() {
300 return toRedefine.isEmpty()
301 ? true
302 : state.executionControl().redefine(toRedefine);
303 }
304
305 void markForReplacement() {
306 // increment for replace class wrapper
307 si.setSequenceNumber(++seq);
308 }
309
310 private boolean isImport() {
311 return si.kind() == Kind.IMPORT;
312 }
313
314 private boolean sigChanged() {
315 return (status.isDefined() != prevStatus.isDefined())
316 || (status.isDefined() && !si.className().equals(classNameInitial))
317 || signatureChanged;
318 }
319
320 Stream<Unit> effectedDependents() {
321 //System.err.printf("effectedDependents sigChanged=%b dependenciesNeeded=%b status=%s\n",
322 // sigChanged(), dependenciesNeeded, status);
|
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.jshell;
27
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.LinkedHashSet;
32 import java.util.List;
33 import java.util.Set;
34 import java.util.stream.Stream;
35 import jdk.jshell.ClassTracker.ClassInfo;
36 import jdk.jshell.Snippet.Kind;
37 import jdk.jshell.Snippet.Status;
38 import jdk.jshell.Snippet.SubKind;
39 import jdk.jshell.TaskFactory.AnalyzeTask;
40 import jdk.jshell.TaskFactory.CompileTask;
41 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
42 import jdk.jshell.spi.ExecutionControl.ClassInstallException;
43 import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
44 import static java.util.stream.Collectors.toList;
45 import static java.util.stream.Collectors.toSet;
46 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
47 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
48 import static jdk.jshell.Snippet.Status.OVERWRITTEN;
49 import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
50 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
51 import static jdk.jshell.Snippet.Status.REJECTED;
52 import static jdk.jshell.Snippet.Status.VALID;
53 import static jdk.jshell.Util.PARSED_LOCALE;
54 import static jdk.jshell.Util.expunge;
55
56 /**
57 * Tracks the compilation and load of a new or updated snippet.
58 * @author Robert Field
59 */
60 final class Unit {
61
62 private final JShell state;
63 private final Snippet si;
64 private final Snippet siOld;
65 private final boolean isDependency;
66 private final boolean isNew;
67 private final Snippet causalSnippet;
68 private final DiagList generatedDiagnostics;
69
70 private int seq;
71 private String classNameInitial;
72 private Wrap activeGuts;
73 private Status status;
74 private Status prevStatus;
75 private boolean signatureChanged;
76 private DiagList compilationDiagnostics;
77 private DiagList recompilationDiagnostics = null;
78 private List<String> unresolved;
79 private SnippetEvent replaceOldEvent;
80 private List<SnippetEvent> secondaryEvents;
81 private boolean isAttemptingCorral;
82 private List<ClassInfo> toRedefine;
83 private boolean dependenciesNeeded;
84
85 Unit(JShell state, Snippet si, Snippet causalSnippet,
86 DiagList generatedDiagnostics) {
87 this.state = state;
88 this.si = si;
89 this.isDependency = causalSnippet != null;
90 this.siOld = isDependency
91 ? si
92 : state.maps.getSnippet(si.key());
93 this.isNew = siOld == null;
94 this.causalSnippet = causalSnippet;
95 this.generatedDiagnostics = generatedDiagnostics;
96
97 this.seq = isNew? 0 : siOld.sequenceNumber();
98 this.classNameInitial = isNew? "<none>" : siOld.className();
99 this.prevStatus = (isNew || isDependency)
100 ? si.status()
101 : siOld.status();
102 si.setSequenceNumber(seq);
248 } else if (isRecoverable()) {
249 if (isAttemptingCorral && !recompilationDiagnostics.hasErrors()) {
250 status = RECOVERABLE_DEFINED;
251 } else {
252 status = RECOVERABLE_NOT_DEFINED;
253 }
254 } else {
255 status = REJECTED;
256 }
257 checkForOverwrite(at);
258
259 state.debug(DBG_GEN, "setStatus() %s - status: %s\n",
260 si, status);
261 }
262
263 boolean isDefined() {
264 return status.isDefined();
265 }
266
267 /**
268 * Process the class information from the last compile. Requires loading of
269 * returned list.
270 *
271 * @return the list of classes to load
272 */
273 Stream<ClassBytecodes> classesToLoad(List<String> classnames) {
274 toRedefine = new ArrayList<>();
275 List<ClassBytecodes> toLoad = new ArrayList<>();
276 if (status.isDefined() && !isImport()) {
277 // Classes should only be loaded/redefined if the compile left them
278 // in a defined state. Imports do not have code and are not loaded.
279 for (String cn : classnames) {
280 ClassInfo ci = state.classTracker.get(cn);
281 if (ci.isLoaded()) {
282 if (ci.isCurrent()) {
283 // nothing to do
284 } else {
285 toRedefine.add(ci);
286 }
287 } else {
288 // If not loaded, add to the list of classes to load.
289 toLoad.add(ci.toClassBytecodes());
290 dependenciesNeeded = true;
291 }
292 }
293 }
294 return toLoad.stream();
295 }
296
297 /**
298 * Redefine classes needing redefine. classesToLoad() must be called first.
299 *
300 * @return true if all redefines succeeded (can be vacuously true)
301 */
302 boolean doRedefines() {
303 if (toRedefine.isEmpty()) {
304 return true;
305 }
306 ClassBytecodes[] cbcs = toRedefine.stream()
307 .map(ci -> ci.toClassBytecodes())
308 .toArray(size -> new ClassBytecodes[size]);
309 try {
310 state.executionControl().redefine(cbcs);
311 state.classTracker.markLoaded(cbcs);
312 return true;
313 } catch (ClassInstallException ex) {
314 state.classTracker.markLoaded(cbcs, ex.installed());
315 return false;
316 } catch (EngineTerminationException ex) {
317 state.closeDown();
318 return false;
319 }
320 }
321
322 void markForReplacement() {
323 // increment for replace class wrapper
324 si.setSequenceNumber(++seq);
325 }
326
327 private boolean isImport() {
328 return si.kind() == Kind.IMPORT;
329 }
330
331 private boolean sigChanged() {
332 return (status.isDefined() != prevStatus.isDefined())
333 || (status.isDefined() && !si.className().equals(classNameInitial))
334 || signatureChanged;
335 }
336
337 Stream<Unit> effectedDependents() {
338 //System.err.printf("effectedDependents sigChanged=%b dependenciesNeeded=%b status=%s\n",
339 // sigChanged(), dependenciesNeeded, status);
|