44 import com.sun.source.tree.VariableTree; 45 import com.sun.tools.javac.tree.JCTree; 46 import com.sun.tools.javac.tree.Pretty; 47 import java.io.IOException; 48 import java.io.StringWriter; 49 import java.io.Writer; 50 import java.util.LinkedHashSet; 51 import java.util.Set; 52 import jdk.jshell.Key.ErroneousKey; 53 import jdk.jshell.Key.MethodKey; 54 import jdk.jshell.Key.TypeDeclKey; 55 import jdk.jshell.Snippet.Kind; 56 import jdk.jshell.Snippet.SubKind; 57 import jdk.jshell.TaskFactory.AnalyzeTask; 58 import jdk.jshell.TaskFactory.BaseTask; 59 import jdk.jshell.TaskFactory.CompileTask; 60 import jdk.jshell.TaskFactory.ParseTask; 61 import jdk.jshell.TreeDissector.ExpressionInfo; 62 import jdk.jshell.Wrap.Range; 63 import jdk.jshell.Snippet.Status; 64 import static java.util.stream.Collectors.toList; 65 import static java.util.stream.Collectors.toSet; 66 import static java.util.Collections.singletonList; 67 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN; 68 import static jdk.jshell.Util.DOIT_METHOD_NAME; 69 import static jdk.jshell.Util.PREFIX_PATTERN; 70 import static jdk.jshell.Util.expunge; 71 import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND; 72 import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND; 73 import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND; 74 import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND; 75 76 /** 77 * The Evaluation Engine. Source internal analysis, wrapping control, 78 * compilation, declaration. redefinition, replacement, and execution. 79 * 80 * @author Robert Field 81 */ 82 class Eval { 83 528 529 if (!si.status().isDefined() 530 && si.diagnostics().isEmpty() 531 && si.unresolved().isEmpty()) { 532 // did not succeed, but no record of it, extract from others 533 si.setDiagnostics(outs.stream() 534 .flatMap(u -> u.snippet().diagnostics().stream()) 535 .collect(Collectors.toCollection(DiagList::new))); 536 } 537 538 // If appropriate, execute the snippet 539 String value = null; 540 JShellException exception = null; 541 if (si.status().isDefined()) { 542 if (si.isExecutable()) { 543 try { 544 value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME); 545 value = si.subKind().hasValue() 546 ? expunge(value) 547 : ""; 548 } catch (EvalException ex) { 549 exception = translateExecutionException(ex); 550 } catch (JShellException ex) { 551 // UnresolvedReferenceException 552 exception = ex; 553 } 554 } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) { 555 switch (((VarSnippet) si).typeName()) { 556 case "byte": 557 case "short": 558 case "int": 559 case "long": 560 value = "0"; 561 break; 562 case "float": 563 case "double": 564 value = "0.0"; 565 break; 566 case "boolean": 567 value = "false"; 568 break; 569 case "char": 570 value = "''"; 571 break; 572 default: 683 } 684 685 // add any new dependencies to the working set 686 List<Unit> newDependencies = ins.stream() 687 .flatMap(u -> u.effectedDependents()) 688 .collect(toList()); 689 state.debug(DBG_GEN, "compileAndLoad %s -- deps: %s success: %s\n", 690 ins, newDependencies, success); 691 if (!ins.addAll(newDependencies) && success) { 692 // all classes that could not be directly loaded (because they 693 // are new) have been redefined, and no new dependnencies were 694 // identified 695 ins.stream().forEach(u -> u.finish()); 696 return ins; 697 } 698 } 699 } 700 701 /** 702 * If there are classes to load, loads by calling the execution engine. 703 * @param classnames names of the classes to load. 704 */ 705 private void load(Collection<String> classnames) { 706 if (!classnames.isEmpty()) { 707 state.executionControl().load(classnames); 708 } 709 } 710 711 private EvalException translateExecutionException(EvalException ex) { 712 StackTraceElement[] raw = ex.getStackTrace(); 713 int last = raw.length; 714 do { 715 if (last == 0) { 716 last = raw.length - 1; 717 break; 718 } 719 } while (!isWrap(raw[--last])); 720 StackTraceElement[] elems = new StackTraceElement[last + 1]; 721 for (int i = 0; i <= last; ++i) { 722 StackTraceElement r = raw[i]; 723 OuterSnippetsClassWrap outer = state.outerMap.getOuter(r.getClassName()); 724 if (outer != null) { 725 String klass = expunge(r.getClassName()); 726 String method = r.getMethodName().equals(DOIT_METHOD_NAME) ? "" : r.getMethodName(); 727 int wln = r.getLineNumber() - 1; 728 int line = outer.wrapLineToSnippetLine(wln) + 1; 729 Snippet sn = outer.wrapLineToSnippet(wln); 730 String file = "#" + sn.id(); 731 elems[i] = new StackTraceElement(klass, method, file, line); 732 } else if (r.getFileName().equals("<none>")) { 733 elems[i] = new StackTraceElement(r.getClassName(), r.getMethodName(), null, r.getLineNumber()); 734 } else { 735 elems[i] = r; 736 } 737 } 738 String msg = ex.getMessage(); 739 if (msg.equals("<none>")) { 740 msg = null; 741 } 742 return new EvalException(msg, ex.getExceptionClassName(), elems); 743 } 744 745 private boolean isWrap(StackTraceElement ste) { 746 return PREFIX_PATTERN.matcher(ste.getClassName()).find(); 747 } 748 749 private DiagList modifierDiagnostics(ModifiersTree modtree, 750 final TreeDissector dis, boolean isAbstractProhibited) { 751 752 class ModifierDiagnostic extends Diag { 753 754 final boolean fatal; 755 final String message; 756 757 ModifierDiagnostic(List<Modifier> list, boolean fatal) { 758 this.fatal = fatal; 759 StringBuilder sb = new StringBuilder(); 760 for (Modifier mod : list) { 761 sb.append("'"); 762 sb.append(mod.toString()); | 44 import com.sun.source.tree.VariableTree; 45 import com.sun.tools.javac.tree.JCTree; 46 import com.sun.tools.javac.tree.Pretty; 47 import java.io.IOException; 48 import java.io.StringWriter; 49 import java.io.Writer; 50 import java.util.LinkedHashSet; 51 import java.util.Set; 52 import jdk.jshell.Key.ErroneousKey; 53 import jdk.jshell.Key.MethodKey; 54 import jdk.jshell.Key.TypeDeclKey; 55 import jdk.jshell.Snippet.Kind; 56 import jdk.jshell.Snippet.SubKind; 57 import jdk.jshell.TaskFactory.AnalyzeTask; 58 import jdk.jshell.TaskFactory.BaseTask; 59 import jdk.jshell.TaskFactory.CompileTask; 60 import jdk.jshell.TaskFactory.ParseTask; 61 import jdk.jshell.TreeDissector.ExpressionInfo; 62 import jdk.jshell.Wrap.Range; 63 import jdk.jshell.Snippet.Status; 64 import jdk.jshell.spi.ExecutionControl.ClassBytecodes; 65 import jdk.jshell.spi.ExecutionControl.ClassInstallException; 66 import jdk.jshell.spi.ExecutionControl.EngineTerminationException; 67 import jdk.jshell.spi.ExecutionControl.InternalException; 68 import jdk.jshell.spi.ExecutionControl.ResolutionException; 69 import jdk.jshell.spi.ExecutionControl.RunException; 70 import jdk.jshell.spi.ExecutionControl.UserException; 71 import static java.util.stream.Collectors.toList; 72 import static java.util.stream.Collectors.toSet; 73 import static java.util.Collections.singletonList; 74 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN; 75 import static jdk.jshell.Util.DOIT_METHOD_NAME; 76 import static jdk.jshell.Util.PREFIX_PATTERN; 77 import static jdk.jshell.Util.expunge; 78 import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND; 79 import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND; 80 import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND; 81 import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND; 82 83 /** 84 * The Evaluation Engine. Source internal analysis, wrapping control, 85 * compilation, declaration. redefinition, replacement, and execution. 86 * 87 * @author Robert Field 88 */ 89 class Eval { 90 535 536 if (!si.status().isDefined() 537 && si.diagnostics().isEmpty() 538 && si.unresolved().isEmpty()) { 539 // did not succeed, but no record of it, extract from others 540 si.setDiagnostics(outs.stream() 541 .flatMap(u -> u.snippet().diagnostics().stream()) 542 .collect(Collectors.toCollection(DiagList::new))); 543 } 544 545 // If appropriate, execute the snippet 546 String value = null; 547 JShellException exception = null; 548 if (si.status().isDefined()) { 549 if (si.isExecutable()) { 550 try { 551 value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME); 552 value = si.subKind().hasValue() 553 ? expunge(value) 554 : ""; 555 } catch (ResolutionException ex) { 556 DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(ex.id()); 557 exception = new UnresolvedReferenceException(sn, ex.getStackTrace()); 558 } catch (UserException ex) { 559 exception = translateExecutionException(ex); 560 } catch (RunException ex) { 561 // StopException - no-op 562 } catch (InternalException ex) { 563 state.debug(ex, "invoke"); 564 } catch (EngineTerminationException ex) { 565 state.closeDown(); 566 } 567 } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) { 568 switch (((VarSnippet) si).typeName()) { 569 case "byte": 570 case "short": 571 case "int": 572 case "long": 573 value = "0"; 574 break; 575 case "float": 576 case "double": 577 value = "0.0"; 578 break; 579 case "boolean": 580 value = "false"; 581 break; 582 case "char": 583 value = "''"; 584 break; 585 default: 696 } 697 698 // add any new dependencies to the working set 699 List<Unit> newDependencies = ins.stream() 700 .flatMap(u -> u.effectedDependents()) 701 .collect(toList()); 702 state.debug(DBG_GEN, "compileAndLoad %s -- deps: %s success: %s\n", 703 ins, newDependencies, success); 704 if (!ins.addAll(newDependencies) && success) { 705 // all classes that could not be directly loaded (because they 706 // are new) have been redefined, and no new dependnencies were 707 // identified 708 ins.stream().forEach(u -> u.finish()); 709 return ins; 710 } 711 } 712 } 713 714 /** 715 * If there are classes to load, loads by calling the execution engine. 716 * @param classbytecoes names of the classes to load. 717 */ 718 private void load(Collection<ClassBytecodes> classbytecoes) { 719 if (!classbytecoes.isEmpty()) { 720 ClassBytecodes[] cbcs = classbytecoes.toArray(new ClassBytecodes[classbytecoes.size()]); 721 try { 722 state.executionControl().load(cbcs); 723 state.classTracker.markLoaded(cbcs); 724 } catch (ClassInstallException ex) { 725 state.classTracker.markLoaded(cbcs, ex.installed()); 726 } catch (EngineTerminationException ex) { 727 state.closeDown(); 728 } 729 } 730 } 731 732 private EvalException translateExecutionException(UserException ex) { 733 StackTraceElement[] raw = ex.getStackTrace(); 734 int last = raw.length; 735 do { 736 if (last == 0) { 737 last = raw.length - 1; 738 break; 739 } 740 } while (!isWrap(raw[--last])); 741 StackTraceElement[] elems = new StackTraceElement[last + 1]; 742 for (int i = 0; i <= last; ++i) { 743 StackTraceElement r = raw[i]; 744 OuterSnippetsClassWrap outer = state.outerMap.getOuter(r.getClassName()); 745 if (outer != null) { 746 String klass = expunge(r.getClassName()); 747 String method = r.getMethodName().equals(DOIT_METHOD_NAME) ? "" : r.getMethodName(); 748 int wln = r.getLineNumber() - 1; 749 int line = outer.wrapLineToSnippetLine(wln) + 1; 750 Snippet sn = outer.wrapLineToSnippet(wln); 751 String file = "#" + sn.id(); 752 elems[i] = new StackTraceElement(klass, method, file, line); 753 } else if (r.getFileName().equals("<none>")) { 754 elems[i] = new StackTraceElement(r.getClassName(), r.getMethodName(), null, r.getLineNumber()); 755 } else { 756 elems[i] = r; 757 } 758 } 759 String msg = ex.getMessage(); 760 if (msg.equals("<none>")) { 761 msg = null; 762 } 763 return new EvalException(msg, ex.causeExceptionClass(), elems); 764 } 765 766 private boolean isWrap(StackTraceElement ste) { 767 return PREFIX_PATTERN.matcher(ste.getClassName()).find(); 768 } 769 770 private DiagList modifierDiagnostics(ModifiersTree modtree, 771 final TreeDissector dis, boolean isAbstractProhibited) { 772 773 class ModifierDiagnostic extends Diag { 774 775 final boolean fatal; 776 final String message; 777 778 ModifierDiagnostic(List<Modifier> list, boolean fatal) { 779 this.fatal = fatal; 780 StringBuilder sb = new StringBuilder(); 781 for (Modifier mod : list) { 782 sb.append("'"); 783 sb.append(mod.toString()); |