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 jdk.jshell.spi.ExecutionControl.NotImplementedException;
45 import static java.util.stream.Collectors.toList;
46 import static java.util.stream.Collectors.toSet;
47 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
48 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
49 import static jdk.jshell.Snippet.Status.OVERWRITTEN;
50 import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
51 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
52 import static jdk.jshell.Snippet.Status.REJECTED;
53 import static jdk.jshell.Snippet.Status.VALID;
54 import static jdk.jshell.Util.PARSED_LOCALE;
55 import static jdk.jshell.Util.expunge;
56
57 /**
58 * Tracks the compilation and load of a new or updated snippet.
59 * @author Robert Field
60 */
61 final class Unit {
62
63 private final JShell state;
64 private final Snippet si;
65 private final Snippet siOld;
66 private final boolean isDependency;
67 private final boolean isNew;
68 private final Snippet causalSnippet;
69 private final DiagList generatedDiagnostics;
70
71 private int seq;
72 private String classNameInitial;
73 private Wrap activeGuts;
74 private Status status;
75 private Status prevStatus;
76 private boolean signatureChanged;
77 private DiagList compilationDiagnostics;
78 private DiagList recompilationDiagnostics = null;
79 private List<String> unresolved;
80 private SnippetEvent replaceOldEvent;
81 private List<SnippetEvent> secondaryEvents;
82 private boolean isAttemptingCorral;
83 private List<ClassInfo> toRedefine;
84 private boolean dependenciesNeeded;
85
86 Unit(JShell state, Snippet si, Snippet causalSnippet,
87 DiagList generatedDiagnostics) {
88 this.state = state;
89 this.si = si;
90 this.isDependency = causalSnippet != null;
91 this.siOld = isDependency
92 ? si
93 : state.maps.getSnippet(si.key());
94 this.isNew = siOld == null;
95 this.causalSnippet = causalSnippet;
96 this.generatedDiagnostics = generatedDiagnostics;
97
98 this.seq = isNew? 0 : siOld.sequenceNumber();
99 this.classNameInitial = isNew? "<none>" : siOld.className();
100 this.prevStatus = (isNew || isDependency)
101 ? si.status()
102 : siOld.status();
103 si.setSequenceNumber(seq);
249 } else if (isRecoverable()) {
250 if (isAttemptingCorral && !recompilationDiagnostics.hasErrors()) {
251 status = RECOVERABLE_DEFINED;
252 } else {
253 status = RECOVERABLE_NOT_DEFINED;
254 }
255 } else {
256 status = REJECTED;
257 }
258 checkForOverwrite(at);
259
260 state.debug(DBG_GEN, "setStatus() %s - status: %s\n",
261 si, status);
262 }
263
264 boolean isDefined() {
265 return status.isDefined();
266 }
267
268 /**
269 * Process the class information from the last compile. Requires loading of
270 * returned list.
271 *
272 * @return the list of classes to load
273 */
274 Stream<ClassBytecodes> classesToLoad(List<String> classnames) {
275 toRedefine = new ArrayList<>();
276 List<ClassBytecodes> toLoad = new ArrayList<>();
277 if (status.isDefined() && !isImport()) {
278 // Classes should only be loaded/redefined if the compile left them
279 // in a defined state. Imports do not have code and are not loaded.
280 for (String cn : classnames) {
281 ClassInfo ci = state.classTracker.get(cn);
282 if (ci.isLoaded()) {
283 if (ci.isCurrent()) {
284 // nothing to do
285 } else {
286 toRedefine.add(ci);
287 }
288 } else {
289 // If not loaded, add to the list of classes to load.
290 toLoad.add(ci.toClassBytecodes());
291 dependenciesNeeded = true;
292 }
293 }
294 }
295 return toLoad.stream();
296 }
297
298 /**
299 * Redefine classes needing redefine. classesToLoad() must be called first.
300 *
301 * @return true if all redefines succeeded (can be vacuously true)
302 */
303 boolean doRedefines() {
304 if (toRedefine.isEmpty()) {
305 return true;
306 }
307 ClassBytecodes[] cbcs = toRedefine.stream()
308 .map(ci -> ci.toClassBytecodes())
309 .toArray(size -> new ClassBytecodes[size]);
310 try {
311 state.executionControl().redefine(cbcs);
312 state.classTracker.markLoaded(cbcs);
313 return true;
314 } catch (ClassInstallException ex) {
315 state.classTracker.markLoaded(cbcs, ex.installed());
316 return false;
317 } catch (EngineTerminationException ex) {
318 state.closeDown();
319 return false;
320 } catch (NotImplementedException ex) {
321 return false;
322 }
323 }
324
325 void markForReplacement() {
326 // increment for replace class wrapper
327 si.setSequenceNumber(++seq);
328 }
329
330 private boolean isImport() {
331 return si.kind() == Kind.IMPORT;
332 }
333
334 private boolean sigChanged() {
335 return (status.isDefined() != prevStatus.isDefined())
336 || (status.isDefined() && !si.className().equals(classNameInitial))
337 || signatureChanged;
338 }
339
340 Stream<Unit> effectedDependents() {
341 //System.err.printf("effectedDependents sigChanged=%b dependenciesNeeded=%b status=%s\n",
342 // sigChanged(), dependenciesNeeded, status);
|